47 #include <regex.h>
48 #include <limits.h>
49 #include <sys/types.h>
50 #include <sys/stat.h>
51 #include <fcntl.h>
52 #include <stdio.h>
53 #include <locale.h>
54 #include <wchar.h>
55 #include <errno.h>
56 #include <unistd.h>
57 #include <wctype.h>
58 #include <ftw.h>
59 #include <sys/param.h>
60
61 #define STDIN_FILENAME gettext("(standard input)")
62
63 #define BSIZE 512 /* Size of block for -b */
64 #define BUFSIZE 8192 /* Input buffer size */
65 #define MAX_DEPTH 1000 /* how deep to recurse */
66
67 #define M_CSETSIZE 256 /* singlebyte chars */
68 static int bmglen; /* length of BMG pattern */
69 static char *bmgpat; /* BMG pattern */
70 static int bmgtab[M_CSETSIZE]; /* BMG delta1 table */
71
72 typedef struct _PATTERN {
73 char *pattern; /* original pattern */
74 wchar_t *wpattern; /* wide, lowercased pattern */
75 struct _PATTERN *next;
76 regex_t re; /* compiled pattern */
77 } PATTERN;
78
79 static PATTERN *patterns;
80 static char errstr[128]; /* regerror string buffer */
81 static int regflags = 0; /* regcomp options */
82 static int matched = 0; /* return of the grep() */
83 static int errors = 0; /* count of errors */
84 static uchar_t fgrep = 0; /* Invoked as fgrep */
85 static uchar_t egrep = 0; /* Invoked as egrep */
86 static uchar_t nvflag = 1; /* Print matching lines */
87 static uchar_t cflag; /* Count of matches */
88 static uchar_t iflag; /* Case insensitve matching */
89 static uchar_t Hflag; /* Precede lines by file name */
90 static uchar_t hflag; /* Supress printing of filename */
91 static uchar_t lflag; /* Print file names of matches */
92 static uchar_t nflag; /* Precede lines by line number */
93 static uchar_t rflag; /* Search directories recursively */
94 static uchar_t bflag; /* Preccede matches by block number */
95 static uchar_t sflag; /* Suppress file error messages */
96 static uchar_t qflag; /* Suppress standard output */
97 static uchar_t wflag; /* Search for expression as a word */
98 static uchar_t xflag; /* Anchoring */
99 static uchar_t Eflag; /* Egrep or -E flag */
100 static uchar_t Fflag; /* Fgrep or -F flag */
101 static uchar_t Rflag; /* Like rflag, but follow symlinks */
102 static uchar_t outfn; /* Put out file name */
103 static char *cmdname;
104
105 static int use_wchar, use_bmg, mblocale;
106
107 static size_t outbuflen, prntbuflen;
108 static char *prntbuf;
109 static wchar_t *outline;
110
111 static void addfile(const char *fn);
112 static void addpattern(char *s);
113 static void fixpatterns(void);
114 static void usage(void);
115 static int grep(int, const char *);
116 static void bmgcomp(char *, int);
117 static char *bmgexec(char *, char *);
118 static int recursive(const char *, const struct stat *, int, struct FTW *);
119 static void process_path(const char *);
120 static void process_file(const char *, int);
121
122 /*
123 * mainline for grep
124 */
125 int
126 main(int argc, char **argv)
127 {
128 char *ap;
129 int c;
130 int fflag = 0;
131 int i, n_pattern = 0, n_file = 0;
132 char **pattern_list = NULL;
133 char **file_list = NULL;
134
135 (void) setlocale(LC_ALL, "");
136 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
137 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
138 #endif
139 (void) textdomain(TEXT_DOMAIN);
140
141 /*
142 * true if this is running on the multibyte locale
143 */
144 mblocale = (MB_CUR_MAX > 1);
145 /*
146 * Skip leading slashes
147 */
148 cmdname = argv[0];
149 if (ap = strrchr(cmdname, '/'))
150 cmdname = ap + 1;
151
152 ap = cmdname;
153 /*
154 * Detect egrep/fgrep via command name, map to -E and -F options.
155 */
156 if (*ap == 'e' || *ap == 'E') {
157 regflags |= REG_EXTENDED;
158 egrep++;
159 } else {
160 if (*ap == 'f' || *ap == 'F') {
161 fgrep++;
162 }
163 }
164
165 while ((c = getopt(argc, argv, "vwchHilnrbse:f:qxEFIR")) != EOF) {
166 switch (c) {
167 case 'v': /* POSIX: negate matches */
168 nvflag = 0;
169 break;
170
171 case 'c': /* POSIX: write count */
172 cflag++;
173 break;
174
175 case 'i': /* POSIX: ignore case */
176 iflag++;
177 regflags |= REG_ICASE;
178 break;
179
180 case 'l': /* POSIX: Write filenames only */
181 lflag++;
182 break;
183
184 case 'n': /* POSIX: Write line numbers */
185 nflag++;
245
246 case 'x': /* POSIX: full line matches */
247 xflag++;
248 regflags |= REG_ANCHOR;
249 break;
250
251 case 'E': /* POSIX: Extended RE's */
252 regflags |= REG_EXTENDED;
253 Eflag++;
254 break;
255
256 case 'F': /* POSIX: strings, not RE's */
257 Fflag++;
258 break;
259
260 case 'R': /* Solaris: like rflag, but follow symlinks */
261 Rflag++;
262 rflag++;
263 break;
264
265 default:
266 usage();
267 }
268 }
269 /*
270 * If we're invoked as egrep or fgrep we need to do some checks
271 */
272
273 if (egrep || fgrep) {
274 /*
275 * Use of -E or -F with egrep or fgrep is illegal
276 */
277 if (Eflag || Fflag)
278 usage();
279 /*
280 * Don't allow use of wflag with egrep / fgrep
281 */
282 if (wflag)
283 usage();
284 /*
525 */
526 bufsiz += BUFSIZE;
527 if ((inbuf = realloc(inbuf, bufsiz)) == NULL) {
528 (void) fprintf(stderr,
529 gettext("%s: out of memory\n"),
530 cmdname);
531 exit(2);
532 }
533 bufp = inbuf + bufused;
534 continue;
535 }
536 if (bufp[buflen - 1] == '\n') {
537 bufp[--buflen] = '\0';
538 }
539 addpattern(inbuf);
540
541 bufp = inbuf;
542 bufused = 0;
543 }
544 free(inbuf);
545 (void) fclose(fp);
546 }
547
548 /*
549 * Add a string to the pattern list.
550 */
551 static void
552 addpattern(char *s)
553 {
554 PATTERN *pp;
555 char *wordbuf;
556 char *np;
557
558 for (; ; ) {
559 np = strchr(s, '\n');
560 if (np != NULL)
561 *np = '\0';
562 if ((pp = malloc(sizeof (PATTERN))) == NULL) {
563 (void) fprintf(stderr, gettext(
564 "%s: out of memory\n"),
701 if ((rv = regcomp(&pp->re, pp->pattern, regflags)) != 0) {
702 (void) regerror(rv, &pp->re, errstr, sizeof (errstr));
703 (void) fprintf(stderr,
704 gettext("%s: RE error in %s: %s\n"),
705 cmdname, pp->pattern, errstr);
706 exit(2);
707 }
708 free(pp->pattern);
709 }
710
711 /*
712 * Decide if we are able to run the Boyer-Moore-Gosper algorithm.
713 * Use the Boyer-Moore-Gosper algorithm if:
714 * - fgrep (Fflag)
715 * - singlebyte locale (!mblocale)
716 * - no ignoring case (!iflag)
717 * - no printing line numbers (!nflag)
718 * - no negating the output (nvflag)
719 * - only one pattern (npatterns == 1)
720 * - non zero length pattern (strlen(patterns->pattern) != 0)
721 *
722 * It's guaranteed patterns->pattern is still alive
723 * when Fflag && !mblocale.
724 */
725 use_bmg = Fflag && !mblocale && !iflag && !nflag && nvflag &&
726 (npatterns == 1) && (strlen(patterns->pattern) != 0);
727 }
728
729 /*
730 * Search a newline from the beginning of the string
731 */
732 static char *
733 find_nl(const char *ptr, size_t len)
734 {
735 while (len-- != 0) {
736 if (*ptr++ == '\n') {
737 return ((char *)--ptr);
738 }
739 }
740 return (NULL);
741 }
742
743 /*
744 * Search a newline from the end of the string
745 */
746 static char *
787
788 /*
789 * Do grep on a single file.
790 * Return true in any lines matched.
791 *
792 * We have two strategies:
793 * The fast one is used when we have a single pattern with
794 * a string known to occur in the pattern. We can then
795 * do a BMG match on the whole buffer.
796 * This is an order of magnitude faster.
797 * Otherwise we split the buffer into lines,
798 * and check for a match on each line.
799 */
800 static int
801 grep(int fd, const char *fn)
802 {
803 PATTERN *pp;
804 off_t data_len; /* length of the data chunk */
805 off_t line_len; /* length of the current line */
806 off_t line_offset; /* current line's offset from the beginning */
807 long long lineno;
808 long long matches = 0; /* Number of matching lines */
809 int newlinep; /* 0 if the last line of file has no newline */
810 char *ptr, *ptrend;
811
812
813 if (patterns == NULL)
814 return (0); /* no patterns to match -- just return */
815
816 pp = patterns;
817
818 if (use_bmg) {
819 bmgcomp(pp->pattern, strlen(pp->pattern));
820 }
821
822 if (use_wchar && outline == NULL) {
823 outbuflen = BUFSIZE + 1;
824 outline = malloc(sizeof (wchar_t) * outbuflen);
825 if (outline == NULL) {
826 (void) fprintf(stderr, gettext("%s: out of memory\n"),
827 cmdname);
828 exit(2);
829 }
830 }
831
832 if (prntbuf == NULL) {
833 prntbuflen = BUFSIZE;
834 if ((prntbuf = malloc(prntbuflen + 1)) == NULL) {
835 (void) fprintf(stderr, gettext("%s: out of memory\n"),
836 cmdname);
837 exit(2);
838 }
839 }
840
841 line_offset = 0;
842 lineno = 0;
843 newlinep = 1;
844 data_len = 0;
845 for (; ; ) {
846 long count;
847 off_t offset = 0;
848
849 if (data_len == 0) {
850 /*
851 * If no data in the buffer, reset ptr
852 */
853 ptr = prntbuf;
854 }
855 if (ptr == prntbuf) {
856 /*
857 * The current data chunk starts from prntbuf.
858 * This means either the buffer has no data
859 * or the buffer has no newline.
860 * So, read more data from input.
861 */
862 count = read(fd, ptr + data_len, prntbuflen - data_len);
863 if (count < 0) {
864 /* read error */
865 if (cflag) {
866 if (outfn && !rflag) {
867 (void) fprintf(stdout,
868 "%s:", fn);
869 }
870 if (!qflag && !rflag) {
871 (void) fprintf(stdout, "%lld\n",
872 matches);
873 }
874 }
875 return (0);
876 } else if (count == 0) {
877 /* no new data */
878 if (data_len == 0) {
879 /* end of file already reached */
880 break;
881 }
882 /* last line of file has no newline */
883 ptrend = ptr + data_len;
884 newlinep = 0;
885 goto L_start_process;
886 }
887 offset = data_len;
888 data_len += count;
889 }
890
891 /*
892 * Look for newline in the chunk
893 * between ptr + offset and ptr + data_len - offset.
894 */
895 ptrend = find_nl(ptr + offset, data_len - offset);
896 if (ptrend == NULL) {
897 /* no newline found in this chunk */
898 if (ptr > prntbuf) {
899 /*
900 * Move remaining data to the beginning
901 * of the buffer.
902 * Remaining data lie from ptr for
903 * data_len bytes.
904 */
905 (void) memmove(prntbuf, ptr, data_len);
906 }
907 if (data_len == prntbuflen) {
908 /*
909 * No enough room in the buffer
910 */
911 prntbuflen += BUFSIZE;
912 prntbuf = realloc(prntbuf, prntbuflen + 1);
913 if (prntbuf == NULL) {
914 (void) fprintf(stderr,
915 gettext("%s: out of memory\n"),
916 cmdname);
917 exit(2);
918 }
919 }
920 ptr = prntbuf;
921 /* read the next input */
922 continue;
923 }
924 L_start_process:
925
926 /*
927 * Beginning of the chunk: ptr
928 * End of the chunk: ptr + data_len
929 * Beginning of the line: ptr
1023 "%s: input file \"%s\": line %lld: invalid multibyte character\n"),
1024 cmdname, fn, lineno);
1025 /* never match a line with invalid sequence */
1026 goto L_skip_line;
1027 }
1028 outline[len] = L'\0';
1029
1030 if (iflag) {
1031 wchar_t *cp;
1032 for (cp = outline; *cp != '\0'; cp++) {
1033 *cp = towlower((wint_t)*cp);
1034 }
1035 }
1036
1037 if (xflag) {
1038 for (pp = patterns; pp; pp = pp->next) {
1039 if (outline[0] == pp->wpattern[0] &&
1040 wcscmp(outline,
1041 pp->wpattern) == 0) {
1042 /* matched */
1043 break;
1044 }
1045 }
1046 } else {
1047 for (pp = patterns; pp; pp = pp->next) {
1048 if (wcswcs(outline, pp->wpattern)
1049 != NULL) {
1050 /* matched */
1051 break;
1052 }
1053 }
1054 }
1055 } else if (Fflag) {
1056 /* fgrep in byte-oriented handling */
1057 char *fptr;
1058 if (iflag) {
1059 fptr = istrdup(ptr);
1060 } else {
1061 fptr = ptr;
1062 }
1063 if (xflag) {
1064 /* fgrep -x */
1065 for (pp = patterns; pp; pp = pp->next) {
1066 if (fptr[0] == pp->pattern[0] &&
1067 strcmp(fptr, pp->pattern) == 0) {
1068 /* matched */
1069 break;
1070 }
1071 }
1072 } else {
1073 for (pp = patterns; pp; pp = pp->next) {
1074 if (strstr(fptr, pp->pattern) != NULL) {
1075 /* matched */
1076 break;
1077 }
1078 }
1079 }
1080 } else {
1081 /* grep or egrep */
1082 for (pp = patterns; pp; pp = pp->next) {
1083 int rv;
1084
1085 rv = regexec(&pp->re, ptr, 0, NULL, 0);
1086 if (rv == REG_OK) {
1087 /* matched */
1088 break;
1089 }
1090
1091 switch (rv) {
1092 case REG_NOMATCH:
1093 break;
1094 case REG_ECHAR:
1095 (void) fprintf(stderr, gettext(
1096 "%s: input file \"%s\": line %lld: invalid multibyte character\n"),
1097 cmdname, fn, lineno);
1098 break;
1099 default:
1100 (void) regerror(rv, &pp->re, errstr,
1101 sizeof (errstr));
1102 (void) fprintf(stderr, gettext(
1103 "%s: input file \"%s\": line %lld: %s\n"),
1104 cmdname, fn, lineno, errstr);
1105 exit(2);
1106 }
1107 }
1108 }
1109
1110 L_next_line:
1111 /*
1112 * Here, if pp points to non-NULL, something has been matched
1113 * to the pattern.
1114 */
1115 if (nvflag == (pp != NULL)) {
1116 matches++;
1117 /*
1118 * Handle q, l, and c flags.
1119 */
1120 if (qflag) {
1121 /* no need to continue */
1122 /*
1123 * End of this line is ptrend.
1124 * We have read up to ptr + data_len.
1125 */
1126 off_t pos;
1127 pos = ptr + data_len - (ptrend + 1);
1128 (void) lseek(fd, -pos, SEEK_CUR);
1129 exit(0);
1130 }
1131 if (lflag) {
1132 (void) printf("%s\n", fn);
1133 break;
1134 }
1135 if (!cflag) {
1136 if (Hflag || outfn) {
1137 (void) printf("%s:", fn);
1138 }
1139 if (bflag) {
1140 (void) printf("%lld:", (offset_t)
1141 (line_offset / BSIZE));
1142 }
1143 if (nflag) {
1144 (void) printf("%lld:", lineno);
1145 }
1146 *ptrend = '\n';
1147 (void) fwrite(ptr, 1, line_len + 1, stdout);
1148 }
1149 if (ferror(stdout)) {
1150 return (0);
1151 }
1152 }
1153 L_skip_line:
1154 if (!newlinep)
1155 break;
1156
1157 data_len -= line_len + 1;
1158 line_offset += line_len + 1;
1159 ptr = ptrend + 1;
1160 }
1161
1162 if (cflag) {
1163 if (Hflag || outfn) {
1164 (void) printf("%s:", fn);
1165 }
1166 if (!qflag) {
1167 (void) printf("%lld\n", matches);
1168 }
1169 }
1170 return (matches != 0);
1171 }
1172
1173 /*
1174 * usage message for grep
1175 */
1176 static void
1177 usage(void)
1178 {
1179 if (egrep || fgrep) {
1180 (void) fprintf(stderr, gettext("Usage:\t%s"), cmdname);
1181 (void) fprintf(stderr,
1182 gettext(" [-c|-l|-q] [-r|-R] [-bhHinsvx] "
1183 "pattern_list [file ...]\n"));
1184
1185 (void) fprintf(stderr, "\t%s", cmdname);
1186 (void) fprintf(stderr,
1187 gettext(" [-c|-l|-q] [-r|-R] [-bhHinsvx] "
1188 "[-e pattern_list]... "
1189 "[-f pattern_file]... [file...]\n"));
1190 } else {
1191 (void) fprintf(stderr, gettext("Usage:\t%s"), cmdname);
1192 (void) fprintf(stderr,
1193 gettext(" [-c|-l|-q] [-r|-R] [-bhHinsvwx] "
1194 "pattern_list [file ...]\n"));
1195
1196 (void) fprintf(stderr, "\t%s", cmdname);
1197 (void) fprintf(stderr,
1198 gettext(" [-c|-l|-q] [-r|-R] [-bhHinsvwx] "
1199 "[-e pattern_list]... "
1200 "[-f pattern_file]... [file...]\n"));
1201
1202 (void) fprintf(stderr, "\t%s", cmdname);
1203 (void) fprintf(stderr,
1204 gettext(" -E [-c|-l|-q] [-r|-R] [-bhHinsvx] "
1205 "pattern_list [file ...]\n"));
1206
1207 (void) fprintf(stderr, "\t%s", cmdname);
1208 (void) fprintf(stderr,
1209 gettext(" -E [-c|-l|-q] [-r|-R] [-bhHinsvx] "
1210 "[-e pattern_list]... "
1211 "[-f pattern_file]... [file...]\n"));
1212
1213 (void) fprintf(stderr, "\t%s", cmdname);
1214 (void) fprintf(stderr,
1215 gettext(" -F [-c|-l|-q] [-r|-R] [-bhHinsvx] "
1216 "pattern_list [file ...]\n"));
1217
1218 (void) fprintf(stderr, "\t%s", cmdname);
1219 (void) fprintf(stderr,
1220 gettext(" -F [-c|-l|-q] [-bhHinsvx] [-e pattern_list]... "
1221 "[-f pattern_file]... [file...]\n"));
1222 }
1223 exit(2);
1224 /* NOTREACHED */
1225 }
1226
1227 /*
1228 * Compile literal pattern into BMG tables
1229 */
1230 static void
1231 bmgcomp(char *pat, int len)
1232 {
1233 int i;
1234 int tlen;
1235 unsigned char *uc = (unsigned char *)pat;
1236
1237 bmglen = len;
1238 bmgpat = pat;
1239
1240 for (i = 0; i < M_CSETSIZE; i++) {
|
47 #include <regex.h>
48 #include <limits.h>
49 #include <sys/types.h>
50 #include <sys/stat.h>
51 #include <fcntl.h>
52 #include <stdio.h>
53 #include <locale.h>
54 #include <wchar.h>
55 #include <errno.h>
56 #include <unistd.h>
57 #include <wctype.h>
58 #include <ftw.h>
59 #include <sys/param.h>
60
61 #define STDIN_FILENAME gettext("(standard input)")
62
63 #define BSIZE 512 /* Size of block for -b */
64 #define BUFSIZE 8192 /* Input buffer size */
65 #define MAX_DEPTH 1000 /* how deep to recurse */
66
67 #define AFTER 1 /* 'After' Context */
68 #define BEFORE 2 /* 'Before' Context */
69 #define CONTEXT (AFTER|BEFORE) /* Full Context */
70
71 #define M_CSETSIZE 256 /* singlebyte chars */
72 static int bmglen; /* length of BMG pattern */
73 static char *bmgpat; /* BMG pattern */
74 static int bmgtab[M_CSETSIZE]; /* BMG delta1 table */
75
76 typedef struct _PATTERN {
77 char *pattern; /* original pattern */
78 wchar_t *wpattern; /* wide, lowercased pattern */
79 struct _PATTERN *next;
80 regex_t re; /* compiled pattern */
81 } PATTERN;
82
83 static PATTERN *patterns;
84 static char errstr[128]; /* regerror string buffer */
85 static int regflags = 0; /* regcomp options */
86 static int matched = 0; /* return of the grep() */
87 static int errors = 0; /* count of errors */
88 static uchar_t fgrep = 0; /* Invoked as fgrep */
89 static uchar_t egrep = 0; /* Invoked as egrep */
90 static uchar_t nvflag = 1; /* Print matching lines */
91 static uchar_t cflag; /* Count of matches */
92 static uchar_t iflag; /* Case insensitve matching */
93 static uchar_t Hflag; /* Precede lines by file name */
94 static uchar_t hflag; /* Supress printing of filename */
95 static uchar_t lflag; /* Print file names of matches */
96 static uchar_t nflag; /* Precede lines by line number */
97 static uchar_t rflag; /* Search directories recursively */
98 static uchar_t bflag; /* Preccede matches by block number */
99 static uchar_t sflag; /* Suppress file error messages */
100 static uchar_t qflag; /* Suppress standard output */
101 static uchar_t wflag; /* Search for expression as a word */
102 static uchar_t xflag; /* Anchoring */
103 static uchar_t Eflag; /* Egrep or -E flag */
104 static uchar_t Fflag; /* Fgrep or -F flag */
105 static uchar_t Rflag; /* Like rflag, but follow symlinks */
106 static uchar_t outfn; /* Put out file name */
107 static uchar_t conflag; /* show context of matches */
108 static char *cmdname;
109
110 static int use_wchar, use_bmg, mblocale;
111
112 static size_t outbuflen, prntbuflen, conbuflen;
113 static unsigned long conalen, conblen, conmatches;
114 static char *prntbuf, *conbuf;
115 static wchar_t *outline;
116
117 static void addfile(const char *fn);
118 static void addpattern(char *s);
119 static void fixpatterns(void);
120 static void usage(void);
121 static int grep(int, const char *);
122 static void bmgcomp(char *, int);
123 static char *bmgexec(char *, char *);
124 static int recursive(const char *, const struct stat *, int, struct FTW *);
125 static void process_path(const char *);
126 static void process_file(const char *, int);
127
128 /*
129 * mainline for grep
130 */
131 int
132 main(int argc, char **argv)
133 {
134 char *ap, *test;
135 int c;
136 int fflag = 0;
137 int i, n_pattern = 0, n_file = 0;
138 char **pattern_list = NULL;
139 char **file_list = NULL;
140
141 (void) setlocale(LC_ALL, "");
142 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
143 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
144 #endif
145 (void) textdomain(TEXT_DOMAIN);
146
147 /*
148 * true if this is running on the multibyte locale
149 */
150 mblocale = (MB_CUR_MAX > 1);
151 /*
152 * Skip leading slashes
153 */
154 cmdname = argv[0];
155 if (ap = strrchr(cmdname, '/'))
156 cmdname = ap + 1;
157
158 ap = cmdname;
159 /*
160 * Detect egrep/fgrep via command name, map to -E and -F options.
161 */
162 if (*ap == 'e' || *ap == 'E') {
163 regflags |= REG_EXTENDED;
164 egrep++;
165 } else {
166 if (*ap == 'f' || *ap == 'F') {
167 fgrep++;
168 }
169 }
170
171 /* check for non-standard "-line-count" option */
172 for (i = 1; i < argc; i++) {
173 if (strcmp(argv[i], "--") == 0)
174 break;
175
176 if ((argv[i][0] == '-') && isdigit(argv[i][1])) {
177 if (strlen(&argv[i][1]) !=
178 strspn(&argv[i][1], "0123456789")) {
179 (void) fprintf(stderr, gettext(
180 "%s: Bad number flag\n"), argv[0]);
181 usage();
182 }
183
184 conalen = conblen = strtoul(&argv[i][1], (char **)NULL,
185 10);
186
187 /* isdigit() check prevents negative arguments */
188 if (conalen >= ULONG_MAX) {
189 (void) fprintf(stderr, gettext(
190 "%s: Bad context argument\n"), argv[0]);
191 }
192
193 if (conalen)
194 conflag = CONTEXT;
195
196 while (i < argc) {
197 argv[i] = argv[i + 1];
198 i++;
199 }
200 argc--;
201 }
202 }
203
204 while ((c = getopt(argc, argv, "vwchHilnrbse:f:qxEFIRA:B:C:")) != EOF) {
205 unsigned long tval;
206 switch (c) {
207 case 'v': /* POSIX: negate matches */
208 nvflag = 0;
209 break;
210
211 case 'c': /* POSIX: write count */
212 cflag++;
213 break;
214
215 case 'i': /* POSIX: ignore case */
216 iflag++;
217 regflags |= REG_ICASE;
218 break;
219
220 case 'l': /* POSIX: Write filenames only */
221 lflag++;
222 break;
223
224 case 'n': /* POSIX: Write line numbers */
225 nflag++;
285
286 case 'x': /* POSIX: full line matches */
287 xflag++;
288 regflags |= REG_ANCHOR;
289 break;
290
291 case 'E': /* POSIX: Extended RE's */
292 regflags |= REG_EXTENDED;
293 Eflag++;
294 break;
295
296 case 'F': /* POSIX: strings, not RE's */
297 Fflag++;
298 break;
299
300 case 'R': /* Solaris: like rflag, but follow symlinks */
301 Rflag++;
302 rflag++;
303 break;
304
305 case 'A': /* print N lines after each match */
306 conalen = strtoul(optarg, &test, 10);
307 /* *test will be non-null if optarg is negative */
308 if (*test != '\0' || conalen >= ULONG_MAX) {
309 (void) fprintf(stderr, gettext(
310 "%s: Bad context argument\n"), argv[0]);
311 exit(2);
312 }
313 if (conalen)
314 conflag |= AFTER;
315 else
316 conflag &= ~AFTER;
317 break;
318 case 'B': /* print N lines before each match */
319 conblen = strtoul(optarg, &test, 10);
320 /* *test will be non-null if optarg is negative */
321 if (*test != '\0' || conblen >= ULONG_MAX) {
322 (void) fprintf(stderr, gettext(
323 "%s: Bad context argument\n"), argv[0]);
324 exit(2);
325 }
326 if (conblen)
327 conflag |= BEFORE;
328 else
329 conflag &= ~BEFORE;
330 break;
331 case 'C': /* print N lines around each match */
332 tval = strtoul(optarg, &test, 10);
333 /* *test will be non-null if optarg is negative */
334 if (*test != '\0' || tval >= ULONG_MAX) {
335 (void) fprintf(stderr, gettext(
336 "%s: Bad context argument\n"), argv[0]);
337 exit(2);
338 }
339 if (tval) {
340 if (!(conflag & BEFORE))
341 conblen = tval;
342 if (!(conflag & AFTER))
343 conalen = tval;
344 conflag = CONTEXT;
345 }
346 break;
347
348 default:
349 usage();
350 }
351 }
352 /*
353 * If we're invoked as egrep or fgrep we need to do some checks
354 */
355
356 if (egrep || fgrep) {
357 /*
358 * Use of -E or -F with egrep or fgrep is illegal
359 */
360 if (Eflag || Fflag)
361 usage();
362 /*
363 * Don't allow use of wflag with egrep / fgrep
364 */
365 if (wflag)
366 usage();
367 /*
608 */
609 bufsiz += BUFSIZE;
610 if ((inbuf = realloc(inbuf, bufsiz)) == NULL) {
611 (void) fprintf(stderr,
612 gettext("%s: out of memory\n"),
613 cmdname);
614 exit(2);
615 }
616 bufp = inbuf + bufused;
617 continue;
618 }
619 if (bufp[buflen - 1] == '\n') {
620 bufp[--buflen] = '\0';
621 }
622 addpattern(inbuf);
623
624 bufp = inbuf;
625 bufused = 0;
626 }
627 free(inbuf);
628 free(prntbuf);
629 free(conbuf);
630 (void) fclose(fp);
631 }
632
633 /*
634 * Add a string to the pattern list.
635 */
636 static void
637 addpattern(char *s)
638 {
639 PATTERN *pp;
640 char *wordbuf;
641 char *np;
642
643 for (; ; ) {
644 np = strchr(s, '\n');
645 if (np != NULL)
646 *np = '\0';
647 if ((pp = malloc(sizeof (PATTERN))) == NULL) {
648 (void) fprintf(stderr, gettext(
649 "%s: out of memory\n"),
786 if ((rv = regcomp(&pp->re, pp->pattern, regflags)) != 0) {
787 (void) regerror(rv, &pp->re, errstr, sizeof (errstr));
788 (void) fprintf(stderr,
789 gettext("%s: RE error in %s: %s\n"),
790 cmdname, pp->pattern, errstr);
791 exit(2);
792 }
793 free(pp->pattern);
794 }
795
796 /*
797 * Decide if we are able to run the Boyer-Moore-Gosper algorithm.
798 * Use the Boyer-Moore-Gosper algorithm if:
799 * - fgrep (Fflag)
800 * - singlebyte locale (!mblocale)
801 * - no ignoring case (!iflag)
802 * - no printing line numbers (!nflag)
803 * - no negating the output (nvflag)
804 * - only one pattern (npatterns == 1)
805 * - non zero length pattern (strlen(patterns->pattern) != 0)
806 * - no context required (!conflag)
807 *
808 * It's guaranteed patterns->pattern is still alive
809 * when Fflag && !mblocale.
810 */
811 use_bmg = Fflag && !mblocale && !iflag && !nflag && nvflag &&
812 (npatterns == 1) && (strlen(patterns->pattern) != 0) && !conflag;
813 }
814
815 /*
816 * Search a newline from the beginning of the string
817 */
818 static char *
819 find_nl(const char *ptr, size_t len)
820 {
821 while (len-- != 0) {
822 if (*ptr++ == '\n') {
823 return ((char *)--ptr);
824 }
825 }
826 return (NULL);
827 }
828
829 /*
830 * Search a newline from the end of the string
831 */
832 static char *
873
874 /*
875 * Do grep on a single file.
876 * Return true in any lines matched.
877 *
878 * We have two strategies:
879 * The fast one is used when we have a single pattern with
880 * a string known to occur in the pattern. We can then
881 * do a BMG match on the whole buffer.
882 * This is an order of magnitude faster.
883 * Otherwise we split the buffer into lines,
884 * and check for a match on each line.
885 */
886 static int
887 grep(int fd, const char *fn)
888 {
889 PATTERN *pp;
890 off_t data_len; /* length of the data chunk */
891 off_t line_len; /* length of the current line */
892 off_t line_offset; /* current line's offset from the beginning */
893 off_t blkoffset; /* line_offset but context-compatible */
894 long long lineno, linenum;
895 long long matches = 0; /* Number of matching lines */
896 long long conacnt = 0, conbcnt = 0; /* context line count */
897 int newlinep; /* 0 if the last line of file has no newline */
898 char *ptr, *ptrend, *prntptr, *prntptrend;
899 char *nextptr = NULL, *nextend = NULL;
900 char *conptr = NULL, *conptrend = NULL;
901 char *matchptr = NULL;
902 int conaprnt = 0, conbprnt = 0, lastmatch = 0;
903 int nearmatch = conmatches ? 1 : 0; /* w/in N+1 of last match */
904 size_t prntlen;
905
906 if (patterns == NULL)
907 return (0); /* no patterns to match -- just return */
908
909 pp = patterns;
910
911 if (use_bmg) {
912 bmgcomp(pp->pattern, strlen(pp->pattern));
913 }
914
915 if (use_wchar && outline == NULL) {
916 outbuflen = BUFSIZE + 1;
917 outline = malloc(sizeof (wchar_t) * outbuflen);
918 if (outline == NULL) {
919 (void) fprintf(stderr, gettext("%s: out of memory\n"),
920 cmdname);
921 exit(2);
922 }
923 }
924
925 if (prntbuf == NULL) {
926 prntbuflen = BUFSIZE;
927 if ((prntbuf = malloc(prntbuflen + 1)) == NULL) {
928 (void) fprintf(stderr, gettext("%s: out of memory\n"),
929 cmdname);
930 exit(2);
931 }
932 }
933
934 if (conflag && (conbuf == NULL)) {
935 conbuflen = BUFSIZE;
936 if ((conbuf = malloc(BUFSIZE+1)) == NULL) {
937 (void) fprintf(stderr, gettext("%s: out of memory\n"),
938 cmdname);
939 exit(2);
940 }
941 }
942
943 blkoffset = line_offset = 0;
944 lineno = 0;
945 linenum = 1;
946 newlinep = 1;
947 data_len = 0;
948 for (; ; ) {
949 long count;
950 off_t offset = 0;
951 int eof = 0, rv = REG_NOMATCH;
952 char separate;
953
954 if (data_len == 0) {
955 /*
956 * If no data in the buffer, reset ptr
957 */
958 ptr = prntbuf;
959 if (conptr == NULL)
960 conptrend = conptr = conbuf;
961 }
962 if (ptr == prntbuf) {
963 /*
964 * The current data chunk starts from prntbuf.
965 * This means either the buffer has no data
966 * or the buffer has no newline.
967 * So, read more data from input.
968 */
969 count = read(fd, ptr + data_len, prntbuflen - data_len);
970 if (count < 0) {
971 /* read error */
972 if (cflag) {
973 if (outfn && !rflag) {
974 (void) fprintf(stdout,
975 "%s:", fn);
976 }
977 if (!qflag && !rflag) {
978 (void) fprintf(stdout, "%lld\n",
979 matches);
980 }
981 }
982 return (0);
983 } else if (count == 0) {
984 /* no new data */
985 eof = 1;
986
987 /* we never want to match EOF */
988 pp = (PATTERN *) !nvflag;
989
990 if (data_len == 0) {
991 /* end of file already reached */
992 if (conflag) {
993 *conptrend = '\n';
994 goto L_next_line;
995 } else {
996 goto out;
997 }
998 }
999 /* last line of file has no newline */
1000 ptrend = ptr + data_len;
1001 newlinep = 0;
1002 goto L_start_process;
1003 }
1004 offset = data_len;
1005 data_len += count;
1006 }
1007
1008 /*
1009 * Look for newline in the chunk
1010 * between ptr + offset and ptr + data_len - offset.
1011 */
1012 ptrend = find_nl(ptr + offset, data_len - offset);
1013 if (ptrend == NULL) {
1014 /* no newline found in this chunk */
1015 if (ptr > prntbuf) {
1016 /*
1017 * Move remaining data to the beginning
1018 * of the buffer.
1019 * Remaining data lie from ptr for
1020 * data_len bytes.
1021 */
1022 (void) memmove(prntbuf, ptr, data_len);
1023 }
1024 if (data_len == prntbuflen) {
1025 /*
1026 * Not enough room in the buffer
1027 */
1028 prntbuflen += BUFSIZE;
1029 prntbuf = realloc(prntbuf, prntbuflen + 1);
1030 if (prntbuf == NULL) {
1031 (void) fprintf(stderr,
1032 gettext("%s: out of memory\n"),
1033 cmdname);
1034 exit(2);
1035 }
1036 }
1037 ptr = prntbuf;
1038 /* read the next input */
1039 continue;
1040 }
1041 L_start_process:
1042
1043 /*
1044 * Beginning of the chunk: ptr
1045 * End of the chunk: ptr + data_len
1046 * Beginning of the line: ptr
1140 "%s: input file \"%s\": line %lld: invalid multibyte character\n"),
1141 cmdname, fn, lineno);
1142 /* never match a line with invalid sequence */
1143 goto L_skip_line;
1144 }
1145 outline[len] = L'\0';
1146
1147 if (iflag) {
1148 wchar_t *cp;
1149 for (cp = outline; *cp != '\0'; cp++) {
1150 *cp = towlower((wint_t)*cp);
1151 }
1152 }
1153
1154 if (xflag) {
1155 for (pp = patterns; pp; pp = pp->next) {
1156 if (outline[0] == pp->wpattern[0] &&
1157 wcscmp(outline,
1158 pp->wpattern) == 0) {
1159 /* matched */
1160 rv = REG_OK;
1161 break;
1162 }
1163 }
1164 } else {
1165 for (pp = patterns; pp; pp = pp->next) {
1166 if (wcswcs(outline, pp->wpattern)
1167 != NULL) {
1168 /* matched */
1169 rv = REG_OK;
1170 break;
1171 }
1172 }
1173 }
1174 } else if (Fflag) {
1175 /* fgrep in byte-oriented handling */
1176 char *fptr;
1177 if (iflag) {
1178 fptr = istrdup(ptr);
1179 } else {
1180 fptr = ptr;
1181 }
1182 if (xflag) {
1183 /* fgrep -x */
1184 for (pp = patterns; pp; pp = pp->next) {
1185 if (fptr[0] == pp->pattern[0] &&
1186 strcmp(fptr, pp->pattern) == 0) {
1187 /* matched */
1188 rv = REG_OK;
1189 break;
1190 }
1191 }
1192 } else {
1193 for (pp = patterns; pp; pp = pp->next) {
1194 if (strstr(fptr, pp->pattern) != NULL) {
1195 /* matched */
1196 rv = REG_OK;
1197 break;
1198 }
1199 }
1200 }
1201 } else {
1202 /* grep or egrep */
1203 for (pp = patterns; pp; pp = pp->next) {
1204 rv = regexec(&pp->re, ptr, 0, NULL, 0);
1205 if (rv == REG_OK) {
1206 /* matched */
1207 break;
1208 }
1209
1210 switch (rv) {
1211 case REG_NOMATCH:
1212 break;
1213 case REG_ECHAR:
1214 (void) fprintf(stderr, gettext(
1215 "%s: input file \"%s\": line %lld: invalid multibyte character\n"),
1216 cmdname, fn, lineno);
1217 break;
1218 default:
1219 (void) regerror(rv, &pp->re, errstr,
1220 sizeof (errstr));
1221 (void) fprintf(stderr, gettext(
1222 "%s: input file \"%s\": line %lld: %s\n"),
1223 cmdname, fn, lineno, errstr);
1224 exit(2);
1225 }
1226 }
1227 }
1228
1229 /*
1230 * Context is set up as follows:
1231 * For a 'Before' context, we maintain a set of pointers
1232 * containing 'N' lines of context. If the current number of
1233 * lines contained is greater than N, and N isn't a match, the
1234 * start pointer is moved forward to the next newline.
1235 *
1236 * If we ever find a match, we print out immediately.
1237 * 'nearmatch' tells us if we're within N+1 lines of the last
1238 * match ; if we are, and we find another match, we don't
1239 * separate the matches. 'nearmatch' becomes false when
1240 * a line gets rotated out of the context.
1241 *
1242 * For an 'After' context, we simply wait until we've found a
1243 * match, then create a context N+1 lines big. If we don't find
1244 * a match within the context, we print out the current context.
1245 * Otherwise, we save a reference to the new matching line,
1246 * print out the other context, and reset our context pointers
1247 * to the new matching line.
1248 *
1249 * 'nearmatch' becomes false when we find a non-matching line
1250 * that isn't a part of any context.
1251 *
1252 * A full-context is implemented as a combination of the
1253 * 'Before' and 'After' context logic. Before we find a match,
1254 * we follow the Before logic. When we find a match, we
1255 * follow the After logic. 'nearmatch' is handled by the Before
1256 * logic.
1257 */
1258
1259 if (!conflag)
1260 goto L_next_line;
1261
1262 if (line_len + (conptrend - conbuf) > conbuflen) {
1263 char *oldconbuf = conbuf;
1264 char *oldconptr = conptr;
1265 long tmp = matchptr - conptr;
1266
1267 conbuflen += BUFSIZE;
1268 conbuf = realloc(conbuf, conbuflen + 1);
1269 if (conbuf == NULL) {
1270 (void) fprintf(stderr,
1271 gettext("%s: out of memory\n"),
1272 cmdname);
1273 exit(2);
1274 }
1275
1276 conptr = conbuf + (conptr - oldconbuf);
1277 conptrend = conptr + (conptrend - oldconptr);
1278 if (matchptr)
1279 matchptr = conptr + tmp;
1280 }
1281 (void) memcpy((conptrend > conptr) ?
1282 conptrend + 1 : conptrend, ptr, line_len);
1283 conptrend += line_len + (conptrend > conptr);
1284 *conptrend = '\n';
1285
1286 if (!nvflag == rv) {
1287 /* matched */
1288 if (lastmatch) {
1289 if (conflag & AFTER) {
1290 conaprnt = 1;
1291 nextend = conptrend;
1292 conptrend = conptr + lastmatch;
1293 nextptr = conptrend + 1;
1294 *nextend = '\n';
1295 }
1296 } else {
1297 if (conflag == AFTER) {
1298 conptr = conptrend - (line_len);
1299 linenum = lineno;
1300 blkoffset = line_offset;
1301 }
1302 blkoffset = line_offset -
1303 (conptrend - conptr - line_len);
1304 }
1305
1306 if (conflag == BEFORE)
1307 conbprnt = 1;
1308
1309 lastmatch = conptrend - conptr;
1310 goto L_next_line;
1311 }
1312
1313 if (!lastmatch) {
1314 if (conflag & BEFORE) {
1315 if (conbcnt >= conblen) {
1316 char *tmp = conptr;
1317 conptr = find_nl(conptr,
1318 conptrend - conptr) + 1;
1319 if (bflag)
1320 blkoffset += conptr - tmp;
1321 linenum++;
1322 nearmatch = 1;
1323 } else {
1324 conbcnt++;
1325 }
1326 }
1327 if (conflag == AFTER)
1328 nearmatch = 1;
1329 } else {
1330 if (++conacnt >= conalen && !conaprnt && conalen)
1331 conaprnt = 1;
1332 else
1333 lastmatch = conptrend - conptr;
1334 }
1335
1336 L_next_line:
1337 /*
1338 * Here, if pp points to non-NULL, something has been matched
1339 * to the pattern.
1340 */
1341 if (nvflag == (pp != NULL)) {
1342 matches++;
1343 if (!nextend)
1344 matchptr = conflag ? conptrend : ptrend;
1345 }
1346
1347 /*
1348 * Set up some print context so that we can treat
1349 * single-line matches as a zero-N context.
1350 * Apply CLI flags to each line of the context.
1351 *
1352 * For context, we only print if we both have a match and are
1353 * either at the end of the data stream, or we've previously
1354 * declared that we want to print for a particular context.
1355 */
1356 if (lastmatch && (eof || conaprnt || conbprnt)) {
1357
1358 /*
1359 * We'd normally do this earlier, but we had to
1360 * escape early because we reached the end of the data.
1361 */
1362 if (eof && nextptr)
1363 conptrend = nextend;
1364
1365 prntlen = conptrend - conptr + 1;
1366 prntptrend = prntptr = conptr;
1367 if (conmatches++ && nearmatch && !cflag)
1368 (void) fwrite("--\n", 1, 3, stdout);
1369 } else if (!conflag && nvflag == (pp != NULL)) {
1370 *ptrend = '\n';
1371 prntlen = line_len + 1;
1372 prntptrend = prntptr = ptr;
1373 linenum = lineno;
1374 blkoffset = line_offset;
1375 } else if (eof) {
1376 /* No match and no more data */
1377 goto out;
1378 } else {
1379 /* No match, or we're not done building context */
1380 goto L_skip_line;
1381 }
1382
1383 while ((prntptrend = find_nl(prntptrend+1, prntlen)) != NULL) {
1384
1385 /*
1386 * GNU grep uses '-' for context lines and ':' for
1387 * matching lines, so replicate that here.
1388 */
1389 if (prntptrend == matchptr) {
1390 if (eof && nextptr) {
1391 matchptr = nextend;
1392 nextptr = NULL;
1393 } else {
1394 matchptr = NULL;
1395 }
1396 separate = ':';
1397 } else {
1398 separate = '-';
1399 }
1400
1401 /*
1402 * Handle q, l, and c flags.
1403 */
1404 if (qflag) {
1405 /* no need to continue */
1406 /*
1407 * End of this line is ptrend.
1408 * We have read up to ptr + data_len.
1409 */
1410 off_t pos;
1411 pos = ptr + data_len - (ptrend + 1);
1412 (void) lseek(fd, -pos, SEEK_CUR);
1413 exit(0);
1414 }
1415 if (lflag) {
1416 (void) printf("%s\n", fn);
1417 goto out;
1418 }
1419 if (!cflag) {
1420 if (Hflag || outfn) {
1421 (void) printf("%s%c", fn, separate);
1422 }
1423 if (bflag) {
1424 (void) printf("%lld%c", (offset_t)
1425 (blkoffset / BSIZE), separate);
1426 }
1427 if (nflag) {
1428 (void) printf("%lld%c", linenum,
1429 separate);
1430 }
1431 (void) fwrite(prntptr, 1,
1432 prntptrend - prntptr + 1, stdout);
1433 }
1434 if (ferror(stdout)) {
1435 return (0);
1436 }
1437 linenum++;
1438 prntlen -= prntptrend - prntptr + 1;
1439 blkoffset += prntptrend - prntptr + 1;
1440 prntptr = prntptrend + 1;
1441 }
1442
1443 if (eof)
1444 goto out;
1445
1446 /*
1447 * Update context buffer and variables post-print
1448 */
1449 if (conflag) {
1450 conptr = conbuf;
1451 conaprnt = conbprnt = 0;
1452 nearmatch = 0;
1453 conacnt = conbcnt = 0;
1454
1455 if (nextptr) {
1456 (void) memmove(conbuf, nextptr,
1457 nextend - nextptr + 1);
1458 blkoffset += nextptr - conptrend - 1;
1459 conptrend = conptr + (nextend - nextptr);
1460 matchptr = conptrend;
1461 linenum = lineno;
1462 lastmatch = conptrend - conptr;
1463 } else {
1464 conptrend = conptr;
1465 conacnt = 0;
1466 lastmatch = 0;
1467 }
1468 nextptr = nextend = NULL;
1469 }
1470
1471 L_skip_line:
1472 if (!newlinep)
1473 break;
1474
1475 data_len -= line_len + 1;
1476 line_offset += line_len + 1;
1477 ptr = ptrend + 1;
1478 }
1479
1480 out:
1481 if (cflag) {
1482 if (Hflag || outfn) {
1483 (void) printf("%s:", fn);
1484 }
1485 if (!qflag) {
1486 (void) printf("%lld\n", matches);
1487 }
1488 }
1489 return (matches != 0);
1490 }
1491
1492 /*
1493 * usage message for grep
1494 */
1495 static void
1496 usage(void)
1497 {
1498 if (egrep || fgrep) {
1499 (void) fprintf(stderr, gettext("Usage:\t%s"), cmdname);
1500 (void) fprintf(stderr,
1501 gettext(" [-c|-l|-q] [-r|-R] [-A #|-B #|-C #|-#] "
1502 "[-bhHinsvx] pattern_list [file ...]\n"));
1503
1504 (void) fprintf(stderr, "\t%s", cmdname);
1505 (void) fprintf(stderr,
1506 gettext(" [-c|-l|-q] [-r|-R] [-A #|-B #|-C #|-#] "
1507 "[-bhHinsvx] [-e pattern_list]... "
1508 "[-f pattern_file]... [file...]\n"));
1509 } else {
1510 (void) fprintf(stderr, gettext("Usage:\t%s"), cmdname);
1511 (void) fprintf(stderr,
1512 gettext(" [-c|-l|-q] [-r|-R] [-A #|-B #|-C #|-#] "
1513 "[-bhHinsvx] pattern_list [file ...]\n"));
1514
1515 (void) fprintf(stderr, "\t%s", cmdname);
1516 (void) fprintf(stderr,
1517 gettext(" [-c|-l|-q] [-r|-R] [-A #|-B #|-C #|-#] "
1518 "[-bhHinsvx] [-e pattern_list]... "
1519 "[-f pattern_file]... [file...]\n"));
1520
1521 (void) fprintf(stderr, "\t%s", cmdname);
1522 (void) fprintf(stderr,
1523 gettext(" -E [-c|-l|-q] [-r|-R] [-A #|-B #|-C #|-#] "
1524 "[-bhHinsvx] pattern_list [file ...]\n"));
1525
1526 (void) fprintf(stderr, "\t%s", cmdname);
1527 (void) fprintf(stderr,
1528 gettext(" -E [-c|-l|-q] [-r|-R] [-A #|-B #|-C #|-#] "
1529 "[-bhHinsvx] [-e pattern_list]... "
1530 "[-f pattern_file]... [file...]\n"));
1531
1532 (void) fprintf(stderr, "\t%s", cmdname);
1533 (void) fprintf(stderr,
1534 gettext(" -F [-c|-l|-q] [-r|-R] [-A #|-B #|-C #|-#] "
1535 "[-bhHinsvx] pattern_list [file ...]\n"));
1536
1537 (void) fprintf(stderr, "\t%s", cmdname);
1538 (void) fprintf(stderr,
1539 gettext(" -F [-c|-l|-q] [-A #|-B #|-C #|-#] "
1540 "[-bhHinsvx] [-e pattern_list]... "
1541 "[-f pattern_file]... [file...]\n"));
1542 }
1543 exit(2);
1544 /* NOTREACHED */
1545 }
1546
1547 /*
1548 * Compile literal pattern into BMG tables
1549 */
1550 static void
1551 bmgcomp(char *pat, int len)
1552 {
1553 int i;
1554 int tlen;
1555 unsigned char *uc = (unsigned char *)pat;
1556
1557 bmglen = len;
1558 bmgpat = pat;
1559
1560 for (i = 0; i < M_CSETSIZE; i++) {
|