4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
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.
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]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * grep - pattern matching program - combined grep, egrep, and fgrep.
29 * Based on MKS grep command, with XCU & Solaris mods.
33 * Copyright 1985, 1992 by Mortice Kern Systems Inc. All rights reserved.
37 /* Copyright 2012 Nexenta Systems, Inc. All rights reserved. */
40 * Copyright 2013 Damian Bogel. All rights reserved.
49 #include <sys/types.h>
59 #include <sys/param.h>
61 #define STDIN_FILENAME gettext("(standard input)")
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 */
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 */
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 */
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
;
105 static int use_wchar
, use_bmg
, mblocale
;
107 static size_t outbuflen
, prntbuflen
;
108 static char *prntbuf
;
109 static wchar_t *outline
;
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);
126 main(int argc
, char **argv
)
131 int i
, n_pattern
= 0, n_file
= 0;
132 char **pattern_list
= NULL
;
133 char **file_list
= NULL
;
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 */
139 (void) textdomain(TEXT_DOMAIN
);
142 * true if this is running on the multibyte locale
144 mblocale
= (MB_CUR_MAX
> 1);
146 * Skip leading slashes
149 if (ap
= strrchr(cmdname
, '/'))
154 * Detect egrep/fgrep via command name, map to -E and -F options.
156 if (*ap
== 'e' || *ap
== 'E') {
157 regflags
|= REG_EXTENDED
;
160 if (*ap
== 'f' || *ap
== 'F') {
165 while ((c
= getopt(argc
, argv
, "vwchHilnrbse:f:qxEFIR")) != EOF
) {
167 case 'v': /* POSIX: negate matches */
171 case 'c': /* POSIX: write count */
175 case 'i': /* POSIX: ignore case */
177 regflags
|= REG_ICASE
;
180 case 'l': /* POSIX: Write filenames only */
184 case 'n': /* POSIX: Write line numbers */
188 case 'r': /* Solaris: search recursively */
192 case 'b': /* Solaris: Write file block numbers */
196 case 's': /* POSIX: No error msgs for files */
200 case 'e': /* POSIX: pattern list */
202 pattern_list
= realloc(pattern_list
,
203 sizeof (char *) * n_pattern
);
204 if (pattern_list
== NULL
) {
205 (void) fprintf(stderr
,
206 gettext("%s: out of memory\n"),
210 *(pattern_list
+ n_pattern
- 1) = optarg
;
213 case 'f': /* POSIX: pattern file */
216 file_list
= realloc(file_list
,
217 sizeof (char *) * n_file
);
218 if (file_list
== NULL
) {
219 (void) fprintf(stderr
,
220 gettext("%s: out of memory\n"),
224 *(file_list
+ n_file
- 1) = optarg
;
227 /* based on options order h or H is set as in GNU grep */
228 case 'h': /* Solaris: supress printing of file name */
232 /* Solaris: precede every matching with file name */
238 case 'q': /* POSIX: quiet: status only */
242 case 'w': /* Solaris: treat pattern as word */
246 case 'x': /* POSIX: full line matches */
248 regflags
|= REG_ANCHOR
;
251 case 'E': /* POSIX: Extended RE's */
252 regflags
|= REG_EXTENDED
;
256 case 'F': /* POSIX: strings, not RE's */
260 case 'R': /* Solaris: like rflag, but follow symlinks */
270 * If we're invoked as egrep or fgrep we need to do some checks
273 if (egrep
|| fgrep
) {
275 * Use of -E or -F with egrep or fgrep is illegal
280 * Don't allow use of wflag with egrep / fgrep
285 * For Solaris the -s flag is equivalent to XCU -q
290 * done with above checks - set the appropriate flags
294 else /* Else fgrep */
298 if (wflag
&& (Eflag
|| Fflag
)) {
300 * -w cannot be specified with grep -F
306 * -E and -F flags are mutually exclusive - check for this
312 * -l overrides -H like in GNU grep
318 * -c, -l and -q flags are mutually exclusive
319 * We have -c override -l like in Solaris.
320 * -q overrides -l & -c programmatically in grep() function.
329 * Now handling -e and -f option
332 for (i
= 0; i
< n_pattern
; i
++) {
333 addpattern(pattern_list
[i
]);
338 for (i
= 0; i
< n_file
; i
++) {
339 addfile(file_list
[i
]);
345 * No -e or -f? Make sure there is one more arg, use it as the pattern.
347 if (patterns
== NULL
&& !fflag
) {
356 * If -x flag is not specified or -i flag is specified
357 * with fgrep in a multibyte locale, need to use
358 * the wide character APIs. Otherwise, byte-oriented
359 * process will be done.
361 use_wchar
= Fflag
&& mblocale
&& (!xflag
|| iflag
);
364 * Compile Patterns and also decide if BMG can be used
368 /* Process all files: stdin, or rest of arg list */
370 matched
= grep(0, STDIN_FILENAME
);
372 if (Hflag
|| (argc
> 2 && hflag
== 0))
373 outfn
= 1; /* Print filename on match line */
374 for (argv
++; *argv
!= NULL
; argv
++) {
379 * Return() here is used instead of exit
382 (void) fflush(stdout
);
386 return (matched
? 0 : 1);
390 process_path(const char *path
)
393 int walkflags
= FTW_CHDIR
;
397 if (stat(path
, &st
) != -1 &&
398 (st
.st_mode
& S_IFMT
) == S_IFDIR
) {
399 outfn
= 1; /* Print filename */
402 * Add trailing slash if arg
403 * is directory, to resolve symlinks.
405 if (path
[strlen(path
) - 1] != '/') {
406 (void) asprintf(&buf
, "%s/", path
);
412 * Search through subdirs if path is directory.
413 * Don't follow symlinks if Rflag is not set.
416 walkflags
|= FTW_PHYS
;
418 if (nftw(path
, recursive
, MAX_DEPTH
, walkflags
) != 0) {
420 (void) fprintf(stderr
,
421 gettext("%s: can't open \"%s\"\n"),
428 process_file(path
, 0);
432 * Read and process all files in directory recursively.
435 recursive(const char *name
, const struct stat
*statp
, int info
, struct FTW
*ftw
)
438 * Process files and follow symlinks if Rflag set.
441 /* Report broken symlinks and unreadable files */
443 (info
== FTW_SLN
|| info
== FTW_DNR
|| info
== FTW_NS
)) {
444 (void) fprintf(stderr
,
445 gettext("%s: can't open \"%s\"\n"), cmdname
, name
);
451 /* Skip devices and pipes if Rflag is not set */
452 if (!Rflag
&& !S_ISREG(statp
->st_mode
))
454 /* Pass offset to relative name from FTW_CHDIR */
455 process_file(name
, ftw
->base
);
460 * Opens file and call grep function.
463 process_file(const char *name
, int base
)
467 if ((fd
= open(name
+ base
, O_RDONLY
)) == -1) {
469 if (!sflag
) /* Silent mode */
470 (void) fprintf(stderr
, gettext(
471 "%s: can't open \"%s\"\n"),
475 matched
|= grep(fd
, name
);
478 if (ferror(stdout
)) {
479 (void) fprintf(stderr
, gettext(
480 "%s: error writing to stdout\n"),
482 (void) fflush(stdout
);
489 * Add a file of strings to the pattern list.
492 addfile(const char *fn
)
497 size_t bufsiz
, buflen
, bufused
;
500 * Open the pattern file
502 if ((fp
= fopen(fn
, "r")) == NULL
) {
503 (void) fprintf(stderr
, gettext("%s: can't open \"%s\"\n"),
508 if ((inbuf
= malloc(bufsiz
)) == NULL
) {
509 (void) fprintf(stderr
,
510 gettext("%s: out of memory\n"), cmdname
);
516 * Read in the file, reallocing as we need more memory
518 while (fgets(bufp
, bufsiz
- bufused
, fp
) != NULL
) {
519 buflen
= strlen(bufp
);
521 if (bufused
+ 1 == bufsiz
&& bufp
[buflen
- 1] != '\n') {
523 * if this line does not fit to the buffer,
524 * realloc larger buffer
527 if ((inbuf
= realloc(inbuf
, bufsiz
)) == NULL
) {
528 (void) fprintf(stderr
,
529 gettext("%s: out of memory\n"),
533 bufp
= inbuf
+ bufused
;
536 if (bufp
[buflen
- 1] == '\n') {
537 bufp
[--buflen
] = '\0';
549 * Add a string to the pattern list.
559 np
= strchr(s
, '\n');
562 if ((pp
= malloc(sizeof (PATTERN
))) == NULL
) {
563 (void) fprintf(stderr
, gettext(
564 "%s: out of memory\n"),
570 * Solaris wflag support: Add '<' '>' to pattern to
571 * select it as a word. Doesn't make sense with -F
572 * but we're Libertarian.
574 size_t slen
, wordlen
;
577 wordlen
= slen
+ 5; /* '\\' '<' s '\\' '>' '\0' */
578 if ((wordbuf
= malloc(wordlen
)) == NULL
) {
579 (void) fprintf(stderr
,
580 gettext("%s: out of memory\n"),
584 (void) strcpy(wordbuf
, "\\<");
585 (void) strcpy(wordbuf
+ 2, s
);
586 (void) strcpy(wordbuf
+ 2 + slen
, "\\>");
588 if ((wordbuf
= strdup(s
)) == NULL
) {
589 (void) fprintf(stderr
,
590 gettext("%s: out of memory\n"),
595 pp
->pattern
= wordbuf
;
606 * Must do after all arguments read, in case later -i option.
612 int rv
, fix_pattern
, npatterns
;
615 * As REG_ANCHOR flag is not supported in the current Solaris,
616 * need to fix the specified pattern if -x is specified with
619 fix_pattern
= !Fflag
&& xflag
;
621 for (npatterns
= 0, pp
= patterns
; pp
!= NULL
; pp
= pp
->next
) {
627 plen
= strlen(pp
->pattern
);
628 /* '^' pattern '$' */
629 nplen
= 1 + plen
+ 1 + 1;
630 if ((cp
= malloc(nplen
)) == NULL
) {
631 (void) fprintf(stderr
,
632 gettext("%s: out of memory\n"),
638 cq
= strcpy(cq
, pp
->pattern
) + plen
;
648 * Fflag && mblocale && iflag
649 * Fflag && mblocale && !xflag
652 n
= strlen(pp
->pattern
) + 1;
654 malloc(sizeof (wchar_t) * n
)) == NULL
) {
655 (void) fprintf(stderr
,
656 gettext("%s: out of memory\n"),
660 if (mbstowcs(pp
->wpattern
, pp
->pattern
, n
) ==
662 (void) fprintf(stderr
,
663 gettext("%s: failed to convert "
664 "\"%s\" to wide-characters\n"),
665 cmdname
, pp
->pattern
);
670 for (wp
= pp
->wpattern
; *wp
!= L
'\0';
672 *wp
= towlower((wint_t)*wp
);
678 * Fflag && mblocale && !iflag
679 * Fflag && !mblocale && iflag
680 * Fflag && !mblocale && !iflag
684 for (cp
= (unsigned char *)pp
->pattern
;
691 * fgrep: No regular expressions.
697 * For non-fgrep, compile the regular expression,
698 * give an informative error message, and exit if
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
);
712 * Decide if we are able to run the Boyer-Moore-Gosper algorithm.
713 * Use the Boyer-Moore-Gosper algorithm if:
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)
722 * It's guaranteed patterns->pattern is still alive
723 * when Fflag && !mblocale.
725 use_bmg
= Fflag
&& !mblocale
&& !iflag
&& !nflag
&& nvflag
&&
726 (npatterns
== 1) && (strlen(patterns
->pattern
) != 0);
730 * Search a newline from the beginning of the string
733 find_nl(const char *ptr
, size_t len
)
736 if (*ptr
++ == '\n') {
737 return ((char *)--ptr
);
744 * Search a newline from the end of the string
747 rfind_nl(const char *ptr
, size_t len
)
749 const char *uptr
= ptr
+ len
;
751 if (*--uptr
== '\n') {
752 return ((char *)uptr
);
759 * Duplicate the specified string converting each character
763 istrdup(const char *s1
)
765 static size_t ibuflen
= 0;
766 static char *ibuf
= NULL
;
771 if (slen
>= ibuflen
) {
772 /* ibuf does not fit to s1 */
774 ibuf
= realloc(ibuf
, ibuflen
);
776 (void) fprintf(stderr
,
777 gettext("%s: out of memory\n"), cmdname
);
784 } while (*s1
++ != '\0');
789 * Do grep on a single file.
790 * Return true in any lines matched.
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.
801 grep(int fd
, const char *fn
)
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 */
808 long long matches
= 0; /* Number of matching lines */
809 int newlinep
; /* 0 if the last line of file has no newline */
813 if (patterns
== NULL
)
814 return (0); /* no patterns to match -- just return */
819 bmgcomp(pp
->pattern
, strlen(pp
->pattern
));
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"),
832 if (prntbuf
== NULL
) {
833 prntbuflen
= BUFSIZE
;
834 if ((prntbuf
= malloc(prntbuflen
+ 1)) == NULL
) {
835 (void) fprintf(stderr
, gettext("%s: out of memory\n"),
851 * If no data in the buffer, reset ptr
855 if (ptr
== prntbuf
) {
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.
862 count
= read(fd
, ptr
+ data_len
, prntbuflen
- data_len
);
866 if (outfn
&& !rflag
) {
867 (void) fprintf(stdout
,
870 if (!qflag
&& !rflag
) {
871 (void) fprintf(stdout
, "%lld\n",
876 } else if (count
== 0) {
879 /* end of file already reached */
882 /* last line of file has no newline */
883 ptrend
= ptr
+ data_len
;
885 goto L_start_process
;
892 * Look for newline in the chunk
893 * between ptr + offset and ptr + data_len - offset.
895 ptrend
= find_nl(ptr
+ offset
, data_len
- offset
);
896 if (ptrend
== NULL
) {
897 /* no newline found in this chunk */
900 * Move remaining data to the beginning
902 * Remaining data lie from ptr for
905 (void) memmove(prntbuf
, ptr
, data_len
);
907 if (data_len
== prntbuflen
) {
909 * No enough room in the buffer
911 prntbuflen
+= BUFSIZE
;
912 prntbuf
= realloc(prntbuf
, prntbuflen
+ 1);
913 if (prntbuf
== NULL
) {
914 (void) fprintf(stderr
,
915 gettext("%s: out of memory\n"),
921 /* read the next input */
927 * Beginning of the chunk: ptr
928 * End of the chunk: ptr + data_len
929 * Beginning of the line: ptr
930 * End of the line: ptrend
935 * Use Boyer-Moore-Gosper algorithm to find out if
936 * this chunk (not this line) contains the specified
937 * pattern. If not, restart from the last line
941 bline
= bmgexec(ptr
, ptr
+ data_len
);
944 * No pattern found in this chunk.
945 * Need to find the last line
948 ptrend
= rfind_nl(ptr
, data_len
);
951 * When this chunk does not contain newline,
952 * ptrend becomes NULL, which should happen
953 * when the last line of file does not end
954 * with a newline. At such a point,
955 * newlinep should have been set to 0.
956 * Therefore, just after jumping to
957 * L_skip_line, the main for-loop quits,
958 * and the line_len value won't be
961 line_len
= ptrend
- ptr
;
964 if (bline
> ptrend
) {
966 * Pattern found not in the first line
968 * Discard the first line.
970 line_len
= ptrend
- ptr
;
974 * Pattern found in the first line of this chunk.
978 line_len
= ptrend
- ptr
;
981 * before jumping to L_next_line,
982 * need to handle xflag if specified
984 if (xflag
&& (line_len
!= bmglen
||
985 strcmp(bmgpat
, ptr
) != 0)) {
989 pp
= patterns
; /* to make it happen */
995 * Line starts from ptr and ends at ptrend.
996 * line_len will be the length of the line.
999 line_len
= ptrend
- ptr
;
1002 * From now, the process will be performed based
1003 * on the line from ptr to ptrend.
1008 if (line_len
>= outbuflen
) {
1009 outbuflen
= line_len
+ 1;
1010 outline
= realloc(outline
,
1011 sizeof (wchar_t) * outbuflen
);
1012 if (outline
== NULL
) {
1013 (void) fprintf(stderr
,
1014 gettext("%s: out of memory\n"),
1020 len
= mbstowcs(outline
, ptr
, line_len
);
1021 if (len
== (size_t)-1) {
1022 (void) fprintf(stderr
, gettext(
1023 "%s: input file \"%s\": line %lld: invalid multibyte character\n"),
1024 cmdname
, fn
, lineno
);
1025 /* never match a line with invalid sequence */
1028 outline
[len
] = L
'\0';
1032 for (cp
= outline
; *cp
!= '\0'; cp
++) {
1033 *cp
= towlower((wint_t)*cp
);
1038 for (pp
= patterns
; pp
; pp
= pp
->next
) {
1039 if (outline
[0] == pp
->wpattern
[0] &&
1041 pp
->wpattern
) == 0) {
1047 for (pp
= patterns
; pp
; pp
= pp
->next
) {
1048 if (wcswcs(outline
, pp
->wpattern
)
1056 /* fgrep in byte-oriented handling */
1059 fptr
= istrdup(ptr
);
1065 for (pp
= patterns
; pp
; pp
= pp
->next
) {
1066 if (fptr
[0] == pp
->pattern
[0] &&
1067 strcmp(fptr
, pp
->pattern
) == 0) {
1073 for (pp
= patterns
; pp
; pp
= pp
->next
) {
1074 if (strstr(fptr
, pp
->pattern
) != NULL
) {
1082 for (pp
= patterns
; pp
; pp
= pp
->next
) {
1085 rv
= regexec(&pp
->re
, ptr
, 0, NULL
, 0);
1095 (void) fprintf(stderr
, gettext(
1096 "%s: input file \"%s\": line %lld: invalid multibyte character\n"),
1097 cmdname
, fn
, lineno
);
1100 (void) regerror(rv
, &pp
->re
, errstr
,
1102 (void) fprintf(stderr
, gettext(
1103 "%s: input file \"%s\": line %lld: %s\n"),
1104 cmdname
, fn
, lineno
, errstr
);
1112 * Here, if pp points to non-NULL, something has been matched
1115 if (nvflag
== (pp
!= NULL
)) {
1118 * Handle q, l, and c flags.
1121 /* no need to continue */
1123 * End of this line is ptrend.
1124 * We have read up to ptr + data_len.
1127 pos
= ptr
+ data_len
- (ptrend
+ 1);
1128 (void) lseek(fd
, -pos
, SEEK_CUR
);
1132 (void) printf("%s\n", fn
);
1136 if (Hflag
|| outfn
) {
1137 (void) printf("%s:", fn
);
1140 (void) printf("%lld:", (offset_t
)
1141 (line_offset
/ BSIZE
));
1144 (void) printf("%lld:", lineno
);
1147 (void) fwrite(ptr
, 1, line_len
+ 1, stdout
);
1149 if (ferror(stdout
)) {
1157 data_len
-= line_len
+ 1;
1158 line_offset
+= line_len
+ 1;
1163 if (Hflag
|| outfn
) {
1164 (void) printf("%s:", fn
);
1167 (void) printf("%lld\n", matches
);
1170 return (matches
!= 0);
1174 * usage message for grep
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"));
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"));
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"));
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"));
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"));
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"));
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"));
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"));
1228 * Compile literal pattern into BMG tables
1231 bmgcomp(char *pat
, int len
)
1235 unsigned char *uc
= (unsigned char *)pat
;
1240 for (i
= 0; i
< M_CSETSIZE
; i
++) {
1245 for (tlen
= len
, i
= 0; i
<= len
; i
++, tlen
--) {
1246 bmgtab
[*uc
++] = tlen
;
1254 bmgexec(char *str
, char *end
)
1259 k
= str
+ bmglen
- 1;
1261 return (memchr(str
, bmgpat
[0], end
- str
));
1264 /* inner loop, should be most optimized */
1265 while (k
< end
&& (t
= bmgtab
[(unsigned char)*k
]) != 0) {
1271 for (s
= k
, p
= bmgpat
+ bmglen
- 1; *--s
== *--p
; ) {