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);
 | 
						|
}
 |