379 lines
9.1 KiB
C
379 lines
9.1 KiB
C
/* cgrep - grep and display context Author: Mark Mallet */
|
|
|
|
/*
|
|
Nov 19 1984 Mark Mallett (mem@zinn.MV.COM)
|
|
|
|
mem 860224 Modified to do r/e (regular expression) parsing on unix
|
|
mem 860324 Added -f, -n; added code to number lines correctly on output.
|
|
mem 870325 Added support for regcmp()/regex() style regular expression
|
|
library; redid some conditionals to provide better mix'n'match.
|
|
mem 870326 Don't try to print the filename if reading from stdin.
|
|
Add -w option. Fix a small problem which occasionally allowed
|
|
the separator to come out between adjacent lines of the file.
|
|
mem 871119 Fix semantics of call to regcmp(): the NULL terminating the
|
|
argument list was missing. It worked, but probably only
|
|
due to some bizarre coincidence.
|
|
dro 890109 Minor mods to compile under Minix
|
|
|
|
*/
|
|
|
|
#define OS_UNIX /* Define this for unix systems */
|
|
/* #define REGEX *//* Define this for re_comp/re_exec library */
|
|
#define REGCMP /* Define this to use regcmp/regex */
|
|
/* #define OS_CPM *//* Define this for CP/M-80 */
|
|
|
|
|
|
/* Don't touch these */
|
|
#define NOREGEXP /* Set this for no regular expression */
|
|
#ifdef REGEX
|
|
#undef NOREGEXP
|
|
#endif /* REGEX */
|
|
|
|
#ifdef REGCMP
|
|
#undef NOREGEXP
|
|
#endif /* REGCMP */
|
|
|
|
|
|
#ifdef OS_CPM
|
|
#include "stdio.h"
|
|
#include "ctype.h"
|
|
#endif /* OS_CPM */
|
|
|
|
#ifdef OS_UNIX
|
|
#include <sys/types.h>
|
|
#include <sys/dir.h> /* Either here or in sys directory - dro */
|
|
#include <ctype.h>
|
|
#include <limits.h> /* should have this - dro */
|
|
#include <regexp.h> /* should have this - dro */
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#endif /* OS_UNIX */
|
|
|
|
|
|
/* Local definitions */
|
|
|
|
#ifndef NULL
|
|
#define NULL ((char *)0)
|
|
#endif /* NULL */
|
|
|
|
#ifndef NUL
|
|
#define NUL '\000'
|
|
#endif
|
|
|
|
#ifndef TRUE
|
|
#define TRUE 1
|
|
#define FALSE 0
|
|
#endif
|
|
|
|
|
|
/* Internal data declared global */
|
|
|
|
|
|
/* Internal routines */
|
|
|
|
_PROTOTYPE(int main, (int argc, char **argv));
|
|
_PROTOTYPE(void dosrch, (char *ifnm));
|
|
_PROTOTYPE(void shwlin, (char *fnm, int linnum, char *line));
|
|
_PROTOTYPE(int matlin, (char *line));
|
|
_PROTOTYPE(void regerror, (const char *s));
|
|
|
|
/* External data */
|
|
|
|
|
|
/* Local data */
|
|
|
|
static int Debug = {FALSE}; /* Debug enabled flag */
|
|
static int Lcur = {0}; /* Current line (in Lines array) */
|
|
static char **Lines = {NULL}; /* Lines pointer array */
|
|
static int Linlen = {100}; /* Line length */
|
|
static int Lone = {0}; /* Line one (in Lines array) */
|
|
static int Nmr = {0}; /* Number of matched regions */
|
|
static char *Pat = {NULL}; /* Pattern */
|
|
static char Shwfile = {TRUE}; /* Show file name... */
|
|
static char Shwline = {TRUE}; /* Show line number */
|
|
static int Waft = {0}; /* Window after */
|
|
static int Wbef = {0}; /* Window before */
|
|
static int Wsiz = {0}; /* Window size */
|
|
|
|
regexp *Re; /* Result from reg compilation */
|
|
|
|
int main(argc, argv)
|
|
int argc; /* Argument count */
|
|
char **argv; /* Argument values */
|
|
|
|
{
|
|
int i; /* Scratch */
|
|
int n; /* Scratch again */
|
|
int c; /* A character */
|
|
char *aptr; /* Argument pointer */
|
|
int nf; /* number of files on command line */
|
|
|
|
nf = 0; /* No files on line */
|
|
|
|
for (i = 1; i < argc; i++) { /* Look at args */
|
|
if (argv[i][0] != '-') {/* If option */
|
|
if (Pat == NULL) { /* If no pattern yet given */
|
|
Pat = argv[i]; /* point here */
|
|
#ifdef REGEX
|
|
if ((Re = re_comp(Pat)) != NULL) {
|
|
fprintf(stderr, "cgrep: %s\n", re);
|
|
exit(1);
|
|
}
|
|
#endif /* REGEX */
|
|
|
|
#ifdef REGCMP
|
|
if ((Re = regcomp(Pat)) == NULL) {
|
|
fprintf(stderr, "cgrep: error in regular expression.\n");
|
|
exit(1);
|
|
}
|
|
#endif /* REGCMP */
|
|
|
|
} else { /* This must be a file to search */
|
|
nf++; /* Count it */
|
|
dosrch(argv[i]); /* Search */
|
|
}
|
|
} else { /* Option char */
|
|
c = argv[i][1]; /* Get option char */
|
|
if (isupper(c)) /* Trap idiot definition of tolower */
|
|
c = tolower(c); /* Don't care about case */
|
|
n = i;
|
|
aptr = NULL; /* Find arg, if any */
|
|
if (argv[i][2] != NUL) {
|
|
aptr = &argv[i][2];
|
|
n = i; /* Where to set i if we use this arg */
|
|
} else if (i < argc - 1) { /* use next.. */
|
|
n = i + 1;
|
|
aptr = argv[n];
|
|
}
|
|
switch (c) { /* Process the option */
|
|
case 'a': /* Lines after */
|
|
Waft = atoi(aptr);
|
|
Lines = NULL;
|
|
i = n;
|
|
break;
|
|
|
|
case 'b': /* Lines before */
|
|
Wbef = atoi(aptr);
|
|
Lines = NULL;
|
|
i = n;
|
|
break;
|
|
|
|
/* Disable debug output
|
|
case 'd': Debug = TRUE; break;
|
|
*/
|
|
|
|
case 'f': /* Suppress filename on output */
|
|
Shwfile = FALSE;
|
|
break;
|
|
|
|
case 'l': /* Line length */
|
|
Linlen = atoi(aptr);
|
|
Lines = NULL;
|
|
i = n;
|
|
break;
|
|
|
|
case 'n': /* Suppress line number on output */
|
|
Shwline = FALSE;
|
|
break;
|
|
|
|
case 'w': /* Window: lines before and after */
|
|
Waft = Wbef = atoi(aptr);
|
|
Lines = NULL;
|
|
i = n;
|
|
break;
|
|
|
|
default:
|
|
fprintf(stderr, "Invalid option %s\n", argv[i]);
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Pat == NULL) { /* If no pattern given */
|
|
fprintf(stderr,
|
|
"Usage: cgrep [-a n] [-b n] [-f] [-l n] [-n] [-w n] pattern [filename... ]\n");
|
|
exit(1);
|
|
}
|
|
if (nf == 0) /* No files processed ? */
|
|
dosrch((char *)NULL); /* Do standard input */
|
|
return(0);
|
|
}
|
|
|
|
/* Dosrch (ifnm) Perform the search
|
|
* Accepts :
|
|
*
|
|
* ifn Input file name
|
|
*
|
|
*
|
|
* Returns :
|
|
*
|
|
*
|
|
*/
|
|
|
|
void dosrch(ifnm)
|
|
char *ifnm; /* Input filelname */
|
|
|
|
{
|
|
FILE *ifp; /* Input fp */
|
|
char *lptr; /* Line pointer */
|
|
int i; /* Scratch */
|
|
int prtaft; /* Print-after count */
|
|
int linnum; /* Line number */
|
|
int nlb; /* Number of lines buffered */
|
|
|
|
if (ifnm != NULL) { /* If file name given */
|
|
ifp = fopen(ifnm, "r"); /* Open it for read access */
|
|
if (ifp == NULL) {
|
|
fprintf(stderr, "Can not open file %s\n", ifnm);
|
|
return;
|
|
}
|
|
} else
|
|
ifp = stdin;
|
|
|
|
if (Lines == NULL) { /* If no line table allocated.. */
|
|
Wsiz = Wbef + 2; /* Determine total window size */
|
|
Lines = (char **) calloc((size_t)Wsiz, sizeof(char *));
|
|
/* Allocate pointer table */
|
|
for (i = 0; i < Wsiz; i++) /* Allocate line buffers */
|
|
Lines[i] = (char *) calloc((size_t)Linlen, sizeof(char));
|
|
}
|
|
Lcur = Lone = 0; /* Setup line pointers */
|
|
nlb = 0; /* No lines buffered */
|
|
linnum = 0; /* Line number is zero */
|
|
prtaft = -(Wbef + 1); /* Make sure separator given first time */
|
|
|
|
for (;;) { /* Loop through the file */
|
|
lptr = Lines[Lcur]; /* Get pointer to current line */
|
|
if (++Lcur == Wsiz) /* Bump curr pointer and wrap */
|
|
Lcur = 0; /* if hit end */
|
|
if (Lone == Lcur) /* If wrapped to beginning of window */
|
|
if (++Lone == Wsiz) /* Bump beginning */
|
|
Lone = 0; /* and wrap if hit end */
|
|
|
|
if (fgets(lptr, Linlen, ifp) != lptr) break; /* if end of file */
|
|
|
|
linnum++; /* Count line number */
|
|
if (matlin(lptr)) { /* If matching line */
|
|
if (prtaft < (-Wbef)) /* Check for separator needed */
|
|
if ((Nmr++ > 0) && ((Wbef > 0) || (Waft > 0)))
|
|
printf("----------------------------------------------------------------------------\n");
|
|
while (Lone != Lcur) { /* Until we close the window */
|
|
shwlin(ifnm, linnum - nlb, Lines[Lone]);
|
|
/* Show the line */
|
|
if (++Lone == Wsiz) Lone = 0;
|
|
nlb--;
|
|
}
|
|
nlb = 0; /* No lines buffered */
|
|
prtaft = Waft; /* Print n lines after */
|
|
} else { /* Didn't match */
|
|
if (prtaft-- > 0) { /* If must print lines after */
|
|
shwlin(ifnm, linnum, lptr);
|
|
/* Show the line */
|
|
Lone = Lcur; /* Match pointers */
|
|
} else if (nlb < Wbef) /* Count lines buffered */
|
|
nlb++;
|
|
}
|
|
}
|
|
|
|
if (ifnm != NULL) fclose(ifp);
|
|
}
|
|
|
|
/* Shwlin (fnm, linnum, line) Show a matching line
|
|
*
|
|
* Accepts :
|
|
*
|
|
* fnm File name
|
|
*
|
|
* linnum Line number
|
|
*
|
|
* line Line to show
|
|
*
|
|
*
|
|
* Returns :
|
|
*
|
|
*
|
|
*/
|
|
|
|
void shwlin(fnm, linnum, line)
|
|
char *fnm; /* File name */
|
|
int linnum; /* Line number */
|
|
char *line; /* Line (with newline at end) to print */
|
|
|
|
{
|
|
if (Shwfile && (fnm != NULL)) printf("%s%s", fnm, Shwline ? " " : ":");
|
|
if (Shwline) printf("@%05d:", linnum);
|
|
printf("%s", line);
|
|
}
|
|
|
|
/* Matlin (line) Perform match against pattern and line
|
|
*
|
|
* Accepts :
|
|
*
|
|
* line Address of line to match
|
|
*
|
|
*
|
|
* Returns :
|
|
*
|
|
* <value> TRUE if match FALSE if not
|
|
*
|
|
*
|
|
*/
|
|
|
|
|
|
int matlin(line)
|
|
char *line; /* Line to match */
|
|
|
|
{
|
|
int rtncode; /* Return value from this routine */
|
|
|
|
|
|
#ifdef NOREGEXP
|
|
char *pptr, *lptr, *tlptr;
|
|
int c1, c2;
|
|
#endif /* NOREGEXP */
|
|
|
|
if (Debug) printf("Matching %s against %s", Pat, line);
|
|
|
|
#ifdef REGEX
|
|
rtncode = re_exec(line); /* Hand off to r/e evaluator */
|
|
#endif /* REGEX */
|
|
|
|
#ifdef REGCMP
|
|
rtncode = (regexec(Re, line, TRUE) != 0);
|
|
#endif /* REGCMP */
|
|
|
|
#ifdef NOREGEX /* Have to do menial comparison.. */
|
|
lptr = line; /* Init line pointer */
|
|
|
|
for (rtncode = -1; rtncode < 0;) {
|
|
tlptr = lptr++; /* Get temp ptr to line */
|
|
pptr = Pat; /* Get ptr to pattern */
|
|
while (TRUE) {
|
|
if ((c1 = *pptr++) == NUL) {
|
|
rtncode = 1; /* GOOD return value */
|
|
break;
|
|
}
|
|
if ((c2 = *tlptr++) == NUL) {
|
|
rtncode = 0; /* BAD return value */
|
|
break;
|
|
}
|
|
if (isupper(c1)) c1 = tolower(c1);
|
|
if (isupper(c2)) c2 = tolower(c2);
|
|
if (c1 != c2) break;
|
|
}
|
|
}
|
|
#endif /* NOREGEX */
|
|
|
|
|
|
if (Debug) printf("matlin returned %s\n", rtncode ? "TRUE" : "FALSE");
|
|
return(rtncode);
|
|
}
|
|
|
|
|
|
|
|
void regerror(s)
|
|
const char *s;
|
|
{
|
|
printf("%s\n", (char *) s);
|
|
exit(1);
|
|
}
|