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 "[ -bchilnsv ] [ -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:Hhlnvs")) != -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 }