Path: utzoo!mnetor!tmsoft!torsqnt!jarvis.csri.toronto.edu!rutgers!ucsd!swrinde!cs.utexas.edu!samsung!uakari.primate.wisc.edu!dogie.macc.wisc.edu!decwrl!crltrx!decvax!zinn!mem From: mem@zinn.MV.COM (Mark E. Mallett) Newsgroups: comp.sources.wanted Subject: Re: Need grep with context Message-ID: <652@zinn.MV.COM> Date: 18 Nov 89 23:25:03 GMT References: Reply-To: mem@zinn.MV.COM (Mark E. Mallett) Distribution: comp Organization: Zinn Computer Co., Litchfield NH Lines: 689 In article kane@urbana.mcd.mot.com (Patrick E Kane) writes: >Hello, > I need a version of grep that will print several lines >of context before and after a "hit". > >Thanks, >Pat Kane I wrote this a long time ago for CP/M, and although it's ugly, it's short and runs on a number of different systems (including CP/M, MSDOS, BSD, and SysV). I still use it. I am also sending it via email to Pat Kane, but figure it's short enough to post here. -mm- -------------------- #!/bin/sh # shar: Shell Archiver (v1.22) # # Run the following text with /bin/sh to create: # Makefile # README # wns.1 # wns.c # sed 's/^X//' << 'SHAR_EOF' > Makefile && X# Makefile for wns X# X# Define in CFLAGS: X# SYSINC if include file hierarchy includes the sys/ directory X# REGEX if using berkeley-style re_exec() and re_comp() X# REGCMP if using regcmp() and regex() X# OS_UNIX if running under unix X# OS_CPM if running under CP/M-80 X# OS_MSDOS if running under MSDOS X# CC_POWERC if your MSDOS compiler is MIX Power C X# X# XCFLAGS=-DOS_UNIX -DREGCMP -DSYSINC X# X# Define LIBS to reflect the librar[y][ies] needed to fetch the r/e routines. X# XLIBS=-lPW X X# XWNSOBJS=wns.o X Xwns: $(WNSOBJS) X cc -o wns $(WNSOBJS) $(LIBS) SHAR_EOF chmod 0640 Makefile || echo "restore of Makefile fails" sed 's/^X//' << 'SHAR_EOF' > README && Xwns - Windowing Search Mark E. Mallett (mem@zinn.MV.COM) X XThis is a program to search for occurances of a pattern in a text file, and Xprint a window of lines around (before and after) each match point. The Xsize of the window is specified on the command line. X XThis is one of my earliest C programs, so don't be too critical of the Ximplementation. It was originally written on a CP/M system and later Xmoved to other environments (such as unix). X XAs for installation - there is not much to explain. The Makefile and the Xmanual source should be enough. X X-mm- XApril 19, 1988 SHAR_EOF chmod 0640 README || echo "restore of README fails" sed 's/^X//' << 'SHAR_EOF' > wns.1 && X.TH WNS 1 X.SH NAME Xwns \- windowing search X.SH SYNOPSIS X.B wns X[-a nnn] X[-b nnn] X[-l nnn] X[-w nnn] Xpattern X[file ... ] X.SH DESCRIPTION X.I wns Xsearches through a file or list of files for occurances of a particular Xpattern, and prints a window of lines around each match point. X.PP XOptions which may be given are as follows: X.TP X.B \-a\ nnn X(After) specifies that nnn lines following the matching line will be Xprinted. default is 0. X.TP X.B \-b\ nnn X(Before) specifies that nnn lines preceding the matching line will be Xprinted. default is 0. X.TP X.B \-d XEnables debugging information. Not a very interesting option. X.TP X.B \-f XSuppress printing of the filename on each output line. X.TP X.B \-l\ nnn XSets the maximum line length to nnn. Lines longer than this will be Xtruncated to this length before attempting to match them to the pattern as Xwell as when printing them. Default is 100. X.TP X.B \-n XSuppress printing of the line number on each output line. X.TP X.B \-w\ nnn XSets the window size to nnn. This is the same as -a nnn -b nnn. X.PP X.I wns Xoutputs lines in the following format: X.PP Xfilename @nnnnn: text X.PP Xwhere X.I filename Xis the name of the file containing the matching text and may be suppressed Xwith the -f option, X.I lnnnn Xis the line number of the displayed line and may be suppressed with the X-n option, and X.I text Xis the line from the file. XAdditionally, if the total window size is greater than 1 (that is, more than Xzero lines before or after), then non-adjacent text areas are separated by Xa short dashed line. X.SH FILES X/usr/local/bin/wns /usr/local/src/wns/* X.SH "CREDITS TO" XM. Mallett (mem@zinn.MV.COM) X.SH BUGS XYou tell me.. SHAR_EOF chmod 0640 wns.1 || echo "restore of wns.1 fails" sed 's/^X//' << 'SHAR_EOF' > wns.c && X/* wns.c - Search for string and print window of lines around it. X X Nov 19 1984 Mark Mallett (mem@zinn.MV.COM) X Xmem 860224 Modified to do r/e (regular expression) parsing on unix Xmem 860324 Added -f, -n; added code to number lines correctly on X output. Xmem 870325 Added support for regcmp()/regex() style regular expression X library; redid some conditionals to provide better mix'n'match. Xmem 870326 Don't try to print the filename if reading from stdin. X Add -w option. Fix a small problem which occasionally allowed X the separator to come out between adjacent lines of the file. Xmem 871119 Fix semantics of call to regcmp(): the NULL terminating the X argument list was missing. It worked, but probably only X due to some bizarre coincidence. Xmem 880518 Add MSDOS support, including wildcard filename expansion. Xmem 880716 Add Power C (MSDOS) stuff. X Change #endif's to conform to newer style rules (ugh). X*/ X X/* The appropriate defines are done in the makefile */ X/* #define OS_UNIX */ /* Define this for unix systems */ X/* #define SYSINC */ /* Define this for sys/ include hierarchy */ X/* #define REGEX */ /* Define this for re_comp/re_exec library */ X/* #define REGCMP */ /* Define this to use regcmp/regex */ X/* #define OS_CPM */ /* Define this for CP/M-80 */ X/* #define OS_MSDOS */ /* Define this for MSDOS */ X/* #define CC_POWERC */ /* For the MIX Power C compiler */ X X X/* Don't touch these */ X#define NOREGEXP /* Set this for no regular expression */ X#ifdef REGEX X#undef NOREGEXP X#endif /* REGEX */ X X#ifdef REGCMP X#undef NOREGEXP X#endif /* REGCMP */ X X X#ifdef OS_CPM X#include "stdio.h" X#include "ctype.h" X#endif /* OS_CPM */ X X#ifdef OS_UNIX X#include X#include X X#ifdef SYSINC X#include X#include X#else /* !SYSINC */ X#include X#include X#endif /* SYSINC */ X#endif /* OS_UNIX */ X X#ifdef OS_MSDOS X#include X#include X#include X#ifdef CC_POWERC X#include X#else X#ifdef SYSINC X#include X#else /* !SYSINC */ X#include X#endif /* SYSINC */ X#endif /* CC_POWERC */ X#endif /* OS_MSDOS */ X X/* Local definitions */ X X#ifndef NULL X#define NULL ((char *)0) X#endif /* NULL */ X X#ifndef NUL X#define NUL '\000' X#endif /* NUL */ X X#ifndef TRUE X#define TRUE 1 X#define FALSE 0 X#endif /* TRUE */ X X X/* Internal data declared global */ X X X/* Internal routines */ X X X/* External data */ X X X/* External routines */ X X#ifdef REGEX /* re_comp/ re_exec */ Xextern char *re_comp(); /* r/e compile */ Xextern int re_exec(); /* r/e exec */ X#endif /* REGEX */ X X#ifdef REGCMP /* regcmp/regex */ Xextern char *regcmp(); /* r/e compile */ Xextern char *regex(); /* r/e exec */ X#endif /* REGCMP */ X X X/* Local data */ X Xstatic int Debug={FALSE}; /* Debug enabled flag */ Xstatic int Lcur = {0}; /* Current line (in Lines array) */ Xstatic char **Lines = {(char **)NULL}; /* Lines pointer array */ Xstatic int Linlen = {100}; /* Line length */ Xstatic int Lone = {0}; /* Line one (in Lines array) */ Xstatic int Nmr = {0}; /* Number of matched regions */ Xstatic char *Pat = {NULL}; /* Pattern */ Xstatic char Shwfile = {TRUE}; /* Show file name... */ Xstatic char Shwline = {TRUE}; /* Show line number */ Xstatic int Waft = {0}; /* Window after */ Xstatic int Wbef = {0}; /* Window before */ Xstatic int Wsiz = {0}; /* Window size */ X X#ifdef REGEX /* regex style r/e manipulations */ Xchar *Re; /* Result from re_comp() */ X#endif /* REGEX */ X X#ifdef REGCMP /* regcmp style r/e */ Xchar *Re; /* Result from regcmp() */ X#endif /* REGCMP */ X X Xmain (argc, argv) X Xint argc; /* Argument count */ Xchar **argv; /* Argument values */ X X{ Xint i; /* Scratch */ Xint n; /* Scratch again */ Xint c; /* A character */ Xchar *aptr; /* Argument pointer */ Xint nf; /* number of files on command line */ X Xnf = 0; /* No files on line */ X Xfor (i = 1; i < argc; i++) /* Look at args */ X { X if (argv[i][0] != '-') /* If option */ X { X if (Pat == NULL) /* If no pattern yet given */ X { X Pat = argv[i]; /* point here */ X#ifdef REGEX X if ((Re = re_comp(Pat)) != NULL) X { X fprintf(stderr, "wns: %s\n", Re); X exit(1); X } X#endif /* REGEX */ X X#ifdef REGCMP X if ((Re = regcmp(Pat, NULL)) == NULL) X { X fprintf(stderr, "wns: error in regular expression.\n"); X exit(1); X } X#endif /* REGCMP */ X X } X else /* This must be a file to search */ X { X nf++; /* Count it */ X#ifdef OS_MSDOS X mswildsrch( argv[i] ); X#else X dosrch (argv[i]); /* Search */ X#endif /* OS_MSDOS */ X } X } X X else /* Option char */ X { X c = argv[i][1]; /* Get option char */ X if (isupper(c)) /* Trap idiot definition of tolower */ X c = tolower(c); /* Don't care about case */ X n = i; X aptr = NULL; /* Find arg, if any */ X if (argv[i][2] != NUL) X { X aptr = &argv[i][2]; X n = i; /* Where to set i if we use this arg */ X } X else if (i < argc-1) /* use next.. */ X { X n = i+1; X aptr = argv[n]; X } X X switch (c) /* Process the option */ X { X case 'a': /* Lines after */ X Waft = atoi (aptr); X Lines = NULL; X i = n; X break; X X case 'b': /* Lines before */ X Wbef = atoi (aptr); X Lines = (char **)NULL; X i = n; X break; X X case 'd': /* Enable debugging */ X Debug = TRUE; X break; X X case 'f': /* Suppress filename on output */ X Shwfile = FALSE; X break; X X case 'l': /* Line length */ X Linlen = atoi (aptr); X Lines = NULL; X i = n; X break; X X case 'n': /* Suppress line number on output */ X Shwline = FALSE; X break; X X case 'w': /* Window: lines before and after */ X Waft = Wbef = atoi (aptr); X Lines = NULL; X i = n; X break; X X default: X fprintf (stderr, "Invalid option %s\n",argv[i]); X exit(); X } X } X } X Xif ( Pat == NULL ) /* If no pattern given */ X { X fprintf(stderr, X"usage: wns [-a n] [-b n] [-d] [-f] [-l n] [-n] [-w n] pattern [filename... ]\n"); X exit(1); X } X Xif (nf == 0) /* No files processed ? */ X dosrch (NULL); /* Do standard input */ X} X/* X X*//* mswildsrch( ifnm ) X X Wildcard file search, for MS_DOS. X XAccepts : X X ifnm Name (possibly wildcarded) of file X XReturns : X X < dosrch called for each matching file > X X*/ X X#ifdef OS_MSDOS Xmswildsrch( ifnm ) X char *ifnm; X{ X int i; X int sts; X#ifdef CC_POWERC X struct ffblk eachfile; X#else X struct find_t eachfile; X#endif /* CC_POWERC */ X char path[100]; X char fullname[100]; X X/* Stupid MSDOS -- first find the drive-directory part of the X filename. */ Xpath[0] = NUL; Xfor( i = strlen( ifnm )-1; i >= 0; --i ) X if ( ( ifnm[i] == ':' ) || ( ifnm[i] == '\\' ) ) X { X strncpy( &path[0], ifnm, ++i ); X path[i] = NUL; X break; X } X X X#ifdef CC_POWERC Xif ( ( sts = findfirst( ifnm, &eachfile, FA_NORMAL ) ) != 0 ) X#else Xif ( ( sts = _dos_findfirst( ifnm, _A_NORMAL, &eachfile ) ) != 0 ) X#endif /* CC_POWERC */ X { X fprintf( stderr, "No such file: %s\n", ifnm ); X return; X } X Xwhile( sts == 0 ) X { X#ifdef CC_POWERC X sprintf( &fullname[0], "%s%s", &path[0], &eachfile.ff_name[0] ); X sts = findnext( &eachfile ); X#else X sprintf( &fullname[0], "%s%s", &path[0], &eachfile.name[0] ); X sts = _dos_findnext( &eachfile ); X#endif /* CC_POWERC */ X X dosrch( &fullname[0] ); X } X} X#endif /* OS_MSDOS */ X/* X X*//* dosrch (ifnm) X X Perform the search X XAccepts : X X ifn Input file name X X XReturns : X X X*/ X Xdosrch (ifnm) X Xchar *ifnm; /* Input filelname */ X X{ XFILE *ifp; /* Input fp */ Xchar *lptr; /* Line pointer */ Xint i; /* Scratch */ Xint prtaft; /* Print-after count */ Xint linnum; /* Line number */ Xint nlb; /* Number of lines buffered */ X Xif (ifnm != NULL) /* If file name given */ X { X ifp = fopen (ifnm, "r"); /* Open it for read access */ X if (ifp == NULL) X { X fprintf (stderr, "Can not open file %s\n", ifnm); X return; X } X } Xelse X ifp = stdin; X Xif (Lines == NULL) /* If no line table allocated.. */ X { X Wsiz = Wbef+2; /* Determine total window size */ X Lines = (char **) calloc (Wsiz, sizeof (char *)); X /* Allocate pointer table */ X for (i = 0; i < Wsiz; i++) /* Allocate line buffers */ X Lines[i] = (char *) calloc (Linlen, sizeof(char)); X } X XLcur = Lone = 0; /* Setup line pointers */ Xnlb = 0; /* No lines buffered */ Xlinnum = 0; /* Line number is zero */ Xprtaft = -(Wbef+1); /* Make sure separator given first time */ X Xfor (;;) /* Loop through the file */ X { X lptr = Lines[Lcur]; /* Get pointer to current line */ X if (++Lcur == Wsiz) /* Bump curr pointer and wrap */ X Lcur = 0; /* if hit end */ X if (Lone == Lcur) /* If wrapped to beginning of window */ X if (++Lone == Wsiz) /* Bump beginning */ X Lone = 0; /* and wrap if hit end */ X X if (fgets (lptr, Linlen, ifp) != lptr) X break; /* if end of file */ X X linnum++; /* Count line number */ X if (matlin (lptr)) /* If matching line */ X { X if (prtaft < (-Wbef) ) /* Check for separator needed */ X if ( (Nmr++ > 0 ) && ((Wbef > 0) || (Waft > 0)) ) X printf ("-------------------\n"); X while (Lone != Lcur) /* Until we close the window */ X { X shwlin (ifnm, linnum-nlb, Lines[Lone]); X /* Show the line */ X if (++Lone == Wsiz) X Lone = 0; X nlb--; X } X nlb = 0; /* No lines buffered */ X prtaft = Waft; /* Print n lines after */ X } X X else /* Didn't match */ X { X if (prtaft-- > 0) /* If must print lines after */ X { X shwlin (ifnm, linnum, lptr); X /* Show the line */ X Lone = Lcur; /* Match pointers */ X } X else if (nlb < Wbef) /* Count lines buffered */ X nlb++; X } X } X Xif (ifnm != NULL) X fclose (ifp); X} X/* X X*//* shwlin (fnm, linnum, line) X X Show a matching line X X XAccepts : X X fnm File name X X linnum Line number X X line Line to show X X XReturns : X X X*/ X Xshwlin (fnm, linnum, line) X Xchar *fnm; /* File name */ Xint linnum; /* Line number */ Xchar *line; /* Line (with newline at end) to print */ X X{ Xif (Shwfile && ( fnm != NULL) ) X printf("%s%s", fnm, Shwline?" ":":"); Xif (Shwline) X printf("@%05d%:", linnum); Xprintf ("%s", line); X} X/* X X*//* matlin (line) X X Perform match against pattern and line X X XAccepts : X X line Address of line to match X X XReturns : X X TRUE if match X FALSE if not X X X*/ X X Xint matlin (line) X Xchar *line; /* Line to match */ X X{ Xint rtncode; /* Return value from this routine */ X X X#ifdef NOREGEXP Xchar *pptr, *lptr, *tlptr; Xint c1,c2; X#endif /* NOREGEXP */ X Xif (Debug) X printf ("Matching %s against %s", Pat, line); X X#ifdef REGEX Xrtncode = re_exec(line); /* Hand off to r/e evaluator */ X#endif /* REGEX */ X X#ifdef REGCMP Xrtncode = ( regex( Re, line ) != NULL ); X#endif /* REGCMP */ X X#ifdef NOREGEXP /* Have to do menial comparison.. */ Xlptr = line; /* Init line pointer */ X Xfor ( rtncode = -1; rtncode < 0; ) X { X tlptr = lptr++; /* Get temp ptr to line */ X pptr = Pat; /* Get ptr to pattern */ X for( ; ; ) X { X if ((c1 = *pptr++) == NUL) X { X rtncode = 1; /* GOOD return value */ X break; X } X if ((c2 = *tlptr++) == NUL) X { X rtncode = 0; /* BAD return value */ X break; X } X if (isupper(c1)) X c1 = tolower(c1); X if (isupper(c2)) X c2 = tolower(c2); X if (c1 != c2) X break; X } X } X#endif /* NOREGEXP */ X X Xif (Debug) X printf("matlin returned %s\n", rtncode?"TRUE":"FALSE"); Xreturn(rtncode); X} X X X SHAR_EOF chmod 0640 wns.c || echo "restore of wns.c fails" exit 0 -- Mark E. Mallett Zinn Computer Co/ PO Box 4188/ Manchester NH/ 03103 Bus. Phone: 603 645 5069 Home: 603 424 8129 BIX: mmallett uucp: mem@zinn.MV.COM ( ...{decvax|elrond|harvard}!zinn!mem ) Northern MA and Southern NH consultants: Ask (in mail!) about MV.COM