1 /* cgrep - grep and display context Author: Mark Mallet */
4 Nov 19 1984 Mark Mallett (mem@zinn.MV.COM)
6 mem 860224 Modified to do r/e (regular expression) parsing on unix
7 mem 860324 Added -f, -n; added code to number lines correctly on output.
8 mem 870325 Added support for regcmp()/regex() style regular expression
9 library; redid some conditionals to provide better mix'n'match.
10 mem 870326 Don't try to print the filename if reading from stdin.
11 Add -w option. Fix a small problem which occasionally allowed
12 the separator to come out between adjacent lines of the file.
13 mem 871119 Fix semantics of call to regcmp(): the NULL terminating the
14 argument list was missing. It worked, but probably only
15 due to some bizarre coincidence.
16 dro 890109 Minor mods to compile under Minix
20 #define OS_UNIX /* Define this for unix systems */
21 /* #define REGEX *//* Define this for re_comp/re_exec library */
22 #define REGCMP /* Define this to use regcmp/regex */
23 /* #define OS_CPM *//* Define this for CP/M-80 */
26 /* Don't touch these */
27 #define NOREGEXP /* Set this for no regular expression */
43 #include <sys/types.h>
44 #include <sys/dir.h> /* Either here or in sys directory - dro */
46 #include <limits.h> /* should have this - dro */
47 #include <regexp.h> /* should have this - dro */
53 /* Local definitions */
56 #define NULL ((char *)0)
69 /* Internal data declared global */
72 /* Internal routines */
74 _PROTOTYPE(int main
, (int argc
, char **argv
));
75 _PROTOTYPE(void dosrch
, (char *ifnm
));
76 _PROTOTYPE(void shwlin
, (char *fnm
, int linnum
, char *line
));
77 _PROTOTYPE(int matlin
, (char *line
));
78 _PROTOTYPE(void regerror
, (const char *s
));
85 static int Debug
= {FALSE
}; /* Debug enabled flag */
86 static int Lcur
= {0}; /* Current line (in Lines array) */
87 static char **Lines
= {NULL
}; /* Lines pointer array */
88 static int Linlen
= {100}; /* Line length */
89 static int Lone
= {0}; /* Line one (in Lines array) */
90 static int Nmr
= {0}; /* Number of matched regions */
91 static char *Pat
= {NULL
}; /* Pattern */
92 static char Shwfile
= {TRUE
}; /* Show file name... */
93 static char Shwline
= {TRUE
}; /* Show line number */
94 static int Waft
= {0}; /* Window after */
95 static int Wbef
= {0}; /* Window before */
96 static int Wsiz
= {0}; /* Window size */
98 regexp
*Re
; /* Result from reg compilation */
101 int argc
; /* Argument count */
102 char **argv
; /* Argument values */
106 int n
; /* Scratch again */
107 int c
; /* A character */
108 char *aptr
; /* Argument pointer */
109 int nf
; /* number of files on command line */
111 nf
= 0; /* No files on line */
113 for (i
= 1; i
< argc
; i
++) { /* Look at args */
114 if (argv
[i
][0] != '-') {/* If option */
115 if (Pat
== NULL
) { /* If no pattern yet given */
116 Pat
= argv
[i
]; /* point here */
118 if ((Re
= re_comp(Pat
)) != NULL
) {
119 fprintf(stderr
, "cgrep: %s\n", re
);
125 if ((Re
= regcomp(Pat
)) == NULL
) {
126 fprintf(stderr
, "cgrep: error in regular expression.\n");
131 } else { /* This must be a file to search */
133 dosrch(argv
[i
]); /* Search */
135 } else { /* Option char */
136 c
= argv
[i
][1]; /* Get option char */
137 if (isupper(c
)) /* Trap idiot definition of tolower */
138 c
= tolower(c
); /* Don't care about case */
140 aptr
= NULL
; /* Find arg, if any */
141 if (argv
[i
][2] != NUL
) {
143 n
= i
; /* Where to set i if we use this arg */
144 } else if (i
< argc
- 1) { /* use next.. */
148 switch (c
) { /* Process the option */
149 case 'a': /* Lines after */
155 case 'b': /* Lines before */
161 /* Disable debug output
162 case 'd': Debug = TRUE; break;
165 case 'f': /* Suppress filename on output */
169 case 'l': /* Line length */
175 case 'n': /* Suppress line number on output */
179 case 'w': /* Window: lines before and after */
180 Waft
= Wbef
= atoi(aptr
);
186 fprintf(stderr
, "Invalid option %s\n", argv
[i
]);
192 if (Pat
== NULL
) { /* If no pattern given */
194 "Usage: cgrep [-a n] [-b n] [-f] [-l n] [-n] [-w n] pattern [filename... ]\n");
197 if (nf
== 0) /* No files processed ? */
198 dosrch((char *)NULL
); /* Do standard input */
202 /* Dosrch (ifnm) Perform the search
205 * ifn Input file name
214 char *ifnm
; /* Input filelname */
217 FILE *ifp
; /* Input fp */
218 char *lptr
; /* Line pointer */
220 int prtaft
; /* Print-after count */
221 int linnum
; /* Line number */
222 int nlb
; /* Number of lines buffered */
224 if (ifnm
!= NULL
) { /* If file name given */
225 ifp
= fopen(ifnm
, "r"); /* Open it for read access */
227 fprintf(stderr
, "Can not open file %s\n", ifnm
);
233 if (Lines
== NULL
) { /* If no line table allocated.. */
234 Wsiz
= Wbef
+ 2; /* Determine total window size */
235 Lines
= (char **) calloc((size_t)Wsiz
, sizeof(char *));
236 /* Allocate pointer table */
237 for (i
= 0; i
< Wsiz
; i
++) /* Allocate line buffers */
238 Lines
[i
] = (char *) calloc((size_t)Linlen
, sizeof(char));
240 Lcur
= Lone
= 0; /* Setup line pointers */
241 nlb
= 0; /* No lines buffered */
242 linnum
= 0; /* Line number is zero */
243 prtaft
= -(Wbef
+ 1); /* Make sure separator given first time */
245 for (;;) { /* Loop through the file */
246 lptr
= Lines
[Lcur
]; /* Get pointer to current line */
247 if (++Lcur
== Wsiz
) /* Bump curr pointer and wrap */
248 Lcur
= 0; /* if hit end */
249 if (Lone
== Lcur
) /* If wrapped to beginning of window */
250 if (++Lone
== Wsiz
) /* Bump beginning */
251 Lone
= 0; /* and wrap if hit end */
253 if (fgets(lptr
, Linlen
, ifp
) != lptr
) break; /* if end of file */
255 linnum
++; /* Count line number */
256 if (matlin(lptr
)) { /* If matching line */
257 if (prtaft
< (-Wbef
)) /* Check for separator needed */
258 if ((Nmr
++ > 0) && ((Wbef
> 0) || (Waft
> 0)))
259 printf("----------------------------------------------------------------------------\n");
260 while (Lone
!= Lcur
) { /* Until we close the window */
261 shwlin(ifnm
, linnum
- nlb
, Lines
[Lone
]);
263 if (++Lone
== Wsiz
) Lone
= 0;
266 nlb
= 0; /* No lines buffered */
267 prtaft
= Waft
; /* Print n lines after */
268 } else { /* Didn't match */
269 if (prtaft
-- > 0) { /* If must print lines after */
270 shwlin(ifnm
, linnum
, lptr
);
272 Lone
= Lcur
; /* Match pointers */
273 } else if (nlb
< Wbef
) /* Count lines buffered */
278 if (ifnm
!= NULL
) fclose(ifp
);
281 /* Shwlin (fnm, linnum, line) Show a matching line
297 void shwlin(fnm
, linnum
, line
)
298 char *fnm
; /* File name */
299 int linnum
; /* Line number */
300 char *line
; /* Line (with newline at end) to print */
303 if (Shwfile
&& (fnm
!= NULL
)) printf("%s%s", fnm
, Shwline
? " " : ":");
304 if (Shwline
) printf("@%05d:", linnum
);
308 /* Matlin (line) Perform match against pattern and line
312 * line Address of line to match
317 * <value> TRUE if match FALSE if not
324 char *line
; /* Line to match */
327 int rtncode
; /* Return value from this routine */
331 char *pptr
, *lptr
, *tlptr
;
333 #endif /* NOREGEXP */
335 if (Debug
) printf("Matching %s against %s", Pat
, line
);
338 rtncode
= re_exec(line
); /* Hand off to r/e evaluator */
342 rtncode
= (regexec(Re
, line
, TRUE
) != 0);
345 #ifdef NOREGEX /* Have to do menial comparison.. */
346 lptr
= line
; /* Init line pointer */
348 for (rtncode
= -1; rtncode
< 0;) {
349 tlptr
= lptr
++; /* Get temp ptr to line */
350 pptr
= Pat
; /* Get ptr to pattern */
352 if ((c1
= *pptr
++) == NUL
) {
353 rtncode
= 1; /* GOOD return value */
356 if ((c2
= *tlptr
++) == NUL
) {
357 rtncode
= 0; /* BAD return value */
360 if (isupper(c1
)) c1
= tolower(c1
);
361 if (isupper(c2
)) c2
= tolower(c2
);
368 if (Debug
) printf("matlin returned %s\n", rtncode
? "TRUE" : "FALSE");
377 printf("%s\n", (char *) s
);