xref: /titanic_52/usr/src/cmd/egrep/egrep.y (revision 1f0c339e39c0c782f9d4c4f3f11d373e24e1d76f)
1 %{
2 /*
3  * CDDL HEADER START
4  *
5  * The contents of this file are subject to the terms of the
6  * Common Development and Distribution License, Version 1.0 only
7  * (the "License").  You may not use this file except in compliance
8  * with the License.
9  *
10  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11  * or http://www.opensolaris.org/os/licensing.
12  * See the License for the specific language governing permissions
13  * and limitations under the License.
14  *
15  * When distributing Covered Code, include this CDDL HEADER in each
16  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17  * If applicable, add the following below this CDDL HEADER, with the
18  * fields enclosed by brackets "[]" replaced with your own identifying
19  * information: Portions Copyright [yyyy] [name of copyright owner]
20  *
21  * CDDL HEADER END
22  */
23 %}
24 /*
25  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
26  * Use is subject to license terms.
27  */
28 
29 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
30 /*	  All Rights Reserved  	*/
31 
32 /*	Copyright (c) 1987, 1988 Microsoft Corporation	*/
33 /*	  All Rights Reserved	*/
34 
35 /*
36  * Copyright 2013 Damian Bogel. All rights reserved.
37  */
38 
39 /*
40  * egrep -- print lines containing (or not containing) a regular expression
41  *
42  *	status returns:
43  *		0 - ok, and some matches
44  *		1 - ok, but no matches
45  *		2 - some error; matches irrelevant
46  */
47 %token CHAR MCHAR DOT MDOT CCL NCCL MCCL NMCCL OR CAT STAR PLUS QUEST
48 %left OR
49 %left CHAR MCHAR DOT CCL NCCL MCCL NMCCL '('
50 %left CAT
51 %left STAR PLUS QUEST
52 
53 %{
54 #include <stdio.h>
55 #include <ctype.h>
56 #include <memory.h>
57 #include <wchar.h>
58 #include <wctype.h>
59 #include <widec.h>
60 #include <stdlib.h>
61 #include <limits.h>
62 #include <locale.h>
63 
64 #define STDIN_FILENAME gettext("(standard input)")
65 
66 #define BLKSIZE 512	/* size of reported disk blocks */
67 #define EBUFSIZ 8192
68 #define MAXLIN 350
69 #define NCHARS 256
70 #define MAXPOS 4000
71 #define NSTATES 64
72 #define FINAL -1
73 #define RIGHT '\n'	/* serves as record separator and as $ */
74 #define LEFT '\n'	/* beginning of line */
75 int gotofn[NSTATES][NCHARS];
76 int state[NSTATES];
77 int out[NSTATES];
78 int line  = 1;
79 int *name;
80 int *left;
81 int *right;
82 int *parent;
83 int *foll;
84 int *positions;
85 char *chars;
86 wchar_t *lower;
87 wchar_t *upper;
88 int maxlin, maxclin, maxwclin, maxpos;
89 int nxtpos = 0;
90 int inxtpos;
91 int nxtchar = 0;
92 int *tmpstat;
93 int *initstat;
94 int istat;
95 int nstate = 1;
96 int xstate;
97 int count;
98 int icount;
99 char *input;
100 
101 
102 wchar_t lyylval;
103 wchar_t nextch();
104 wchar_t maxmin();
105 int compare();
106 void overflo();
107 
108 char reinit = 0;
109 
110 long long lnum;
111 int	bflag;
112 int	cflag;
113 int	eflag;
114 int	fflag;
115 int	Hflag;
116 int	hflag;
117 int	iflag;
118 int	lflag;
119 int	nflag;
120 int	qflag;
121 int	vflag;
122 int	nfile;
123 long long blkno;
124 long long tln;
125 int	nsucc;
126 int	badbotch;
127 extern 	char *optarg;
128 extern 	int optind;
129 
130 int	f;
131 FILE	*expfile;
132 %}
133 
134 %%
135 s:	t
136 		{
137 		  unary(FINAL, $1);
138 		  line--;
139 		}
140 	;
141 t:	b r
142 		{ $$ = node(CAT, $1, $2); }
143 	| OR b r OR
144 		{ $$ = node(CAT, $2, $3); }
145 	| OR b r
146 		{ $$ = node(CAT, $2, $3); }
147 	| b r OR
148 		{ $$ = node(CAT, $1, $2); }
149 	;
150 b:
151 		{ /* if(multibyte)
152 			$$ = mdotenter();
153 		  else */
154 			$$ = enter(DOT);
155 		  $$ = unary(STAR, $$);
156 		}
157 	;
158 r:	CHAR
159 		{ $$ = iflag && isalpha($1) ?
160 		node(OR, enter(tolower($1)), enter(toupper($1))) : enter($1); }
161 	| MCHAR
162 		{ $$ = (iflag && iswalpha(lyylval)) ?
163 		node(OR, mchar(towlower(lyylval)), mchar(towupper(lyylval))) :
164 		mchar(lyylval); }
165 	| DOT
166 		{ if(multibyte)
167 			$$ = mdotenter();
168 		  else
169 			$$ = enter(DOT);
170 		}
171 	| CCL
172 		{ $$ = cclenter(CCL); }
173 	| NCCL
174 		{ $$ = cclenter(NCCL); }
175 	| MCCL
176 		{ $$ = ccl(CCL); }
177 	| NMCCL
178 		{ $$ = ccl(NCCL); }
179 	;
180 
181 r:	r OR r
182 		{ $$ = node(OR, $1, $3); }
183 	| r r %prec CAT
184 		{ $$ = node(CAT, $1, $2); }
185 	| r STAR
186 		{ $$ = unary(STAR, $1); }
187 	| r PLUS
188 		{ $$ = unary(PLUS, $1); }
189 	| r QUEST
190 		{ $$ = unary(QUEST, $1); }
191 	| '(' r ')'
192 		{ $$ = $2; }
193 	| error
194 	;
195 
196 %%
197 void	add(int *, int);
198 void	clearg(void);
199 void	execute(char *);
200 void	follow(int);
201 int	mgetc(void);
202 void	synerror(void);
203 
204 
205 void
206 yyerror(char *s)
207 {
208 	fprintf(stderr, "egrep: %s\n", s);
209 	exit(2);
210 }
211 
212 int
213 yylex(void)
214 {
215 	extern int yylval;
216 	int cclcnt, x, ccount, oldccount;
217 	wchar_t c, lc;
218 
219 	c = nextch();
220 	switch(c) {
221 		case '^':
222 			yylval = LEFT;
223 			return(CHAR);
224 		case '$':
225 			c = RIGHT;
226 			goto defchar;
227 		case '|': return (OR);
228 		case '*': return (STAR);
229 		case '+': return (PLUS);
230 		case '?': return (QUEST);
231 		case '(': return (c);
232 		case ')': return (c);
233 		case '.': return(DOT);
234 		case '\0': return (0);
235 		case RIGHT: return (OR);
236 		case '[':
237 			x = (multibyte ? MCCL : CCL);
238 			cclcnt = 0;
239 			count = nxtchar++;
240 			if ((c = nextch()) == '^') {
241 				x = (multibyte ? NMCCL : NCCL);
242 				c = nextch();
243 			}
244 			lc = 0;
245 			do {
246 				if (iflag && iswalpha(c))
247 					c = towlower(c);
248 				if (c == '\0') synerror();
249 				if (c == '-' && cclcnt > 0 && lc != 0) {
250 					if ((c = nextch()) != 0) {
251 						if(c == ']') {
252 							chars[nxtchar++] = '-';
253 							cclcnt++;
254 							break;
255 						}
256 						if (iflag && iswalpha(c))
257 							c = towlower(c);
258 						if (!multibyte ||
259 						(c & WCHAR_CSMASK) == (lc & WCHAR_CSMASK) &&
260 						lc < c &&
261 						!iswcntrl(c) && !iswcntrl(lc)) {
262 							if (nxtchar >= maxclin)
263 								if (allocchars() == 0)
264 									overflo();
265 							chars[nxtchar++] = '-';
266 							cclcnt++;
267 						}
268 					}
269 				}
270 				ccount = oldccount = nxtchar;
271 				if(ccount + MB_LEN_MAX >= maxclin)
272 					if(allocchars() == 0)
273 						overflo();
274 				ccount += wctomb(&chars[ccount], c);
275 				cclcnt += ccount - oldccount;
276 				nxtchar += ccount - oldccount;
277 				lc = c;
278 			} while ((c = nextch()) != ']');
279 			chars[count] = cclcnt;
280 			return(x);
281 
282 		case '\\':
283 			if ((c = nextch()) == '\0') synerror();
284 		defchar:
285 		default:
286 			if (c <= 0177) {
287 				yylval = c;
288 				return (CHAR);
289 			} else {
290 				lyylval = c;
291 				return (MCHAR);
292 			}
293 	}
294 }
295 
296 wchar_t
297 nextch(void)
298 {
299 	wchar_t lc;
300 	char multic[MB_LEN_MAX];
301 	int length, d;
302 	if (fflag) {
303 		if ((length = _mbftowc(multic, &lc, mgetc, &d)) < 0)
304 			synerror();
305 		if(length == 0)
306 			lc = '\0';
307 	}
308 	else  {
309 		if((length = mbtowc(&lc, input, MB_LEN_MAX)) == -1)
310 			synerror();
311 		if(length == 0)
312 			return(0);
313 		input += length;
314 	}
315 	return(lc);
316 }
317 
318 int
319 mgetc(void)
320 {
321 	return(getc(expfile));
322 }
323 
324 void
325 synerror(void)
326 {
327 	fprintf(stderr, gettext("egrep: syntax error\n"));
328 	exit(2);
329 }
330 
331 int
332 enter(int x)
333 {
334 	if(line >= maxlin)
335 		if(alloctree() == 0)
336 			overflo();
337 	name[line] = x;
338 	left[line] = 0;
339 	right[line] = 0;
340 	return(line++);
341 }
342 
343 int
344 cclenter(int x)
345 {
346 	int linno;
347 	linno = enter(x);
348 	right[linno] = count;
349 	return (linno);
350 }
351 
352 int
353 node(int x, int l, int r)
354 {
355 	if(line >= maxlin)
356 		if(alloctree() == 0)
357 			overflo();
358 	name[line] = x;
359 	left[line] = l;
360 	right[line] = r;
361 	parent[l] = line;
362 	parent[r] = line;
363 	return(line++);
364 }
365 
366 int
367 unary(int x, int d)
368 {
369 	if(line >= maxlin)
370 		if(alloctree() == 0)
371 			overflo();
372 	name[line] = x;
373 	left[line] = d;
374 	right[line] = 0;
375 	parent[d] = line;
376 	return(line++);
377 }
378 
379 int
380 allocchars(void)
381 {
382 	maxclin += MAXLIN;
383 	if((chars = realloc(chars, maxclin)) == (char *)0)
384 		return 0;
385 	return 1;
386 }
387 
388 int
389 alloctree(void)
390 {
391 	maxlin += MAXLIN;
392 	if((name = (int *)realloc(name, maxlin*sizeof(int))) == (int *)0)
393 		return 0;
394 	if((left = (int *)realloc(left, maxlin*sizeof(int))) == (int *)0)
395 		return 0;
396 	if((right = (int *)realloc(right, maxlin*sizeof(int))) == (int *)0)
397 		return 0;
398 	if((parent = (int *)realloc(parent, maxlin*sizeof(int))) == (int *)0)
399 		return 0;
400 	if((foll = (int *)realloc(foll, maxlin*sizeof(int))) == (int *)0)
401 		return 0;
402 	if((tmpstat = (int *)realloc(tmpstat, maxlin*sizeof(int))) == (int *)0)
403 		return 0;
404 	if((initstat = (int *)realloc(initstat, maxlin*sizeof(int))) == (int *)0)
405 		return 0;
406 	return 1;
407 }
408 
409 void
410 overflo(void)
411 {
412 	fprintf(stderr, gettext("egrep: regular expression too long\n"));
413 	exit(2);
414 }
415 
416 void
417 cfoll(int v)
418 {
419 	int i;
420 	if (left[v] == 0) {
421 		count = 0;
422 		for (i=1; i<=line; i++) tmpstat[i] = 0;
423 		follow(v);
424 		add(foll, v);
425 	}
426 	else if (right[v] == 0) cfoll(left[v]);
427 	else {
428 		cfoll(left[v]);
429 		cfoll(right[v]);
430 	}
431 }
432 
433 void
434 cgotofn(void)
435 {
436 	int i;
437 	count = 0;
438 	inxtpos = nxtpos;
439 	for (i=3; i<=line; i++) tmpstat[i] = 0;
440 	if (cstate(line-1)==0) {
441 		tmpstat[line] = 1;
442 		count++;
443 		out[1] = 1;
444 	}
445 	for (i=3; i<=line; i++) initstat[i] = tmpstat[i];
446 	count--;		/*leave out position 1 */
447 	icount = count;
448 	tmpstat[1] = 0;
449 	add(state, 1);
450 	istat = nxtst(1, LEFT);
451 }
452 
453 int
454 nxtst(int s, int c)
455 {
456 	int i, num, k;
457 	int pos, curpos, number, newpos;
458 	num = positions[state[s]];
459 	count = icount;
460 	for (i=3; i<=line; i++) tmpstat[i] = initstat[i];
461 	pos = state[s] + 1;
462 	for (i=0; i<num; i++) {
463 		curpos = positions[pos];
464 		k = name[curpos];
465 		if (k >= 0)
466 			if (
467 				(k == c)
468 				|| (k == DOT && dot(c))
469 				|| (k == MDOT && mdot(c))
470 				|| (k == CCL && dot(c) && member(c, right[curpos], 1))
471 				|| (k == NCCL && dot(c) && member(c, right[curpos], 0))
472 				|| (k == MCCL && mdot(c) && member(c, right[curpos], 1))
473 			) {
474 				number = positions[foll[curpos]];
475 				newpos = foll[curpos] + 1;
476 				for (k=0; k<number; k++) {
477 					if (tmpstat[positions[newpos]] != 1) {
478 						tmpstat[positions[newpos]] = 1;
479 						count++;
480 					}
481 					newpos++;
482 				}
483 			}
484 		pos++;
485 	}
486 	if (notin(nstate)) {
487 		if (++nstate >= NSTATES) {
488 			for (i=1; i<NSTATES; i++)
489 				out[i] = 0;
490 			for (i=1; i<NSTATES; i++)
491 				for (k=0; k<NCHARS; k++)
492 					gotofn[i][k] = 0;
493 			nstate = 1;
494 			nxtpos = inxtpos;
495 			reinit = 1;
496 			add(state, nstate);
497 			if (tmpstat[line] == 1) out[nstate] = 1;
498 			return nstate;
499 		}
500 		add(state, nstate);
501 		if (tmpstat[line] == 1) out[nstate] = 1;
502 		gotofn[s][c] = nstate;
503 		return nstate;
504 	}
505 	else {
506 		gotofn[s][c] = xstate;
507 		return xstate;
508 	}
509 }
510 
511 
512 int
513 cstate(int v)
514 {
515 	int b;
516 	if (left[v] == 0) {
517 		if (tmpstat[v] != 1) {
518 			tmpstat[v] = 1;
519 			count++;
520 		}
521 		return(1);
522 	}
523 	else if (right[v] == 0) {
524 		if (cstate(left[v]) == 0) return (0);
525 		else if (name[v] == PLUS) return (1);
526 		else return (0);
527 	}
528 	else if (name[v] == CAT) {
529 		if (cstate(left[v]) == 0 && cstate(right[v]) == 0) return (0);
530 		else return (1);
531 	}
532 	else { /* name[v] == OR */
533 		b = cstate(right[v]);
534 		if (cstate(left[v]) == 0 || b == 0) return (0);
535 		else return (1);
536 	}
537 }
538 
539 
540 int
541 dot(int c)
542 {
543 	if(multibyte && c >= 0200 && (!iscntrl(c) || c == SS2 && eucw2 || c == SS3 && eucw3))
544 		return(0);
545 	if(c == RIGHT || c == LEFT)
546 		return(0);
547 	return(1);
548 }
549 
550 int
551 mdot(int c)
552 {
553 	if(c >= 0200 && !iscntrl(c))
554 		return(1);
555 	return(0);
556 }
557 
558 int
559 member(int symb, int set, int torf)
560 {
561 	int i, num, pos, c, lc;
562 	if(symb == RIGHT || symb == LEFT)
563 		return(0);
564 	num = chars[set];
565 	pos = set + 1;
566 	lc = 0;
567 	if(iflag)
568 		symb = tolower(symb);
569 	for (i=0; i<num; i++) {
570 		c = (unsigned char)chars[pos++];
571 		if(c == '-' && lc != 0 && ++i < num) {
572 			c = (unsigned char)chars[pos++];
573 			if(lc <= symb && symb <= c)
574 				return(torf);
575 		}
576 		if (symb == c)
577 			return (torf);
578 		lc = c;
579 	}
580 	return(!torf);
581 }
582 
583 int
584 notin(int n)
585 {
586 	int i, j, pos;
587 	for (i=1; i<=n; i++) {
588 		if (positions[state[i]] == count) {
589 			pos = state[i] + 1;
590 			for (j=0; j < count; j++)
591 				if (tmpstat[positions[pos++]] != 1) goto nxt;
592 			xstate = i;
593 			return (0);
594 		}
595 		nxt: ;
596 	}
597 	return (1);
598 }
599 
600 void
601 add(int *array, int n)
602 {
603 	int i;
604 	if (nxtpos + count >= maxpos) {
605 		maxpos += MAXPOS + count;
606 		if((positions = (int *)realloc(positions, maxpos *sizeof(int))) == (int *)0)
607 			overflo();
608 	}
609 	array[n] = nxtpos;
610 	positions[nxtpos++] = count;
611 	for (i=3; i <= line; i++) {
612 		if (tmpstat[i] == 1) {
613 			positions[nxtpos++] = i;
614 		}
615 	}
616 }
617 
618 void
619 follow(int v)
620 {
621 	int p;
622 	if (v == line) return;
623 	p = parent[v];
624 	switch(name[p]) {
625 		case STAR:
626 		case PLUS:	cstate(v);
627 				follow(p);
628 				return;
629 
630 		case OR:
631 		case QUEST:	follow(p);
632 				return;
633 
634 		case CAT:	if (v == left[p]) {
635 					if (cstate(right[p]) == 0) {
636 						follow(p);
637 						return;
638 					}
639 				}
640 				else follow(p);
641 				return;
642 		case FINAL:	if (tmpstat[line] != 1) {
643 					tmpstat[line] = 1;
644 					count++;
645 				}
646 				return;
647 	}
648 }
649 
650 #define USAGE "[ -bchHilnsqv ] [ -e exp ] [ -f file ] [ strings ] [ file ] ..."
651 
652 int
653 main(int argc, char **argv)
654 {
655 	char c;
656 	char nl = '\n';
657 	int errflag = 0;
658 
659 	(void)setlocale(LC_ALL, "");
660 
661 #if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D */
662 	#define TEXT_DOMAIN "SYS_TEST"  /* Use this only if it weren't. */
663 #endif
664 	(void) textdomain(TEXT_DOMAIN);
665 
666 	while((c = getopt(argc, argv, "ybcie:f:Hhlnvsq")) != -1)
667 		switch(c) {
668 
669 		case 'b':
670 			bflag++;
671 			continue;
672 
673 		case 'c':
674 			cflag++;
675 			continue;
676 
677 		case 'e':
678 			eflag++;
679 			input = optarg;
680 			continue;
681 
682 		case 'f':
683 			fflag++;
684 			expfile = fopen(optarg, "r");
685 			if(expfile == NULL) {
686 				fprintf(stderr,
687 				  gettext("egrep: can't open %s\n"), optarg);
688 				exit(2);
689 			}
690 			continue;
691 
692 		case 'H':
693 			if (!lflag) /* H is excluded by l as in GNU grep */
694 				Hflag++;
695 			hflag = 0; /* H excludes h */
696 			continue;
697 
698 		case 'h':
699 			hflag++;
700 			Hflag = 0; /* h excludes H */
701 			continue;
702 
703 		case 'y':
704 		case 'i':
705 			iflag++;
706 			continue;
707 
708 		case 'l':
709 			lflag++;
710 			Hflag = 0; /* l excludes H */
711 			continue;
712 
713 		case 'n':
714 			nflag++;
715 			continue;
716 
717 		case 'q':
718 		case 's': /* Solaris: legacy option */
719 			qflag++;
720 			continue;
721 
722 		case 'v':
723 			vflag++;
724 			continue;
725 
726 		case '?':
727 			errflag++;
728 		}
729 	if (errflag || ((argc <= 0) && !fflag && !eflag)) {
730 		fprintf(stderr, gettext("usage: egrep %s\n"), gettext(USAGE));
731 		exit(2);
732 	}
733 	if(!eflag && !fflag) {
734 		input = argv[optind];
735 		optind++;
736 	}
737 
738 	argc -= optind;
739 	argv = &argv[optind];
740 
741 	/* allocate initial space for arrays */
742 	if((name = (int *)malloc(MAXLIN*sizeof(int))) == (int *)0)
743 		overflo();
744 	if((left = (int *)malloc(MAXLIN*sizeof(int))) == (int *)0)
745 		overflo();
746 	if((right = (int *)malloc(MAXLIN*sizeof(int))) == (int *)0)
747 		overflo();
748 	if((parent = (int *)malloc(MAXLIN*sizeof(int))) == (int *)0)
749 		overflo();
750 	if((foll = (int *)malloc(MAXLIN*sizeof(int))) == (int *)0)
751 		overflo();
752 	if((tmpstat = (int *)malloc(MAXLIN*sizeof(int))) == (int *)0)
753 		overflo();
754 	if((initstat = (int *)malloc(MAXLIN*sizeof(int))) == (int *)0)
755 		overflo();
756 	if((chars = (char *)malloc(MAXLIN)) == (char *)0)
757 		overflo();
758 	if((lower = (wchar_t *)malloc(MAXLIN*sizeof(wchar_t))) == (wchar_t *)0)
759 		overflo();
760 	if((upper = (wchar_t *)malloc(MAXLIN*sizeof(wchar_t))) == (wchar_t *)0)
761 		overflo();
762 	if((positions = (int *)malloc(MAXPOS*sizeof(int))) == (int *)0)
763 		overflo();
764 	maxlin = MAXLIN;
765 	maxclin = MAXLIN;
766 	maxwclin = MAXLIN;
767 	maxpos = MAXPOS;
768 
769 	yyparse();
770 
771 	cfoll(line-1);
772 	cgotofn();
773 	nfile = argc;
774 	if (argc<=0) {
775 		execute(0);
776 	}
777 	else while (--argc >= 0) {
778 		if (reinit == 1) clearg();
779 		execute(*argv++);
780 	}
781 	return (badbotch ? 2 : nsucc==0);
782 }
783 
784 void
785 execute(char *file)
786 {
787 	char *p;
788 	int cstat;
789 	wchar_t c;
790 	int t;
791 	long count;
792 	long count1, count2;
793 	long nchars;
794 	int succ;
795 	char *ptr, *ptrend, *lastptr;
796 	char *buf;
797 	long lBufSiz;
798 	FILE *f;
799 	int nlflag;
800 
801 	lBufSiz = EBUFSIZ;
802 	if ((buf = malloc (lBufSiz + EBUFSIZ)) == NULL) {
803 		exit (2); /* out of memory - BAIL */
804 	}
805 
806 	if (file) {
807 		if ((f = fopen(file, "r")) == NULL) {
808 			fprintf(stderr,
809 				gettext("egrep: can't open %s\n"), file);
810 			badbotch=1;
811 			return;
812 		}
813 	} else {
814 		f = stdin;
815 		file = STDIN_FILENAME;
816 	}
817 	lnum = 1;
818 	tln = 0;
819 	if((count = read(fileno(f), buf, EBUFSIZ)) <= 0) {
820 		fclose(f);
821 
822 		if (cflag && !qflag) {
823 			if (Hflag || (nfile > 1 && !hflag))
824 				fprintf(stdout, "%s:", file);
825 			fprintf(stdout, "%lld\n", tln);
826 		}
827 		return;
828 	}
829 
830 	blkno = count;
831 	ptr = buf;
832 	for(;;) {
833 		if((ptrend = memchr(ptr, '\n', buf + count - ptr)) == NULL) {
834 			/*
835 				move the unused partial record to the head of the buffer
836 			*/
837 			if (ptr > buf) {
838 				count = buf + count - ptr;
839 				memmove (buf, ptr, count);
840 				ptr = buf;
841 			}
842 
843 			/*
844 				Get a bigger buffer if this one is full
845 			*/
846 			if(count > lBufSiz) {
847 				/*
848 					expand the buffer
849 				*/
850 				lBufSiz += EBUFSIZ;
851 				if ((buf = realloc (buf, lBufSiz + EBUFSIZ)) == NULL) {
852 					exit (2); /* out of memory - BAIL */
853 				}
854 
855 				ptr = buf;
856 			}
857 
858 			p = buf + count;
859 			if((count1 = read(fileno(f), p, EBUFSIZ)) > 0) {
860 				count += count1;
861 				blkno += count1;
862 				continue;
863 			}
864 			ptrend = ptr + count;
865 			nlflag = 0;
866 		} else
867 			nlflag = 1;
868 		*ptrend = '\n';
869 		p = ptr;
870 		lastptr = ptr;
871 		cstat = istat;
872 		succ = 0;
873 		for(;;) {
874 			if(out[cstat]) {
875 				if(multibyte && p > ptr) {
876 					wchar_t wchar;
877 					int length;
878 					char *endptr = p;
879 					p = lastptr;
880 					while(p < endptr) {
881 						length = mbtowc(&wchar, p, MB_LEN_MAX);
882 						if(length <= 1)
883 							p++;
884 						else
885 							p += length;
886 					}
887 					if(p == endptr) {
888 						succ = !vflag;
889 						break;
890 					}
891 					cstat = 1;
892 					length = mbtowc(&wchar, lastptr, MB_LEN_MAX);
893 					if(length <= 1)
894 						lastptr++;
895 					else
896 						lastptr += length;
897 					p = lastptr;
898 					continue;
899 				}
900 				succ = !vflag;
901 				break;
902 			}
903 			c = (unsigned char)*p++;
904 			if ((t = gotofn[cstat][c]) == 0)
905 				cstat = nxtst(cstat, c);
906 			else
907 				cstat = t;
908 			if(c == RIGHT) {
909 				if(out[cstat]) {
910 					succ = !vflag;
911 					break;
912 				}
913 				succ = vflag;
914 				break;
915 			}
916 		}
917 		if (succ) {
918 			nsucc = 1;
919 			if (lflag || qflag) {
920 				if (!qflag)
921 					(void) printf("%s\n", file);
922 				fclose(f);
923 				return;
924 			}
925 			if (cflag) {
926 				tln++;
927 			} else {
928 				if (Hflag || (nfile > 1 && !hflag))
929 					printf("%s:", file);
930 				if (bflag) {
931 					nchars = blkno - (buf + count - ptrend) - 2;
932 					if(nlflag)
933 						nchars++;
934 					printf("%lld:", nchars/BLKSIZE);
935 				}
936 				if (nflag)
937 					printf("%lld:", lnum);
938 				if(nlflag)
939 					nchars = ptrend - ptr + 1;
940 				else
941 					nchars = ptrend - ptr;
942 				fwrite(ptr, (size_t)1, (size_t)nchars, stdout);
943 			}
944 		}
945 		if(!nlflag)
946 			break;
947 		ptr = ptrend + 1;
948 		if(ptr >= buf + count) {
949 			ptr = buf;
950 			if((count = read(fileno(f), buf, EBUFSIZ)) <= 0)
951 				break;
952 			blkno += count;
953 		}
954 		lnum++;
955 		if (reinit == 1)
956 			clearg();
957 	}
958 	fclose(f);
959 	if (cflag && !qflag) {
960 		if (Hflag || (nfile > 1 && !hflag))
961 			printf("%s:", file);
962 		printf("%lld\n", tln);
963 	}
964 }
965 
966 void
967 clearg(void)
968 {
969 	int i, k;
970 	for (i=1; i<=nstate; i++)
971 		out[i] = 0;
972 	for (i=1; i<=nstate; i++)
973 		for (k=0; k<NCHARS; k++)
974 			gotofn[i][k] = 0;
975 	nstate = 1;
976 	nxtpos = inxtpos;
977 	reinit = 0;
978 	count = 0;
979 	for (i=3; i<=line; i++) tmpstat[i] = 0;
980 	if (cstate(line-1)==0) {
981 		tmpstat[line] = 1;
982 		count++;
983 		out[1] = 1;
984 	}
985 	for (i=3; i<=line; i++) initstat[i] = tmpstat[i];
986 	count--;		/*leave out position 1 */
987 	icount = count;
988 	tmpstat[1] = 0;
989 	add(state, 1);
990 	istat = nxtst(1, LEFT);
991 }
992 
993 int
994 mdotenter(void)
995 {
996 	int i, x1, x2;
997 	x1 = enter(DOT);
998 	x2 = enter(MDOT);
999 	for(i = 1; i < (int) eucw1; i++)
1000 		x2 = node(CAT, x2, enter(MDOT));
1001 	x1 = node(OR, x1, x2);
1002 	if(eucw2) {
1003 		x2 = enter('\216');
1004 		for(i = 1; i <= (int) eucw2; i++)
1005 			x2 = node(CAT, x2, enter(MDOT));
1006 		x1 = node(OR, x1, x2);
1007 	}
1008 	if(eucw3) {
1009 		x2 = enter('\217');
1010 		for(i = 1; i <= (int) eucw3; i++)
1011 			x2 = node(CAT, x2, enter(MDOT));
1012 		x1 = node(OR, x1, x2);
1013 	}
1014 	return(x1);
1015 }
1016 
1017 int
1018 mchar(wchar_t c)
1019 {
1020 	char multichar[MB_LEN_MAX+1];
1021 	char *p;
1022 	int x1, lc, length;
1023 
1024 	length = wctomb(multichar, c);
1025 	p = multichar;
1026 	*(p + length) = '\0';
1027 	x1 = enter((unsigned char)*p++);
1028 	while(lc = (unsigned char)*p++)
1029 		x1 = node(CAT, x1, enter(lc));
1030 	return(x1);
1031 }
1032 
1033 int
1034 ccl(int type)
1035 {
1036 	wchar_t c, lc;
1037 	char multic1[MB_LEN_MAX];
1038 	char multic2[MB_LEN_MAX];
1039 	int x1, x2, length, current, last, cclcnt;
1040 	x2 = 0;
1041 	current = 0;
1042 	last = genrange(type);
1043 	nxtchar = count + 1;
1044 	cclcnt = 0;
1045 	/* create usual character class for single byte characters */
1046 	while(current <= last && (isascii(c = lower[current]) || c <= 0377 && iscntrl(c))) {
1047 		cclcnt++;
1048 		chars[nxtchar++] = c;
1049 		if(lower[current] != upper[current]) {
1050 			chars[nxtchar++] = '-';
1051 			chars[nxtchar++] = upper[current];
1052 			cclcnt += 2;
1053 		}
1054 		current++;
1055 	}
1056 
1057 	if(cclcnt)
1058 		chars[count] = cclcnt;
1059 	else
1060 		nxtchar = count;
1061 	if(current > 0)
1062 		/* single byte part of character class */
1063 		x2 = cclenter(type);
1064 	else if(type == NCCL)
1065 		/* all single byte characters match */
1066 		x2 = enter(DOT);
1067 	while(current <= last) {
1068 		if(upper[current] == lower[current])
1069 			x1 = mchar(lower[current]);
1070 		else {
1071 			length = wctomb(multic1, lower[current]);
1072 			wctomb(multic2, upper[current]);
1073 			x1 = range((unsigned char *)multic1,
1074 			    (unsigned char *)multic2, length);
1075 		}
1076 		if(x2)
1077 			x2 = node(OR, x2, x1);
1078 		else
1079 			x2 = x1;
1080 		current++;
1081 	}
1082 	return x2;
1083 }
1084 
1085 int
1086 range(unsigned char *p1, unsigned char *p2, int length)
1087 {
1088 	char multic[MB_LEN_MAX+1];
1089 	char *p;
1090 	int i, x1, x2;
1091 	if(length == 1)
1092 		return(classenter(*p1, *p2));
1093 	if(p1[0] == p2[0])
1094 		return(node(CAT, enter(p1[0]), range(p1+1, p2+1, length - 1)));
1095 	p = multic;
1096 	for(i = 1; i < length; i++)
1097 		*p++ = 0377;
1098 	x1 = node(CAT, enter(p1[0]),
1099 	    range(p1+1, (unsigned char *)multic, length - 1));
1100 	if((unsigned char)(p1[0] + 1) < p2[0]) {
1101 		x2 = classenter(p1[0] + 1, p2[0] - 1);
1102 		for(i = 1; i < length; i++)
1103 			x2 = node(CAT, x2, enter(MDOT));
1104 		x1 = node(OR, x1, x2);
1105 	}
1106 	p = multic;
1107 	for(i = 1; i < length; i++)
1108 		*p++ = 0200;
1109 	x2 = node(CAT, enter(p2[0]),
1110 	    range((unsigned char *)multic, p2+1, length - 1));
1111 	return node(OR, x1, x2);
1112 }
1113 
1114 int
1115 classenter(int x1, int x2)
1116 {
1117 	static int max, min;
1118 	if(!max) {
1119 		int i;
1120 		for(i = 0200; i <= 0377; i++)
1121 			if(!iscntrl(i))
1122 				break;
1123 		min = i;
1124 		for(i = 0377; i >= 0200; i--)
1125 			if(!iscntrl(i))
1126 				break;
1127 		max = i;
1128 	}
1129 	if(x1 <= min && x2 >= max)
1130 		return enter(MDOT);
1131 	if(nxtchar + 4 >= maxclin)
1132 		if(allocchars() == 0)
1133 			overflo();
1134 	count = nxtchar++;
1135 	chars[nxtchar++] = x1;
1136 	chars[nxtchar++] = '-';
1137 	chars[nxtchar++] = x2;
1138 	chars[count] = 3;
1139 	return cclenter(MCCL);
1140 }
1141 
1142 int
1143 genrange(int type)
1144 {
1145 	char *p, *endp;
1146 	int current, nel, i, last, length;
1147 	wchar_t c, lc;
1148 
1149 	current = 0;
1150 	p = &chars[count+1];
1151 	endp = &chars[count+1] + chars[count];
1152 	lc = 0;
1153 
1154 	/* convert character class into union of ranges */
1155 	while(p < endp) {
1156 		length = mbtowc(&c, p, MB_LEN_MAX);
1157 		p += length;
1158 		if(c == '-' && lc != 0) {
1159 			length = mbtowc(&c, p, MB_LEN_MAX);
1160 			upper[current-1] = c;
1161 			p += length;
1162 		} else {
1163 			lower[current] = c;
1164 			upper[current++] = c;
1165 		}
1166 		lc = c;
1167 	}
1168 	nel = current;
1169 	/* sort lower and upper bounds of ranges */
1170 	qsort((char *)lower, nel, sizeof(wchar_t), compare);
1171 	qsort((char *)upper, nel, sizeof(wchar_t), compare);
1172 	last = current - 1;
1173 	current = 0;
1174 	/* combine overlapping or adjacent ranges */
1175 	for(i = 0; i < last; i++)
1176 		if(upper[i] >= lower[i+1] - 1)
1177 			upper[current] = upper[i+1];
1178 		else {
1179 			lower[++current] = lower[i+1];
1180 			upper[current] = upper[i+1];
1181 		}
1182 	if(type == NCCL) {
1183 		/* find complement of character class */
1184 		int j, next;
1185 		i = 0;
1186 		while(i <= current && isascii(c=lower[i]) || c <= 0377 && iscntrl(c))
1187 			i++;
1188 		if(i > current) {
1189 			/* match all multibyte characters */
1190 			if(eucw2) {
1191 				lower[i] = maxmin(WCHAR_CS2, 0);
1192 				upper[i++] = maxmin(WCHAR_CS2, 1);
1193 			}
1194 			if(eucw3) {
1195 				lower[i] = maxmin(WCHAR_CS3, 0);
1196 				upper[i++] = maxmin(WCHAR_CS3, 1);
1197 			}
1198 			lower[i] = maxmin(WCHAR_CS1, 0);
1199 			upper[i++] = maxmin(WCHAR_CS1, 1);
1200 			return i - 1;
1201 		}
1202 		next = current + 1;
1203 		if(next + current + 2 >= maxwclin) {
1204 			maxwclin += MAXLIN + next + current + 2;
1205 			if((lower = (wchar_t *)realloc(lower, maxwclin *sizeof(wchar_t))) == (wchar_t *)0 ||
1206 			   (upper = (wchar_t *)realloc(upper, maxwclin * sizeof(wchar_t))) == (wchar_t *)0)
1207 				overflo();
1208 		}
1209 		if(eucw2 && lower[i] > maxmin(WCHAR_CS2, 0)) {
1210 			lower[next] = maxmin(WCHAR_CS2, 0);
1211 			if((lower[i] & WCHAR_CSMASK) != WCHAR_CS2) {
1212 				upper[next++] = maxmin(WCHAR_CS2, 1);
1213 				if((lower[i] & WCHAR_CSMASK) == WCHAR_CS1 && eucw3) {
1214 					lower[next] = maxmin(WCHAR_CS3, 0);
1215 					upper[next++] = maxmin(WCHAR_CS3, 1);
1216 				}
1217 				if(lower[i] > maxmin(lower[i] & WCHAR_CSMASK, 0)) {
1218 					lower[next] = maxmin(lower[i] & WCHAR_CSMASK, 0);
1219 					upper[next++] = lower[i] - 1;
1220 				}
1221 			} else
1222 				upper[next++] = lower[i] - 1;
1223 		} else if(lower[i] > maxmin(lower[i] & WCHAR_CSMASK, 0)) {
1224 			lower[next] = maxmin(lower[i] & WCHAR_CSMASK, 0);
1225 			upper[next++] = lower[i] - 1;
1226 		}
1227 		for(j = i; j < current; j++) {
1228 			if(upper[j] < maxmin(upper[j] & WCHAR_CSMASK, 1)) {
1229 				lower[next] = upper[j] + 1;
1230 				if((upper[j] & WCHAR_CSMASK) != (lower[j+1] & WCHAR_CSMASK)) {
1231 					upper[next++] = maxmin(upper[j] & WCHAR_CSMASK, 1);
1232 					if(eucw3 && (upper[j] & WCHAR_CSMASK) == WCHAR_CS2 && (lower[j+1] & WCHAR_CSMASK) == WCHAR_CS1) {
1233 						lower[next] = maxmin(WCHAR_CS3, 0);
1234 						upper[next++] = maxmin(WCHAR_CS3, 1);
1235 					}
1236 					if(lower[j+1] > maxmin(lower[j+1] & WCHAR_CSMASK, 0)) {
1237 						lower[next] = maxmin(lower[j+1] & WCHAR_CSMASK, 0);
1238 						upper[next++] = lower[j+1] - 1;
1239 					}
1240 				} else
1241 					upper[next++] = lower[j+1] - 1;
1242 			} else if(lower[j+1] > maxmin(lower[j+1], 0)) {
1243 				lower[next] = maxmin(lower[j+1], 0);
1244 				upper[next++] = lower[j+1] - 1;
1245 			}
1246 		}
1247 		if(upper[current] < maxmin(upper[current] & WCHAR_CSMASK, 1)) {
1248 			lower[next] = upper[current] + 1;
1249 			upper[next++] = maxmin(upper[current] & WCHAR_CSMASK, 1);
1250 		}
1251 		if((upper[current] & WCHAR_CSMASK) != WCHAR_CS1) {
1252 			if((upper[current] & WCHAR_CSMASK) == WCHAR_CS2 && eucw3) {
1253 				lower[next] = maxmin(WCHAR_CS3, 0);
1254 				upper[next++] = maxmin(WCHAR_CS3, 1);
1255 			}
1256 			lower[next] = maxmin(WCHAR_CS1, 0);
1257 			upper[next++] = maxmin(WCHAR_CS1, 1);
1258 		}
1259 		for(j = current + 1; j < next; j++) {
1260 			lower[i] = lower[j];
1261 			upper[i++] = upper[j];
1262 		}
1263 		current = i - 1;
1264 	}
1265 	return(current);
1266 }
1267 
1268 int
1269 compare(wchar_t *c, wchar_t *d)
1270 {
1271 	if(*c < *d)
1272 		return -1;
1273 	if(*c == *d)
1274 		return 0;
1275 	return 1;
1276 }
1277 
1278 wchar_t
1279 maxmin(wchar_t c, int flag)
1280 {
1281 	static wchar_t minmax1[2], minmax2[2], minmax3[2];
1282 
1283 	if(!minmax1[0]) {
1284 		/* compute min and max process codes for all code sets */
1285 		int length, i;
1286 		char multic[MB_LEN_MAX], minmax[2];
1287 		for(i = 0377; i >= 0200; i--)
1288 			if(!iscntrl(i))
1289 				break;
1290 		minmax[1] = i;
1291 		for(i = 0240; i <= 0377; i++)
1292 			if(!iscntrl(i))
1293 				break;
1294 		minmax[0] = i;
1295 		for(i = 0; i <= 1; i++) {
1296 			length = MB_LEN_MAX;
1297 			while(length--)
1298 				multic[length] = minmax[i];
1299 			mbtowc(&minmax1[i], multic, MB_LEN_MAX);
1300 			if(eucw2) {
1301 				multic[0] = SS2;
1302 				mbtowc(&minmax2[i], multic, MB_LEN_MAX);
1303 			}
1304 			if(eucw3) {
1305 				multic[0] = SS3;
1306 				mbtowc(&minmax3[i], multic, MB_LEN_MAX);
1307 			}
1308 		}
1309 	}
1310 	switch(c) {
1311 		case WCHAR_CS1: return minmax1[flag];
1312 		case WCHAR_CS2: return minmax2[flag];
1313 		case WCHAR_CS3: return minmax3[flag];
1314 	}
1315 
1316 	/* NOTREACHED */
1317 	return (0);
1318 }
1319