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