2 * The information in this document is subject to change
3 * without notice and should not be construed as a commitment
4 * by Digital Equipment Corporation or by DECUS.
6 * Neither Digital Equipment Corporation, DECUS, nor the authors
7 * assume any responsibility for the use or reliability of this
8 * document or the described software.
10 * Copyright (C) 1980, DECUS
12 * General permission to copy or modify, but not for profit, is
13 * hereby granted, provided that the above copyright notice is
14 * included and reference made to the fact that reproduction
15 * privileges were granted by DECUS.
23 * Runs on the Decus compiler or on vms, On vms, define as:
24 * grep :== "$disk:[account]grep" (native)
25 * grep :== "$disk:[account]grep grep" (Decus)
26 * See below for more information.
29 char *documentation
[] = {
30 "grep searches a file for a given pattern. Execute by",
31 " grep [flags] regular_expression file_list\n",
32 "Flags are single characters preceded by '-':",
33 " -c Only a count of matching lines is printed",
34 " -f Print file name for matching lines switch, see below",
35 " -n Each line is preceded by its line number",
36 " -v Only print non-matching lines\n",
37 "The file_list is a list of files (wildcards are acceptable on RSX modes).",
38 "\nThe file name is normally printed if there is a file given.",
39 "The -f flag reverses this action (print name no file, not if more).\n",
43 "The regular_expression defines the pattern to search for. Upper- and",
44 "lower-case are always ignored. Blank lines never match. The expression",
45 "should be quoted to prevent file-name translation.",
46 "x An ordinary character (not mentioned below) matches that character.",
47 "'\\' The backslash quotes any character. \"\\$\" matches a dollar-sign.",
48 "'^' A circumflex at the beginning of an expression matches the",
49 " beginning of a line.",
50 "'$' A dollar-sign at the end of an expression matches the end of a line.",
51 "'.' A period matches any character except \"new-line\".",
52 "':a' A colon matches a class of characters described by the following",
53 "':d' character. \":a\" matches any alphabetic, \":d\" matches digits,",
54 "':n' \":n\" matches alphanumerics, \": \" matches spaces, tabs, and",
55 "': ' other control characters, such as new-line.",
56 "'*' An expression followed by an asterisk matches zero or more",
57 " occurrences of that expression: \"fo*\" matches \"f\", \"fo\"",
59 "'+' An expression followed by a plus sign matches one or more",
60 " occurrences of that expression: \"fo+\" matches \"fo\", etc.",
61 "'-' An expression followed by a minus sign optionally matches",
63 "'[]' A string enclosed in square brackets matches any character in",
64 " that string, but no others. If the first character in the",
65 " string is a circumflex, the expression matches any character",
66 " except \"new-line\" and the characters in the string. For",
67 " example, \"[xyz]\" matches \"xx\" and \"zyx\", while \"[^xyz]\"",
68 " matches \"abc\" but not \"axb\". A range of characters may be",
69 " specified by two characters separated by \"-\". Note that,",
70 " [a-z] matches alphabetics, while [z-a] never matches.",
71 "The concatenation of regular expressions is a regular expression.",
93 int cflag
=0, fflag
=0, nflag
=0, vflag
=0, nfile
=0, debug
=0;
95 char *pp
, lbuf
[LMAX
], pbuf
[PMAX
];
101 void badpat(char *, char *, char *);
105 /*** Display a file name *******************************/
108 printf("File %s:\n", s
);
111 /*** Report unopenable file ****************************/
114 fprintf(stderr
, "%s: cannot open\n", s
);
117 /*** Give good help ************************************/
122 for (dp
= hp
; *dp
; ++dp
)
126 /*** Display usage summary *****************************/
129 fprintf(stderr
, "?GREP-E-%s\n", s
);
131 "Usage: grep [-cfnv] pattern [file ...]. grep ? for help\n");
135 /*** Compile the pattern into global pbuf[] ************/
136 void compile(char *source
)
138 char *s
; /* Source string pointer */
139 char *lp
; /* Last pattern pointer */
140 int c
; /* Current character */
142 char *spp
; /* Save beginning of pattern */
146 printf("Pattern = \"%s\"\n", s
);
150 * STAR, PLUS and MINUS are special.
152 if (c
== '*' || c
== '+' || c
== '-') {
159 badpat("Illegal occurrence op.", source
, s
);
162 spp
= pp
; /* Save pattern end */
163 while (--pp
> lp
) /* Move pattern down */
164 *pp
= pp
[-1]; /* one byte */
165 *pp
= (c
== '*') ? STAR
:
166 (c
== '-') ? MINUS
: PLUS
;
167 pp
= spp
; /* Restore pattern end */
173 lp
= pp
; /* Remember start */
189 s
= cclass(source
, s
);
194 switch(tolower(c
= *s
++)) {
216 badpat("Unknown : type", source
, s
);
221 else badpat("No : type", source
, s
);
233 store(0); /* Terminate string */
235 for (lp
= pbuf
; lp
< pp
;) {
236 if ((c
= (*lp
++ & 0377)) < ' ')
238 else printf("%c ", c
);
244 /*** Compile a class (within []) ***********************/
245 char *cclass(char *source
, char *src
)
246 /* char *source; // Pattern start -- for error msg. */
247 /* char *src; // Class start */
249 char *s
; /* Source pointer */
250 char *cp
; /* Pattern start */
251 int c
; /* Current character */
262 store(0); /* Byte count */
263 while ((c
= *s
++) && c
!=']') {
264 if (c
== '\\') { /* Store quoted char */
265 if ((c
= *s
++) == '\0') /* Gotta get something */
266 badpat("Class terminates badly", source
, s
);
267 else store(tolower(c
));
270 (pp
- cp
) > 1 && *s
!= ']' && *s
!= '\0') {
271 c
= pp
[-1]; /* Range start */
272 pp
[-1] = RANGE
; /* Range signal */
273 store(c
); /* Re-store start */
274 c
= *s
++; /* Get end char and*/
275 store(tolower(c
)); /* Store it */
278 store(tolower(c
)); /* Store normal char */
282 badpat("Unterminated class", source
, s
);
283 if ((c
= (pp
- cp
)) >= 256)
284 badpat("Class too large", source
, s
);
286 badpat("Empty class", source
, s
);
291 /*** Store an entry in the pattern buffer **************/
294 if (pp
>= &pbuf
[PMAX
])
295 error("Pattern too complex\n");
299 /*** Report a bad pattern specification ****************/
300 void badpat(char *message
, char *source
, char *stop
)
301 /* char *message; // Error message */
302 /* char *source; // Pattern start */
303 /* char *stop; // Pattern end */
305 fprintf(stderr
, "-GREP-E-%s, pattern is\"%s\"\n", message
, source
);
306 fprintf(stderr
, "-GREP-E-Stopped at byte %ld, '%c'\n",
307 stop
-source
, stop
[-1]);
308 error("?GREP-E-Bad pattern\n");
311 /*** Scan the file for the pattern in pbuf[] ***********/
312 void grep(FILE *fp
, char *fn
)
313 /* FILE *fp; // File to process */
314 /* char *fn; // File name (for -f option) */
320 while (fgets(lbuf
, LMAX
, fp
)) {
323 if ((m
&& !vflag
) || (!m
&& vflag
)) {
332 printf("%s\n", lbuf
);
339 printf("%d\n", count
);
343 /*** Match line (lbuf) with pattern (pbuf) return 1 if match ***/
346 char *l
; /* Line pointer */
348 for (l
= lbuf
; *l
; ++l
) {
355 /*** Match partial line with pattern *******************/
356 char *pmatch(char *line
, char *pattern
)
357 /* char *line; // (partial) line to match */
358 /* char *pattern; // (partial) pattern to match */
360 char *l
; /* Current line pointer */
361 char *p
; /* Current pattern pointer */
362 char c
; /* Current character */
363 char *e
; /* End for STAR and PLUS match */
364 int op
; /* Pattern operation */
365 int n
; /* Class counter */
366 char *are
; /* Start of STAR match */
370 printf("pmatch(\"%s\")\n", line
);
372 while ((op
= *p
++) != ENDPAT
) {
374 printf("byte[%ld] = 0%o, '%c', op = 0%o\n",
379 if (tolower(*l
++) != *p
++)
399 if ((c
= *l
++) < '0' || (c
> '9'))
405 if (c
< 'a' || c
> 'z')
411 if (c
>= 'a' && c
<= 'z')
413 else if (c
< '0' || c
> '9')
419 if (c
== 0 || c
> ' ')
431 if (c
>= p
[-2] && c
<= p
[-1])
437 if ((op
== CLASS
) == (n
<= 1))
444 e
= pmatch(l
, p
); /* Look for a match */
445 while (*p
++ != ENDPAT
); /* Skip over pattern */
446 if (e
) /* Got a match? */
447 l
= e
; /* Yes, update string */
448 break; /* Always succeeds */
450 case PLUS
: /* One or more ... */
451 if ((l
= pmatch(l
, p
)) == 0)
452 return(0); /* Gotta have a match */
453 case STAR
: /* Zero or more ... */
454 are
= l
; /* Remember line start */
455 while (*l
&& (e
= pmatch(l
, p
)))
456 l
= e
; /* Get longest match */
457 while (*p
++ != ENDPAT
); /* Skip over pattern */
458 while (l
>= are
) { /* Try to match rest */
459 if (e
= pmatch(l
, p
))
461 --l
; /* Nope, try earlier */
463 return(0); /* Nothing else worked */
466 printf("Bad op code %d\n", op
);
467 error("Cannot happen -- match\n");
473 /*** Report an error ***********************************/
476 fprintf(stderr
, "%s", s
);
480 /*** Main program - parse arguments & grep *************/
481 int main(int argc
, char **argv
)
490 usage("No arguments");
491 if (argc
== 2 && argv
[1][0] == '?' && argv
[1][1] == 0) {
498 for (i
=1; i
< argc
; ++i
) {
535 usage("Unknown flag");
540 } else if (!gotpattern
) {
552 fflag
= fflag
^ (nfile
> 0);
553 for (i
=1; i
< argc
; ++i
) {
555 if ((f
=fopen(p
, "r")) == NULL
)
567 /* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/