380 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			380 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| /* 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);
 | |
| }
 | 
