add .Vx so tmac.andoc will call tmac.mdoc-old
[unix-history] / usr / src / usr.bin / ex / ex_re.c
CommitLineData
19d73a0e
DF
1/*
2 * Copyright (c) 1980 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
7#ifndef lint
5a6c967e 8static char *sccsid = "@(#)ex_re.c 7.6 (Berkeley) %G%";
19d73a0e
DF
9#endif not lint
10
22316d4f
MH
11#include "ex.h"
12#include "ex_re.h"
13
14/*
15 * Global, substitute and regular expressions.
16 * Very similar to ed, with some re extensions and
17 * confirmed substitute.
18 */
19global(k)
20 bool k;
21{
22 register char *gp;
23 register int c;
24 register line *a1;
25 char globuf[GBSIZE], *Cwas;
26 int lines = lineDOL();
27 int oinglobal = inglobal;
28 char *oglobp = globp;
29
30 Cwas = Command;
31 /*
32 * States of inglobal:
33 * 0: ordinary - not in a global command.
34 * 1: text coming from some buffer, not tty.
35 * 2: like 1, but the source of the buffer is a global command.
36 * Hence you're only in a global command if inglobal==2. This
37 * strange sounding convention is historically derived from
38 * everybody simulating a global command.
39 */
40 if (inglobal==2)
41 error("Global within global@not allowed");
42 markDOT();
43 setall();
44 nonzero();
45 if (skipend())
46 error("Global needs re|Missing regular expression for global");
5a6c967e 47 c = ex_getchar();
22316d4f
MH
48 ignore(compile(c, 1));
49 savere(scanre);
50 gp = globuf;
5a6c967e 51 while ((c = ex_getchar()) != '\n') {
22316d4f
MH
52 switch (c) {
53
54 case EOF:
55 c = '\n';
56 goto brkwh;
57
58 case '\\':
5a6c967e 59 c = ex_getchar();
22316d4f
MH
60 switch (c) {
61
62 case '\\':
63 ungetchar(c);
64 break;
65
66 case '\n':
67 break;
68
69 default:
70 *gp++ = '\\';
71 break;
72 }
73 break;
74 }
75 *gp++ = c;
76 if (gp >= &globuf[GBSIZE - 2])
77 error("Global command too long");
78 }
79brkwh:
80 ungetchar(c);
22316d4f
MH
81 newline();
82 *gp++ = c;
83 *gp++ = 0;
887e3e0d 84 saveall();
22316d4f
MH
85 inglobal = 2;
86 for (a1 = one; a1 <= dol; a1++) {
87 *a1 &= ~01;
88 if (a1 >= addr1 && a1 <= addr2 && execute(0, a1) == k)
89 *a1 |= 01;
90 }
f0f2d980
MH
91#ifdef notdef
92/*
93 * This code is commented out for now. The problem is that we don't
94 * fix up the undo area the way we should. Basically, I think what has
95 * to be done is to copy the undo area down (since we shrunk everything)
96 * and move the various pointers into it down too. I will do this later
97 * when I have time. (Mark, 10-20-80)
98 */
04379bab
MH
99 /*
100 * Special case: g/.../d (avoid n^2 algorithm)
101 */
102 if (globuf[0]=='d' && globuf[1]=='\n' && globuf[2]=='\0') {
103 gdelete();
104 return;
105 }
f0f2d980 106#endif
22316d4f
MH
107 if (inopen)
108 inopen = -1;
04379bab
MH
109 /*
110 * Now for each marked line, set dot there and do the commands.
111 * Note the n^2 behavior here for lots of lines matching.
112 * This is really needed: in some cases you could delete lines,
113 * causing a marked line to be moved before a1 and missed if
114 * we didn't restart at zero each time.
115 */
22316d4f
MH
116 for (a1 = one; a1 <= dol; a1++) {
117 if (*a1 & 01) {
118 *a1 &= ~01;
119 dot = a1;
120 globp = globuf;
121 commands(1, 1);
122 a1 = zero;
123 }
124 }
125 globp = oglobp;
126 inglobal = oinglobal;
127 endline = 1;
128 Command = Cwas;
129 netchHAD(lines);
130 setlastchar(EOF);
131 if (inopen) {
132 ungetchar(EOF);
133 inopen = 1;
134 }
135}
136
04379bab
MH
137/*
138 * gdelete: delete inside a global command. Handles the
139 * special case g/r.e./d. All lines to be deleted have
140 * already been marked. Squeeze the remaining lines together.
141 * Note that other cases such as g/r.e./p, g/r.e./s/r.e.2/rhs/,
142 * and g/r.e./.,/r.e.2/d are not treated specially. There is no
143 * good reason for this except the question: where to you draw the line?
144 */
145gdelete()
146{
147 register line *a1, *a2, *a3;
148
149 a3 = dol;
150 /* find first marked line. can skip all before it */
151 for (a1=zero; (*a1&01)==0; a1++)
152 if (a1>=a3)
153 return;
154 /* copy down unmarked lines, compacting as we go. */
155 for (a2=a1+1; a2<=a3;) {
156 if (*a2&01) {
157 a2++; /* line is marked, skip it */
158 dot = a1; /* dot left after line deletion */
159 } else
160 *a1++ = *a2++; /* unmarked, copy it */
161 }
162 dol = a1-1;
163 if (dot>dol)
164 dot = dol;
165 change();
166}
167
d266c416 168bool cflag;
22316d4f
MH
169int scount, slines, stotal;
170
171substitute(c)
172 int c;
173{
174 register line *addr;
175 register int n;
427286eb 176 int gsubf, hopcount;
22316d4f
MH
177
178 gsubf = compsub(c);
887e3e0d 179 if(FIXUNDO)
22316d4f
MH
180 save12(), undkind = UNDCHANGE;
181 stotal = 0;
182 slines = 0;
183 for (addr = addr1; addr <= addr2; addr++) {
427286eb 184 scount = hopcount = 0;
22316d4f
MH
185 if (dosubcon(0, addr) == 0)
186 continue;
187 if (gsubf) {
22316d4f 188 /*
04379bab
MH
189 * The loop can happen from s/\</&/g
190 * but we don't want to break other, reasonable cases.
22316d4f 191 */
04379bab
MH
192 while (*loc2) {
193 if (++hopcount > sizeof linebuf)
194 error("substitution loop");
22316d4f
MH
195 if (dosubcon(1, addr) == 0)
196 break;
04379bab 197 }
22316d4f
MH
198 }
199 if (scount) {
200 stotal += scount;
201 slines++;
202 putmark(addr);
203 n = append(getsub, addr);
204 addr += n;
205 addr2 += n;
206 }
207 }
d266c416 208 if (stotal == 0 && !inglobal && !cflag)
22316d4f
MH
209 error("Fail|Substitute pattern match failed");
210 snote(stotal, slines);
211 return (stotal);
212}
213
214compsub(ch)
215{
216 register int seof, c, uselastre;
217 static int gsubf;
218
219 if (!value(EDCOMPATIBLE))
d266c416 220 gsubf = cflag = 0;
22316d4f
MH
221 uselastre = 0;
222 switch (ch) {
223
224 case 's':
225 ignore(skipwh());
5a6c967e 226 seof = ex_getchar();
22316d4f
MH
227 if (endcmd(seof) || any(seof, "gcr")) {
228 ungetchar(seof);
229 goto redo;
230 }
231 if (isalpha(seof) || isdigit(seof))
232 error("Substitute needs re|Missing regular expression for substitute");
233 seof = compile(seof, 1);
234 uselastre = 1;
235 comprhs(seof);
236 gsubf = 0;
d266c416 237 cflag = 0;
22316d4f
MH
238 break;
239
240 case '~':
241 uselastre = 1;
242 /* fall into ... */
243 case '&':
244 redo:
245 if (re.Expbuf[0] == 0)
246 error("No previous re|No previous regular expression");
d266c416
MH
247 if (subre.Expbuf[0] == 0)
248 error("No previous substitute re|No previous substitute to repeat");
22316d4f
MH
249 break;
250 }
251 for (;;) {
5a6c967e 252 c = ex_getchar();
22316d4f
MH
253 switch (c) {
254
255 case 'g':
256 gsubf = !gsubf;
257 continue;
258
259 case 'c':
d266c416 260 cflag = !cflag;
22316d4f
MH
261 continue;
262
263 case 'r':
264 uselastre = 1;
265 continue;
266
267 default:
268 ungetchar(c);
269 setcount();
270 newline();
271 if (uselastre)
272 savere(subre);
273 else
274 resre(subre);
275 return (gsubf);
276 }
277 }
278}
279
280comprhs(seof)
281 int seof;
282{
283 register char *rp, *orp;
284 register int c;
04379bab 285 char orhsbuf[RHSSIZE];
22316d4f
MH
286
287 rp = rhsbuf;
288 CP(orhsbuf, rp);
289 for (;;) {
5a6c967e 290 c = ex_getchar();
22316d4f
MH
291 if (c == seof)
292 break;
293 switch (c) {
294
295 case '\\':
5a6c967e 296 c = ex_getchar();
22316d4f
MH
297 if (c == EOF) {
298 ungetchar(c);
299 break;
300 }
301 if (value(MAGIC)) {
302 /*
303 * When "magic", \& turns into a plain &,
304 * and all other chars work fine quoted.
305 */
306 if (c != '&')
307 c |= QUOTE;
308 break;
309 }
310magic:
311 if (c == '~') {
312 for (orp = orhsbuf; *orp; *rp++ = *orp++)
04379bab 313 if (rp >= &rhsbuf[RHSSIZE - 1])
22316d4f
MH
314 goto toobig;
315 continue;
316 }
317 c |= QUOTE;
318 break;
319
320 case '\n':
321 case EOF:
887e3e0d
MH
322 if (!(globp && globp[0])) {
323 ungetchar(c);
324 goto endrhs;
325 }
22316d4f
MH
326
327 case '~':
328 case '&':
329 if (value(MAGIC))
330 goto magic;
331 break;
332 }
04379bab 333 if (rp >= &rhsbuf[RHSSIZE - 1]) {
22316d4f 334toobig:
04379bab 335 *rp = 0;
22316d4f 336 error("Replacement pattern too long@- limit 256 characters");
04379bab 337 }
22316d4f
MH
338 *rp++ = c;
339 }
340endrhs:
341 *rp++ = 0;
342}
343
344getsub()
345{
346 register char *p;
347
348 if ((p = linebp) == 0)
349 return (EOF);
350 strcLIN(p);
351 linebp = 0;
352 return (0);
353}
354
355dosubcon(f, a)
356 bool f;
357 line *a;
358{
359
360 if (execute(f, a) == 0)
361 return (0);
362 if (confirmed(a)) {
363 dosub();
364 scount++;
365 }
366 return (1);
367}
368
369confirmed(a)
370 line *a;
371{
372 register int c, ch;
373
d266c416 374 if (cflag == 0)
22316d4f
MH
375 return (1);
376 pofix();
377 pline(lineno(a));
378 if (inopen)
5a6c967e 379 ex_putchar('\n' | QUOTE);
22316d4f
MH
380 c = column(loc1 - 1);
381 ugo(c - 1 + (inopen ? 1 : 0), ' ');
382 ugo(column(loc2 - 1) - c, '^');
383 flush();
384 ch = c = getkey();
385again:
386 if (c == '\r')
387 c = '\n';
388 if (inopen)
5a6c967e 389 ex_putchar(c), flush();
22316d4f
MH
390 if (c != '\n' && c != EOF) {
391 c = getkey();
392 goto again;
393 }
394 noteinp();
395 return (ch == 'y');
396}
397
398getch()
399{
400 char c;
401
402 if (read(2, &c, 1) != 1)
403 return (EOF);
404 return (c & TRIM);
405}
406
407ugo(cnt, with)
408 int with;
409 int cnt;
410{
411
412 if (cnt > 0)
413 do
5a6c967e 414 ex_putchar(with);
22316d4f
MH
415 while (--cnt > 0);
416}
417
418int casecnt;
419bool destuc;
420
421dosub()
422{
423 register char *lp, *sp, *rp;
424 int c;
425
426 lp = linebuf;
427 sp = genbuf;
428 rp = rhsbuf;
429 while (lp < loc1)
430 *sp++ = *lp++;
431 casecnt = 0;
432 while (c = *rp++) {
299f2784
MH
433 /* ^V <return> from vi to split lines */
434 if (c == '\r')
435 c = '\n';
436
22316d4f
MH
437 if (c & QUOTE)
438 switch (c & TRIM) {
439
440 case '&':
441 sp = place(sp, loc1, loc2);
442 if (sp == 0)
443 goto ovflo;
444 continue;
445
446 case 'l':
447 casecnt = 1;
448 destuc = 0;
449 continue;
450
451 case 'L':
452 casecnt = LBSIZE;
453 destuc = 0;
454 continue;
455
456 case 'u':
457 casecnt = 1;
458 destuc = 1;
459 continue;
460
461 case 'U':
462 casecnt = LBSIZE;
463 destuc = 1;
464 continue;
465
466 case 'E':
467 case 'e':
468 casecnt = 0;
469 continue;
470 }
471 if (c < 0 && (c &= TRIM) >= '1' && c < nbra + '1') {
472 sp = place(sp, braslist[c - '1'], braelist[c - '1']);
473 if (sp == 0)
474 goto ovflo;
475 continue;
476 }
477 if (casecnt)
478 *sp++ = fixcase(c & TRIM);
479 else
480 *sp++ = c & TRIM;
481 if (sp >= &genbuf[LBSIZE])
482ovflo:
44232d5b 483 error("Line overflow@in substitute");
22316d4f
MH
484 }
485 lp = loc2;
486 loc2 = sp + (linebuf - genbuf);
487 while (*sp++ = *lp++)
488 if (sp >= &genbuf[LBSIZE])
489 goto ovflo;
490 strcLIN(genbuf);
491}
492
493fixcase(c)
494 register int c;
495{
496
497 if (casecnt == 0)
498 return (c);
499 casecnt--;
500 if (destuc) {
501 if (islower(c))
502 c = toupper(c);
503 } else
504 if (isupper(c))
505 c = tolower(c);
506 return (c);
507}
508
509char *
510place(sp, l1, l2)
511 register char *sp, *l1, *l2;
512{
513
514 while (l1 < l2) {
515 *sp++ = fixcase(*l1++);
516 if (sp >= &genbuf[LBSIZE])
517 return (0);
518 }
519 return (sp);
520}
521
522snote(total, lines)
523 register int total, lines;
524{
525
526 if (!notable(total))
527 return;
5a6c967e 528 ex_printf(mesg("%d subs|%d substitutions"), total);
22316d4f 529 if (lines != 1 && lines != total)
5a6c967e 530 ex_printf(" on %d lines", lines);
22316d4f
MH
531 noonl();
532 flush();
533}
534
535compile(eof, oknl)
536 int eof;
537 int oknl;
538{
539 register int c;
540 register char *ep;
541 char *lastep;
542 char bracket[NBRA], *bracketp, *rhsp;
543 int cclcnt;
544
545 if (isalpha(eof) || isdigit(eof))
546 error("Regular expressions cannot be delimited by letters or digits");
547 ep = expbuf;
5a6c967e 548 c = ex_getchar();
22316d4f
MH
549 if (eof == '\\')
550 switch (c) {
551
552 case '/':
553 case '?':
554 if (scanre.Expbuf[0] == 0)
555error("No previous scan re|No previous scanning regular expression");
556 resre(scanre);
557 return (c);
558
559 case '&':
560 if (subre.Expbuf[0] == 0)
561error("No previous substitute re|No previous substitute regular expression");
562 resre(subre);
563 return (c);
564
565 default:
566 error("Badly formed re|Regular expression \\ must be followed by / or ?");
567 }
568 if (c == eof || c == '\n' || c == EOF) {
569 if (*ep == 0)
570 error("No previous re|No previous regular expression");
571 if (c == '\n' && oknl == 0)
572 error("Missing closing delimiter@for regular expression");
573 if (c != eof)
574 ungetchar(c);
575 return (eof);
576 }
577 bracketp = bracket;
578 nbra = 0;
579 circfl = 0;
580 if (c == '^') {
5a6c967e 581 c = ex_getchar();
22316d4f
MH
582 circfl++;
583 }
584 ungetchar(c);
585 for (;;) {
586 if (ep >= &expbuf[ESIZE - 2])
587complex:
588 cerror("Re too complex|Regular expression too complicated");
5a6c967e 589 c = ex_getchar();
22316d4f
MH
590 if (c == eof || c == EOF) {
591 if (bracketp != bracket)
592cerror("Unmatched \\(|More \\('s than \\)'s in regular expression");
d266c416 593 *ep++ = CEOFC;
22316d4f
MH
594 if (c == EOF)
595 ungetchar(c);
596 return (eof);
597 }
598 if (value(MAGIC)) {
599 if (c != '*' || ep == expbuf)
600 lastep = ep;
601 } else
602 if (c != '\\' || peekchar() != '*' || ep == expbuf)
603 lastep = ep;
604 switch (c) {
605
606 case '\\':
5a6c967e 607 c = ex_getchar();
22316d4f
MH
608 switch (c) {
609
610 case '(':
611 if (nbra >= NBRA)
612cerror("Awash in \\('s!|Too many \\('d subexressions in a regular expression");
613 *bracketp++ = nbra;
614 *ep++ = CBRA;
615 *ep++ = nbra++;
616 continue;
617
618 case ')':
619 if (bracketp <= bracket)
620cerror("Extra \\)|More \\)'s than \\('s in regular expression");
621 *ep++ = CKET;
622 *ep++ = *--bracketp;
623 continue;
624
625 case '<':
626 *ep++ = CBRC;
627 continue;
628
629 case '>':
630 *ep++ = CLET;
631 continue;
632 }
633 if (value(MAGIC) == 0)
634magic:
635 switch (c) {
636
637 case '.':
638 *ep++ = CDOT;
639 continue;
640
641 case '~':
642 rhsp = rhsbuf;
643 while (*rhsp) {
644 if (*rhsp & QUOTE) {
645 c = *rhsp & TRIM;
646 if (c == '&')
647error("Replacement pattern contains &@- cannot use in re");
648 if (c >= '1' && c <= '9')
649error("Replacement pattern contains \\d@- cannot use in re");
650 }
651 if (ep >= &expbuf[ESIZE-2])
652 goto complex;
653 *ep++ = CCHR;
654 *ep++ = *rhsp++ & TRIM;
655 }
656 continue;
657
658 case '*':
659 if (ep == expbuf)
660 break;
661 if (*lastep == CBRA || *lastep == CKET)
662cerror("Illegal *|Can't * a \\( ... \\) in regular expression");
663 if (*lastep == CCHR && (lastep[1] & QUOTE))
664cerror("Illegal *|Can't * a \\n in regular expression");
665 *lastep |= STAR;
666 continue;
667
668 case '[':
669 *ep++ = CCL;
670 *ep++ = 0;
671 cclcnt = 1;
5a6c967e 672 c = ex_getchar();
22316d4f 673 if (c == '^') {
5a6c967e 674 c = ex_getchar();
22316d4f
MH
675 ep[-2] = NCCL;
676 }
677 if (c == ']')
678cerror("Bad character class|Empty character class '[]' or '[^]' cannot match");
679 while (c != ']') {
680 if (c == '\\' && any(peekchar(), "]-^\\"))
5a6c967e 681 c = ex_getchar() | QUOTE;
22316d4f
MH
682 if (c == '\n' || c == EOF)
683 cerror("Missing ]");
684 *ep++ = c;
685 cclcnt++;
686 if (ep >= &expbuf[ESIZE])
687 goto complex;
5a6c967e 688 c = ex_getchar();
22316d4f
MH
689 }
690 lastep[1] = cclcnt;
691 continue;
692 }
693 if (c == EOF) {
694 ungetchar(EOF);
695 c = '\\';
696 goto defchar;
697 }
698 *ep++ = CCHR;
699 if (c == '\n')
700cerror("No newlines in re's|Can't escape newlines into regular expressions");
701/*
702 if (c < '1' || c > NBRA + '1') {
703*/
704 *ep++ = c;
705 continue;
706/*
707 }
708 c -= '1';
709 if (c >= nbra)
710cerror("Bad \\n|\\n in regular expression with n greater than the number of \\('s");
711 *ep++ = c | QUOTE;
712 continue;
713*/
714
715 case '\n':
716 if (oknl) {
717 ungetchar(c);
d266c416 718 *ep++ = CEOFC;
22316d4f
MH
719 return (eof);
720 }
721cerror("Badly formed re|Missing closing delimiter for regular expression");
722
723 case '$':
724 if (peekchar() == eof || peekchar() == EOF || oknl && peekchar() == '\n') {
725 *ep++ = CDOL;
726 continue;
727 }
728 goto defchar;
729
730 case '.':
731 case '~':
732 case '*':
733 case '[':
734 if (value(MAGIC))
735 goto magic;
736defchar:
737 default:
738 *ep++ = CCHR;
739 *ep++ = c;
740 continue;
741 }
742 }
743}
744
745cerror(s)
746 char *s;
747{
748
749 expbuf[0] = 0;
750 error(s);
751}
752
753same(a, b)
754 register int a, b;
755{
756
757 return (a == b || value(IGNORECASE) &&
758 ((islower(a) && toupper(a) == b) || (islower(b) && toupper(b) == a)));
759}
760
761char *locs;
762
5a6c967e 763/* VARARGS1 */
22316d4f
MH
764execute(gf, addr)
765 line *addr;
766{
767 register char *p1, *p2;
768 register int c;
769
770 if (gf) {
771 if (circfl)
772 return (0);
22316d4f
MH
773 locs = p1 = loc2;
774 } else {
775 if (addr == zero)
776 return (0);
777 p1 = linebuf;
778 getline(*addr);
779 locs = 0;
780 }
781 p2 = expbuf;
782 if (circfl) {
783 loc1 = p1;
784 return (advance(p1, p2));
785 }
786 /* fast check for first character */
787 if (*p2 == CCHR) {
788 c = p2[1];
789 do {
790 if (c != *p1 && (!value(IGNORECASE) ||
791 !((islower(c) && toupper(c) == *p1) ||
792 (islower(*p1) && toupper(*p1) == c))))
793 continue;
794 if (advance(p1, p2)) {
795 loc1 = p1;
796 return (1);
797 }
798 } while (*p1++);
799 return (0);
800 }
801 /* regular algorithm */
802 do {
803 if (advance(p1, p2)) {
804 loc1 = p1;
805 return (1);
806 }
807 } while (*p1++);
808 return (0);
809}
810
811#define uletter(c) (isalpha(c) || c == '_')
812
813advance(lp, ep)
814 register char *lp, *ep;
815{
816 register char *curlp;
22316d4f
MH
817
818 for (;;) switch (*ep++) {
819
820 case CCHR:
821/* useless
822 if (*ep & QUOTE) {
823 c = *ep++ & TRIM;
824 sp = braslist[c];
825 sp1 = braelist[c];
826 while (sp < sp1) {
827 if (!same(*sp, *lp))
828 return (0);
829 sp++, lp++;
830 }
831 continue;
832 }
833*/
834 if (!same(*ep, *lp))
835 return (0);
836 ep++, lp++;
837 continue;
838
839 case CDOT:
840 if (*lp++)
841 continue;
842 return (0);
843
844 case CDOL:
845 if (*lp == 0)
846 continue;
847 return (0);
848
d266c416 849 case CEOFC:
22316d4f
MH
850 loc2 = lp;
851 return (1);
852
853 case CCL:
854 if (cclass(ep, *lp++, 1)) {
855 ep += *ep;
856 continue;
857 }
858 return (0);
859
860 case NCCL:
861 if (cclass(ep, *lp++, 0)) {
862 ep += *ep;
863 continue;
864 }
865 return (0);
866
867 case CBRA:
868 braslist[*ep++] = lp;
869 continue;
870
871 case CKET:
872 braelist[*ep++] = lp;
873 continue;
874
875 case CDOT|STAR:
876 curlp = lp;
877 while (*lp++)
878 continue;
879 goto star;
880
881 case CCHR|STAR:
882 curlp = lp;
883 while (same(*lp, *ep))
884 lp++;
885 lp++;
886 ep++;
887 goto star;
888
889 case CCL|STAR:
890 case NCCL|STAR:
891 curlp = lp;
892 while (cclass(ep, *lp++, ep[-1] == (CCL|STAR)))
893 continue;
894 ep += *ep;
895 goto star;
896star:
897 do {
898 lp--;
899 if (lp == locs)
900 break;
901 if (advance(lp, ep))
902 return (1);
903 } while (lp > curlp);
904 return (0);
905
906 case CBRC:
81a53a4e 907 if (lp == linebuf)
22316d4f
MH
908 continue;
909 if ((isdigit(*lp) || uletter(*lp)) && !uletter(lp[-1]) && !isdigit(lp[-1]))
910 continue;
911 return (0);
912
913 case CLET:
914 if (!uletter(*lp) && !isdigit(*lp))
915 continue;
916 return (0);
917
918 default:
919 error("Re internal error");
920 }
921}
922
923cclass(set, c, af)
924 register char *set;
925 register int c;
926 int af;
927{
928 register int n;
929
930 if (c == 0)
931 return (0);
932 if (value(IGNORECASE) && isupper(c))
933 c = tolower(c);
934 n = *set++;
935 while (--n)
936 if (n > 2 && set[1] == '-') {
937 if (c >= (set[0] & TRIM) && c <= (set[2] & TRIM))
938 return (af);
939 set += 3;
940 n -= 2;
941 } else
942 if ((*set++ & TRIM) == c)
943 return (af);
944 return (!af);
945}