Print this page
3047 grep support for -r would be useful


   7  * with the License.
   8  *
   9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10  * or http://www.opensolaris.org/os/licensing.
  11  * See the License for the specific language governing permissions
  12  * and limitations under the License.
  13  *
  14  * When distributing Covered Code, include this CDDL HEADER in each
  15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16  * If applicable, add the following below this CDDL HEADER, with the
  17  * fields enclosed by brackets "[]" replaced with your own identifying
  18  * information: Portions Copyright [yyyy] [name of copyright owner]
  19  *
  20  * CDDL HEADER END
  21  */
  22 /*
  23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #pragma ident   "%Z%%M% %I%     %E% SMI"
  28 
  29 /*
  30  * grep - pattern matching program - combined grep, egrep, and fgrep.
  31  *      Based on MKS grep command, with XCU & Solaris mods.
  32  */
  33 
  34 /*
  35  * Copyright 1985, 1992 by Mortice Kern Systems Inc.  All rights reserved.
  36  *
  37  */
  38 


  39 #include <string.h>
  40 #include <stdlib.h>
  41 #include <ctype.h>
  42 #include <stdarg.h>
  43 #include <regex.h>
  44 #include <limits.h>
  45 #include <sys/types.h>
  46 #include <sys/stat.h>
  47 #include <fcntl.h>
  48 #include <stdio.h>
  49 #include <locale.h>
  50 #include <wchar.h>
  51 #include <errno.h>
  52 #include <unistd.h>
  53 #include <wctype.h>


  54 
  55 #define BSIZE           512             /* Size of block for -b */
  56 #define BUFSIZE         8192            /* Input buffer size */

  57 
  58 #define M_CSETSIZE      256             /* singlebyte chars */
  59 static int      bmglen;                 /* length of BMG pattern */
  60 static char     *bmgpat;                /* BMG pattern */
  61 static int      bmgtab[M_CSETSIZE];     /* BMG delta1 table */
  62 
  63 typedef struct  _PATTERN        {
  64         char    *pattern;               /* original pattern */
  65         wchar_t *wpattern;              /* wide, lowercased pattern */
  66         struct  _PATTERN        *next;
  67         regex_t re;                     /* compiled pattern */
  68 } PATTERN;
  69 
  70 static PATTERN  *patterns;
  71 static char     errstr[128];            /* regerror string buffer */
  72 static int      regflags = 0;           /* regcomp options */


  73 static uchar_t  fgrep = 0;              /* Invoked as fgrep */
  74 static uchar_t  egrep = 0;              /* Invoked as egrep */
  75 static uchar_t  nvflag = 1;             /* Print matching lines */
  76 static uchar_t  cflag;                  /* Count of matches */
  77 static uchar_t  iflag;                  /* Case insensitve matching */
  78 static uchar_t  hflag;                  /* Supress printing of filename */
  79 static uchar_t  lflag;                  /* Print file names of matches */
  80 static uchar_t  nflag;                  /* Precede lines by line number */

  81 static uchar_t  bflag;                  /* Preccede matches by block number */
  82 static uchar_t  sflag;                  /* Suppress file error messages */
  83 static uchar_t  qflag;                  /* Suppress standard output */
  84 static uchar_t  wflag;                  /* Search for expression as a word */
  85 static uchar_t  xflag;                  /* Anchoring */
  86 static uchar_t  Eflag;                  /* Egrep or -E flag */
  87 static uchar_t  Fflag;                  /* Fgrep or -F flag */

  88 static uchar_t  outfn;                  /* Put out file name */
  89 static char     *cmdname;
  90 
  91 static int      use_wchar, use_bmg, mblocale;
  92 
  93 static size_t   outbuflen, prntbuflen;
  94 static char     *prntbuf;
  95 static wchar_t  *outline;
  96 
  97 static void     addfile(char *fn);
  98 static void     addpattern(char *s);
  99 static void     fixpatterns(void);
 100 static void     usage(void);
 101 static int      grep(int, char *);
 102 static void     bmgcomp(char *, int);
 103 static char     *bmgexec(char *, char *);



 104 
 105 /*
 106  * mainline for grep
 107  */
 108 int
 109 main(int argc, char **argv)
 110 {
 111         char    *ap;
 112         int     matched = 0;
 113         int     c;
 114         int     fflag = 0;
 115         int     errors = 0;
 116         int     i, n_pattern = 0, n_file = 0;
 117         char    **pattern_list = NULL;
 118         char    **file_list = NULL;
 119 
 120         (void) setlocale(LC_ALL, "");
 121 #if !defined(TEXT_DOMAIN)       /* Should be defined by cc -D */
 122 #define TEXT_DOMAIN     "SYS_TEST"      /* Use this only if it weren't */
 123 #endif
 124         (void) textdomain(TEXT_DOMAIN);
 125 
 126         /*
 127          * true if this is running on the multibyte locale
 128          */
 129         mblocale = (MB_CUR_MAX > 1);
 130         /*
 131          * Skip leading slashes
 132          */
 133         cmdname = argv[0];
 134         if (ap = strrchr(cmdname, '/'))
 135                 cmdname = ap + 1;
 136 
 137         ap = cmdname;
 138         /*
 139          * Detect egrep/fgrep via command name, map to -E and -F options.
 140          */
 141         if (*ap == 'e' || *ap == 'E') {
 142                 regflags |= REG_EXTENDED;
 143                 egrep++;
 144         } else {
 145                 if (*ap == 'f' || *ap == 'F') {
 146                         fgrep++;
 147                 }
 148         }
 149 
 150         while ((c = getopt(argc, argv, "vwchilnbse:f:qxEFI")) != EOF) {
 151                 switch (c) {
 152                 case 'v':       /* POSIX: negate matches */
 153                         nvflag = 0;
 154                         break;
 155 
 156                 case 'c':       /* POSIX: write count */
 157                         cflag++;
 158                         break;
 159 
 160                 case 'i':       /* POSIX: ignore case */
 161                         iflag++;
 162                         regflags |= REG_ICASE;
 163                         break;
 164 
 165                 case 'l':       /* POSIX: Write filenames only */
 166                         lflag++;
 167                         break;
 168 
 169                 case 'n':       /* POSIX: Write line numbers */
 170                         nflag++;
 171                         break;
 172 




 173                 case 'b':       /* Solaris: Write file block numbers */
 174                         bflag++;
 175                         break;
 176 
 177                 case 's':       /* POSIX: No error msgs for files */
 178                         sflag++;
 179                         break;
 180 
 181                 case 'e':       /* POSIX: pattern list */
 182                         n_pattern++;
 183                         pattern_list = realloc(pattern_list,
 184                             sizeof (char *) * n_pattern);
 185                         if (pattern_list == NULL) {
 186                                 (void) fprintf(stderr,
 187                                     gettext("%s: out of memory\n"),
 188                                     cmdname);
 189                                 exit(2);
 190                         }
 191                         *(pattern_list + n_pattern - 1) = optarg;
 192                         break;


 213                         break;
 214 
 215                 case 'w':       /* Solaris: treat pattern as word */
 216                         wflag++;
 217                         break;
 218 
 219                 case 'x':       /* POSIX: full line matches */
 220                         xflag++;
 221                         regflags |= REG_ANCHOR;
 222                         break;
 223 
 224                 case 'E':       /* POSIX: Extended RE's */
 225                         regflags |= REG_EXTENDED;
 226                         Eflag++;
 227                         break;
 228 
 229                 case 'F':       /* POSIX: strings, not RE's */
 230                         Fflag++;
 231                         break;
 232 





 233                 default:
 234                         usage();
 235                 }
 236         }
 237         /*
 238          * If we're invoked as egrep or fgrep we need to do some checks
 239          */
 240 
 241         if (egrep || fgrep) {
 242                 /*
 243                  * Use of -E or -F with egrep or fgrep is illegal
 244                  */
 245                 if (Eflag || Fflag)
 246                         usage();
 247                 /*
 248                  * Don't allow use of wflag with egrep / fgrep
 249                  */
 250                 if (wflag)
 251                         usage();
 252                 /*


 317         /*
 318          * If -x flag is not specified or -i flag is specified
 319          * with fgrep in a multibyte locale, need to use
 320          * the wide character APIs.  Otherwise, byte-oriented
 321          * process will be done.
 322          */
 323         use_wchar = Fflag && mblocale && (!xflag || iflag);
 324 
 325         /*
 326          * Compile Patterns and also decide if BMG can be used
 327          */
 328         fixpatterns();
 329 
 330         /* Process all files: stdin, or rest of arg list */
 331         if (argc < 2) {
 332                 matched = grep(0, gettext("(standard input)"));
 333         } else {
 334                 if (argc > 2 && hflag == 0)
 335                         outfn = 1;      /* Print filename on match line */
 336                 for (argv++; *argv != NULL; argv++) {
 337                         int     fd;
 338 
 339                         if ((fd = open(*argv, O_RDONLY)) == -1) {
 340                                 errors = 1;
 341                                 if (sflag)
 342                                         continue;
 343                                 (void) fprintf(stderr, gettext(
 344                                     "%s: can't open \"%s\"\n"),
 345                                     cmdname, *argv);
 346                                 continue;
 347                         }
 348                         matched |= grep(fd, *argv);
 349                         (void) close(fd);
 350                         if (ferror(stdout))
 351                                 break;
 352                 }
 353         }
 354         /*
 355          * Return() here is used instead of exit
 356          */
 357 
 358         (void) fflush(stdout);
 359 
 360         if (errors)
 361                 return (2);
 362         return (matched ? 0 : 1);
 363 }
 364 










































 365 /*

























































 366  * Add a file of strings to the pattern list.
 367  */
 368 static void
 369 addfile(char *fn)
 370 {
 371         FILE    *fp;
 372         char    *inbuf;
 373         char    *bufp;
 374         size_t  bufsiz, buflen, bufused;
 375 
 376         /*
 377          * Open the pattern file
 378          */
 379         if ((fp = fopen(fn, "r")) == NULL) {
 380                 (void) fprintf(stderr, gettext("%s: can't open \"%s\"\n"),
 381                     cmdname, fn);
 382                 exit(2);
 383         }
 384         bufsiz = BUFSIZE;
 385         if ((inbuf = malloc(bufsiz)) == NULL) {
 386                 (void) fprintf(stderr,
 387                     gettext("%s: out of memory\n"), cmdname);
 388                 exit(2);
 389         }


 658         p = ibuf;
 659         do {
 660                 *p++ = tolower(*s1);
 661         } while (*s1++ != '\0');
 662         return (ibuf);
 663 }
 664 
 665 /*
 666  * Do grep on a single file.
 667  * Return true in any lines matched.
 668  *
 669  * We have two strategies:
 670  * The fast one is used when we have a single pattern with
 671  * a string known to occur in the pattern. We can then
 672  * do a BMG match on the whole buffer.
 673  * This is an order of magnitude faster.
 674  * Otherwise we split the buffer into lines,
 675  * and check for a match on each line.
 676  */
 677 static int
 678 grep(int fd, char *fn)
 679 {
 680         PATTERN *pp;
 681         off_t   data_len;       /* length of the data chunk */
 682         off_t   line_len;       /* length of the current line */
 683         off_t   line_offset;    /* current line's offset from the beginning */
 684         long long       lineno;
 685         long long       matches = 0;    /* Number of matching lines */
 686         int     newlinep;       /* 0 if the last line of file has no newline */
 687         char    *ptr, *ptrend;
 688 
 689 
 690         if (patterns == NULL)
 691                 return (0);     /* no patterns to match -- just return */
 692 
 693         pp = patterns;
 694 
 695         if (use_bmg) {
 696                 bmgcomp(pp->pattern, strlen(pp->pattern));
 697         }
 698 


 723                 long    count;
 724                 off_t   offset = 0;
 725 
 726                 if (data_len == 0) {
 727                         /*
 728                          * If no data in the buffer, reset ptr
 729                          */
 730                         ptr = prntbuf;
 731                 }
 732                 if (ptr == prntbuf) {
 733                         /*
 734                          * The current data chunk starts from prntbuf.
 735                          * This means either the buffer has no data
 736                          * or the buffer has no newline.
 737                          * So, read more data from input.
 738                          */
 739                         count = read(fd, ptr + data_len, prntbuflen - data_len);
 740                         if (count < 0) {
 741                                 /* read error */
 742                                 if (cflag) {
 743                                         if (outfn) {
 744                                                 (void) fprintf(stdout,
 745                                                     "%s:", fn);
 746                                         }
 747                                         if (!qflag) {
 748                                                 (void) fprintf(stdout, "%lld\n",
 749                                                     matches);
 750                                         }
 751                                 }
 752                                 return (0);
 753                         } else if (count == 0) {
 754                                 /* no new data */
 755                                 if (data_len == 0) {
 756                                         /* end of file already reached */
 757                                         break;
 758                                 }
 759                                 /* last line of file has no newline */
 760                                 ptrend = ptr + data_len;
 761                                 newlinep = 0;
 762                                 goto L_start_process;
 763                         }
 764                         offset = data_len;
 765                         data_len += count;
 766                 }
 767 


1039         if (cflag) {
1040                 if (outfn) {
1041                         (void) printf("%s:", fn);
1042                 }
1043                 if (!qflag) {
1044                         (void) printf("%lld\n", matches);
1045                 }
1046         }
1047         return (matches != 0);
1048 }
1049 
1050 /*
1051  * usage message for grep
1052  */
1053 static void
1054 usage(void)
1055 {
1056         if (egrep || fgrep) {
1057                 (void) fprintf(stderr, gettext("Usage:\t%s"), cmdname);
1058                 (void) fprintf(stderr,
1059                     gettext(" [-c|-l|-q] [-bhinsvx] "
1060                         "pattern_list [file ...]\n"));
1061 
1062                 (void) fprintf(stderr, "\t%s", cmdname);
1063                 (void) fprintf(stderr,
1064                     gettext(" [-c|-l|-q] [-bhinsvx] [-e pattern_list]... "

1065                         "[-f pattern_file]... [file...]\n"));
1066         } else {
1067                 (void) fprintf(stderr, gettext("Usage:\t%s"), cmdname);
1068                 (void) fprintf(stderr,
1069                     gettext(" [-c|-l|-q] [-bhinsvwx] "
1070                         "pattern_list [file ...]\n"));
1071 
1072                 (void) fprintf(stderr, "\t%s", cmdname);
1073                 (void) fprintf(stderr,
1074                     gettext(" [-c|-l|-q] [-bhinsvwx] [-e pattern_list]... "

1075                         "[-f pattern_file]... [file...]\n"));
1076 
1077                 (void) fprintf(stderr, "\t%s", cmdname);
1078                 (void) fprintf(stderr,
1079                     gettext(" -E [-c|-l|-q] [-bhinsvx] "
1080                         "pattern_list [file ...]\n"));
1081 
1082                 (void) fprintf(stderr, "\t%s", cmdname);
1083                 (void) fprintf(stderr,
1084                     gettext(" -E [-c|-l|-q] [-bhinsvx] [-e pattern_list]... "

1085                         "[-f pattern_file]... [file...]\n"));
1086 
1087                 (void) fprintf(stderr, "\t%s", cmdname);
1088                 (void) fprintf(stderr,
1089                     gettext(" -F [-c|-l|-q] [-bhinsvx] "
1090                         "pattern_list [file ...]\n"));
1091 
1092                 (void) fprintf(stderr, "\t%s", cmdname);
1093                 (void) fprintf(stderr,
1094                     gettext(" -F [-c|-l|-q] [-bhinsvx] [-e pattern_list]... "
1095                         "[-f pattern_file]... [file...]\n"));
1096         }
1097         exit(2);
1098         /* NOTREACHED */
1099 }
1100 
1101 /*
1102  * Compile literal pattern into BMG tables
1103  */
1104 static void
1105 bmgcomp(char *pat, int len)
1106 {
1107         int     i;
1108         int     tlen;
1109         unsigned char   *uc = (unsigned char *)pat;




   7  * with the License.
   8  *
   9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10  * or http://www.opensolaris.org/os/licensing.
  11  * See the License for the specific language governing permissions
  12  * and limitations under the License.
  13  *
  14  * When distributing Covered Code, include this CDDL HEADER in each
  15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16  * If applicable, add the following below this CDDL HEADER, with the
  17  * fields enclosed by brackets "[]" replaced with your own identifying
  18  * information: Portions Copyright [yyyy] [name of copyright owner]
  19  *
  20  * CDDL HEADER END
  21  */
  22 /*
  23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 


  27 /*
  28  * grep - pattern matching program - combined grep, egrep, and fgrep.
  29  *      Based on MKS grep command, with XCU & Solaris mods.
  30  */
  31 
  32 /*
  33  * Copyright 1985, 1992 by Mortice Kern Systems Inc.  All rights reserved.
  34  *
  35  */
  36 
  37 /* Copyright 2012 Nexenta Systems, Inc.  All rights reserved. */
  38 
  39 #include <string.h>
  40 #include <stdlib.h>
  41 #include <ctype.h>
  42 #include <stdarg.h>
  43 #include <regex.h>
  44 #include <limits.h>
  45 #include <sys/types.h>
  46 #include <sys/stat.h>
  47 #include <fcntl.h>
  48 #include <stdio.h>
  49 #include <locale.h>
  50 #include <wchar.h>
  51 #include <errno.h>
  52 #include <unistd.h>
  53 #include <wctype.h>
  54 #include <ftw.h>
  55 #include <sys/param.h>
  56 
  57 #define BSIZE           512             /* Size of block for -b */
  58 #define BUFSIZE         8192            /* Input buffer size */
  59 #define MAX_DEPTH       1000            /* how deep to recurse */
  60 
  61 #define M_CSETSIZE      256             /* singlebyte chars */
  62 static int      bmglen;                 /* length of BMG pattern */
  63 static char     *bmgpat;                /* BMG pattern */
  64 static int      bmgtab[M_CSETSIZE];     /* BMG delta1 table */
  65 
  66 typedef struct  _PATTERN        {
  67         char    *pattern;               /* original pattern */
  68         wchar_t *wpattern;              /* wide, lowercased pattern */
  69         struct  _PATTERN        *next;
  70         regex_t re;                     /* compiled pattern */
  71 } PATTERN;
  72 
  73 static PATTERN  *patterns;
  74 static char     errstr[128];            /* regerror string buffer */
  75 static int      regflags = 0;           /* regcomp options */
  76 static int      matched = 0;            /* return of the grep() */
  77 static int      errors = 0;             /* count of errors */
  78 static uchar_t  fgrep = 0;              /* Invoked as fgrep */
  79 static uchar_t  egrep = 0;              /* Invoked as egrep */
  80 static uchar_t  nvflag = 1;             /* Print matching lines */
  81 static uchar_t  cflag;                  /* Count of matches */
  82 static uchar_t  iflag;                  /* Case insensitve matching */
  83 static uchar_t  hflag;                  /* Supress printing of filename */
  84 static uchar_t  lflag;                  /* Print file names of matches */
  85 static uchar_t  nflag;                  /* Precede lines by line number */
  86 static uchar_t  rflag;                  /* Search directories recursively */
  87 static uchar_t  bflag;                  /* Preccede matches by block number */
  88 static uchar_t  sflag;                  /* Suppress file error messages */
  89 static uchar_t  qflag;                  /* Suppress standard output */
  90 static uchar_t  wflag;                  /* Search for expression as a word */
  91 static uchar_t  xflag;                  /* Anchoring */
  92 static uchar_t  Eflag;                  /* Egrep or -E flag */
  93 static uchar_t  Fflag;                  /* Fgrep or -F flag */
  94 static uchar_t  Rflag;                  /* Like rflag, but follow symlinks */
  95 static uchar_t  outfn;                  /* Put out file name */
  96 static char     *cmdname;
  97 
  98 static int      use_wchar, use_bmg, mblocale;
  99 
 100 static size_t   outbuflen, prntbuflen;
 101 static char     *prntbuf;
 102 static wchar_t  *outline;
 103 
 104 static void     addfile(const char *fn);
 105 static void     addpattern(char *s);
 106 static void     fixpatterns(void);
 107 static void     usage(void);
 108 static int      grep(int, const char *);
 109 static void     bmgcomp(char *, int);
 110 static char     *bmgexec(char *, char *);
 111 static int      recursive(const char *, const struct stat *, int, struct FTW *);
 112 static void     process_path(const char *);
 113 static void     process_file(const char *, int);
 114 
 115 /*
 116  * mainline for grep
 117  */
 118 int
 119 main(int argc, char **argv)
 120 {
 121         char    *ap;

 122         int     c;
 123         int     fflag = 0;

 124         int     i, n_pattern = 0, n_file = 0;
 125         char    **pattern_list = NULL;
 126         char    **file_list = NULL;
 127 
 128         (void) setlocale(LC_ALL, "");
 129 #if !defined(TEXT_DOMAIN)       /* Should be defined by cc -D */
 130 #define TEXT_DOMAIN     "SYS_TEST"      /* Use this only if it weren't */
 131 #endif
 132         (void) textdomain(TEXT_DOMAIN);
 133 
 134         /*
 135          * true if this is running on the multibyte locale
 136          */
 137         mblocale = (MB_CUR_MAX > 1);
 138         /*
 139          * Skip leading slashes
 140          */
 141         cmdname = argv[0];
 142         if (ap = strrchr(cmdname, '/'))
 143                 cmdname = ap + 1;
 144 
 145         ap = cmdname;
 146         /*
 147          * Detect egrep/fgrep via command name, map to -E and -F options.
 148          */
 149         if (*ap == 'e' || *ap == 'E') {
 150                 regflags |= REG_EXTENDED;
 151                 egrep++;
 152         } else {
 153                 if (*ap == 'f' || *ap == 'F') {
 154                         fgrep++;
 155                 }
 156         }
 157 
 158         while ((c = getopt(argc, argv, "vwchilnrbse:f:qxEFIR")) != EOF) {
 159                 switch (c) {
 160                 case 'v':       /* POSIX: negate matches */
 161                         nvflag = 0;
 162                         break;
 163 
 164                 case 'c':       /* POSIX: write count */
 165                         cflag++;
 166                         break;
 167 
 168                 case 'i':       /* POSIX: ignore case */
 169                         iflag++;
 170                         regflags |= REG_ICASE;
 171                         break;
 172 
 173                 case 'l':       /* POSIX: Write filenames only */
 174                         lflag++;
 175                         break;
 176 
 177                 case 'n':       /* POSIX: Write line numbers */
 178                         nflag++;
 179                         break;
 180 
 181                 case 'r':       /* Solaris: search recursively */
 182                         rflag++;
 183                         break;
 184 
 185                 case 'b':       /* Solaris: Write file block numbers */
 186                         bflag++;
 187                         break;
 188 
 189                 case 's':       /* POSIX: No error msgs for files */
 190                         sflag++;
 191                         break;
 192 
 193                 case 'e':       /* POSIX: pattern list */
 194                         n_pattern++;
 195                         pattern_list = realloc(pattern_list,
 196                             sizeof (char *) * n_pattern);
 197                         if (pattern_list == NULL) {
 198                                 (void) fprintf(stderr,
 199                                     gettext("%s: out of memory\n"),
 200                                     cmdname);
 201                                 exit(2);
 202                         }
 203                         *(pattern_list + n_pattern - 1) = optarg;
 204                         break;


 225                         break;
 226 
 227                 case 'w':       /* Solaris: treat pattern as word */
 228                         wflag++;
 229                         break;
 230 
 231                 case 'x':       /* POSIX: full line matches */
 232                         xflag++;
 233                         regflags |= REG_ANCHOR;
 234                         break;
 235 
 236                 case 'E':       /* POSIX: Extended RE's */
 237                         regflags |= REG_EXTENDED;
 238                         Eflag++;
 239                         break;
 240 
 241                 case 'F':       /* POSIX: strings, not RE's */
 242                         Fflag++;
 243                         break;
 244 
 245                 case 'R':       /* Solaris: like rflag, but follow symlinks */
 246                         Rflag++;
 247                         rflag++;
 248                         break;
 249 
 250                 default:
 251                         usage();
 252                 }
 253         }
 254         /*
 255          * If we're invoked as egrep or fgrep we need to do some checks
 256          */
 257 
 258         if (egrep || fgrep) {
 259                 /*
 260                  * Use of -E or -F with egrep or fgrep is illegal
 261                  */
 262                 if (Eflag || Fflag)
 263                         usage();
 264                 /*
 265                  * Don't allow use of wflag with egrep / fgrep
 266                  */
 267                 if (wflag)
 268                         usage();
 269                 /*


 334         /*
 335          * If -x flag is not specified or -i flag is specified
 336          * with fgrep in a multibyte locale, need to use
 337          * the wide character APIs.  Otherwise, byte-oriented
 338          * process will be done.
 339          */
 340         use_wchar = Fflag && mblocale && (!xflag || iflag);
 341 
 342         /*
 343          * Compile Patterns and also decide if BMG can be used
 344          */
 345         fixpatterns();
 346 
 347         /* Process all files: stdin, or rest of arg list */
 348         if (argc < 2) {
 349                 matched = grep(0, gettext("(standard input)"));
 350         } else {
 351                 if (argc > 2 && hflag == 0)
 352                         outfn = 1;      /* Print filename on match line */
 353                 for (argv++; *argv != NULL; argv++) {
 354                         process_path(*argv);









 355                 }




 356         }

 357         /*
 358          * Return() here is used instead of exit
 359          */
 360 
 361         (void) fflush(stdout);
 362 
 363         if (errors)
 364                 return (2);
 365         return (matched ? 0 : 1);
 366 }
 367 
 368 static void
 369 process_path(const char *path)
 370 {
 371         struct  stat st;
 372         int     walkflags = FTW_CHDIR;
 373         char    *buf = NULL;
 374 
 375         if (rflag) {
 376                 if (stat(path, &st) != -1 &&
 377                     (st.st_mode & S_IFMT) == S_IFDIR) {
 378                         outfn = 1; /* Print filename */
 379 
 380                         /*
 381                          * Add trailing slash if arg
 382                          * is directory, to resolve symlinks.
 383                          */
 384                         if (path[strlen(path) - 1] != '/') {
 385                                 (void) asprintf(&buf, "%s/", path);
 386                                 if (buf != NULL)
 387                                         path = buf;
 388                         }
 389 
 390                         /*
 391                          * Search through subdirs if path is directory.
 392                          * Don't follow symlinks if Rflag is not set.
 393                          */
 394                         if (!Rflag)
 395                                 walkflags |= FTW_PHYS;
 396 
 397                         if (nftw(path, recursive, MAX_DEPTH, walkflags) != 0) {
 398                                 if (!sflag)
 399                                         (void) fprintf(stderr,
 400                                             gettext("%s: can't open \"%s\"\n"),
 401                                             cmdname, path);
 402                                 errors = 1;
 403                         }
 404                         return;
 405                 }
 406         }
 407         process_file(path, 0);
 408 }
 409 
 410 /*
 411  * Read and process all files in directory recursively.
 412  */
 413 static int
 414 recursive(const char *name, const struct stat *statp, int info, struct FTW *ftw)
 415 {
 416         /*
 417          * Process files and follow symlinks if Rflag set.
 418          */
 419         if (info != FTW_F) {
 420                 /* Report broken symlinks and unreadable files */
 421                 if (!sflag &&
 422                     (info == FTW_SLN || info == FTW_DNR || info == FTW_NS)) {
 423                         (void) fprintf(stderr,
 424                             gettext("%s: can't open \"%s\"\n"), cmdname, name);
 425                 }
 426                 return (0);
 427         }
 428 
 429 
 430         /* Skip devices and pipes if Rflag is not set */
 431         if (!Rflag && !S_ISREG(statp->st_mode))
 432                 return (0);
 433         /* Pass offset to relative name from FTW_CHDIR */
 434         process_file(name, ftw->base);
 435         return (0);
 436 }
 437 
 438 /*
 439  * Opens file and call grep function.
 440  */
 441 static void
 442 process_file(const char *name, int base)
 443 {
 444         int fd;
 445 
 446         if ((fd = open(name + base, O_RDONLY)) == -1) {
 447                 errors = 1;
 448                 if (!sflag) /* Silent mode */
 449                         (void) fprintf(stderr, gettext(
 450                             "%s: can't open \"%s\"\n"),
 451                             cmdname, name);
 452                 return;
 453         }
 454         matched |= grep(fd, name);
 455         (void) close(fd);
 456 
 457         if (ferror(stdout)) {
 458                 (void) fprintf(stderr, gettext(
 459                     "%s: error writing to stdout\n"),
 460                     cmdname);
 461                 (void) fflush(stdout);
 462                 exit(2);
 463         }
 464 
 465 }
 466 
 467 /*
 468  * Add a file of strings to the pattern list.
 469  */
 470 static void
 471 addfile(const char *fn)
 472 {
 473         FILE    *fp;
 474         char    *inbuf;
 475         char    *bufp;
 476         size_t  bufsiz, buflen, bufused;
 477 
 478         /*
 479          * Open the pattern file
 480          */
 481         if ((fp = fopen(fn, "r")) == NULL) {
 482                 (void) fprintf(stderr, gettext("%s: can't open \"%s\"\n"),
 483                     cmdname, fn);
 484                 exit(2);
 485         }
 486         bufsiz = BUFSIZE;
 487         if ((inbuf = malloc(bufsiz)) == NULL) {
 488                 (void) fprintf(stderr,
 489                     gettext("%s: out of memory\n"), cmdname);
 490                 exit(2);
 491         }


 760         p = ibuf;
 761         do {
 762                 *p++ = tolower(*s1);
 763         } while (*s1++ != '\0');
 764         return (ibuf);
 765 }
 766 
 767 /*
 768  * Do grep on a single file.
 769  * Return true in any lines matched.
 770  *
 771  * We have two strategies:
 772  * The fast one is used when we have a single pattern with
 773  * a string known to occur in the pattern. We can then
 774  * do a BMG match on the whole buffer.
 775  * This is an order of magnitude faster.
 776  * Otherwise we split the buffer into lines,
 777  * and check for a match on each line.
 778  */
 779 static int
 780 grep(int fd, const char *fn)
 781 {
 782         PATTERN *pp;
 783         off_t   data_len;       /* length of the data chunk */
 784         off_t   line_len;       /* length of the current line */
 785         off_t   line_offset;    /* current line's offset from the beginning */
 786         long long       lineno;
 787         long long       matches = 0;    /* Number of matching lines */
 788         int     newlinep;       /* 0 if the last line of file has no newline */
 789         char    *ptr, *ptrend;
 790 
 791 
 792         if (patterns == NULL)
 793                 return (0);     /* no patterns to match -- just return */
 794 
 795         pp = patterns;
 796 
 797         if (use_bmg) {
 798                 bmgcomp(pp->pattern, strlen(pp->pattern));
 799         }
 800 


 825                 long    count;
 826                 off_t   offset = 0;
 827 
 828                 if (data_len == 0) {
 829                         /*
 830                          * If no data in the buffer, reset ptr
 831                          */
 832                         ptr = prntbuf;
 833                 }
 834                 if (ptr == prntbuf) {
 835                         /*
 836                          * The current data chunk starts from prntbuf.
 837                          * This means either the buffer has no data
 838                          * or the buffer has no newline.
 839                          * So, read more data from input.
 840                          */
 841                         count = read(fd, ptr + data_len, prntbuflen - data_len);
 842                         if (count < 0) {
 843                                 /* read error */
 844                                 if (cflag) {
 845                                         if (outfn && !rflag) {
 846                                                 (void) fprintf(stdout,
 847                                                     "%s:", fn);
 848                                         }
 849                                         if (!qflag && !rflag) {
 850                                                 (void) fprintf(stdout, "%lld\n",
 851                                                     matches);
 852                                         }
 853                                 }
 854                                 return (0);
 855                         } else if (count == 0) {
 856                                 /* no new data */
 857                                 if (data_len == 0) {
 858                                         /* end of file already reached */
 859                                         break;
 860                                 }
 861                                 /* last line of file has no newline */
 862                                 ptrend = ptr + data_len;
 863                                 newlinep = 0;
 864                                 goto L_start_process;
 865                         }
 866                         offset = data_len;
 867                         data_len += count;
 868                 }
 869 


1141         if (cflag) {
1142                 if (outfn) {
1143                         (void) printf("%s:", fn);
1144                 }
1145                 if (!qflag) {
1146                         (void) printf("%lld\n", matches);
1147                 }
1148         }
1149         return (matches != 0);
1150 }
1151 
1152 /*
1153  * usage message for grep
1154  */
1155 static void
1156 usage(void)
1157 {
1158         if (egrep || fgrep) {
1159                 (void) fprintf(stderr, gettext("Usage:\t%s"), cmdname);
1160                 (void) fprintf(stderr,
1161                     gettext(" [-c|-l|-q] [-r|-R] [-bhinsvx] "
1162                     "pattern_list [file ...]\n"));
1163 
1164                 (void) fprintf(stderr, "\t%s", cmdname);
1165                 (void) fprintf(stderr,
1166                     gettext(" [-c|-l|-q] [-r|-R] [-bhinsvx] "
1167                     "[-e pattern_list]... "
1168                     "[-f pattern_file]... [file...]\n"));
1169         } else {
1170                 (void) fprintf(stderr, gettext("Usage:\t%s"), cmdname);
1171                 (void) fprintf(stderr,
1172                     gettext(" [-c|-l|-q] [-r|-R] [-bhinsvwx] "
1173                     "pattern_list [file ...]\n"));
1174 
1175                 (void) fprintf(stderr, "\t%s", cmdname);
1176                 (void) fprintf(stderr,
1177                     gettext(" [-c|-l|-q] [-r|-R] [-bhinsvwx] "
1178                     "[-e pattern_list]... "
1179                     "[-f pattern_file]... [file...]\n"));
1180 
1181                 (void) fprintf(stderr, "\t%s", cmdname);
1182                 (void) fprintf(stderr,
1183                     gettext(" -E [-c|-l|-q] [-r|-R] [-bhinsvx] "
1184                     "pattern_list [file ...]\n"));
1185 
1186                 (void) fprintf(stderr, "\t%s", cmdname);
1187                 (void) fprintf(stderr,
1188                     gettext(" -E [-c|-l|-q] [-r|-R] [-bhinsvx] "
1189                     "[-e pattern_list]... "
1190                     "[-f pattern_file]... [file...]\n"));
1191 
1192                 (void) fprintf(stderr, "\t%s", cmdname);
1193                 (void) fprintf(stderr,
1194                     gettext(" -F [-c|-l|-q] [-r|-R] [-bhinsvx] "
1195                     "pattern_list [file ...]\n"));
1196 
1197                 (void) fprintf(stderr, "\t%s", cmdname);
1198                 (void) fprintf(stderr,
1199                     gettext(" -F [-c|-l|-q] [-bhinsvx] [-e pattern_list]... "
1200                     "[-f pattern_file]... [file...]\n"));
1201         }
1202         exit(2);
1203         /* NOTREACHED */
1204 }
1205 
1206 /*
1207  * Compile literal pattern into BMG tables
1208  */
1209 static void
1210 bmgcomp(char *pat, int len)
1211 {
1212         int     i;
1213         int     tlen;
1214         unsigned char   *uc = (unsigned char *)pat;