[comp.sources.wanted] Need grep with context

kane@urbana.mcd.mot.com (Patrick E Kane) (11/09/89)

Hello,
	I need a version of grep that will print several lines
of context before and after a "hit".

Thanks,
Pat Kane

cpcahil@virtech.uucp (Conor P. Cahill) (11/11/89)

In article <KANE.89Nov8224931@dacapo.urbana.mcd.mot.com>, kane@urbana.mcd.mot.com (Patrick E Kane) writes:
> 	I need a version of grep that will print several lines
> of context before and after a "hit".

use gnu.grep.

-- 
+-----------------------------------------------------------------------+
| Conor P. Cahill     uunet!virtech!cpcahil      	703-430-9247	!
| Virtual Technologies Inc.,    P. O. Box 876,   Sterling, VA 22170     |
+-----------------------------------------------------------------------+

rdr@mdavcr.UUCP (Randolph Roesler) (11/15/89)

[Why don't people put there address (State/Province & Country) in
the subject where requesting software --- I don't like mailing
across North America where a New York request is best handled
from New York.]

A project libarain once requested the same thing, so we
wrote a small script, It worked find, then she added all those
comments, well, it probably still functions......

---------- Cut Here if you wish ------------------------------
#!/bin/sh
#
# wgrep  search file for pattern displaying in context
#
# define usage message here once.  The shell replaces $0 in the string
#  with the name used to invoke the script
#
USAGE="Usage: $0 [ -c# ] pattern file"
#
# construct a unique temporary file name by using the process-id of
#  the shell running the script in the file name.  The shell variable
#  $$ is set to this process-id, and because it will be unique, the
#  temporary file name wil also be unique.  The variable tempfile
#  holes this file name for easy reference throughout the script.
#
tempfile=/tmp/wgrep$$
#
# The shell's trap command specifies what should occur if the specified
#  software signals are sent to the shell process while it is running the
#  script.  The shell allows the signals to be referred to ONLY by
#  number instead of by a symbolic name.  Which numbers are associated
#  with which signals are in the file /usr/include/signal.h
#  The signals which wgrep handles specially are:
#   1 - the modem hanging up
#   2 - interrupt generated by pressing Delete or entering Control-C
#   3 - quit - a Control-\ by default
#  15 - terminate - the standard woftware kill signal usually sent by 
#        the kill command
#  In addition, the shell uses signal number 0 which is not a legal 
#   signal number, to refer to a normal exit from the script.
#  The trap command makes sure that wgrep's temporary file is removed
#   when it exits, so the /tmp directory will be cleansed of
#   previously used, temporary files.
#
trap "/bin/rm -f $tempfile; exit" 0 1 2 3 15
#
# process invocation arguments
#
nlines=1                       
#                                default context is 4 (2 x 2) lines
#
# The case statement takes different actions depending on how many
#  arguments were given to the script (stored in the $# variable).
# Wildcard patterns similar to those used for matching file names 
#  are accepted in the case labels.
# The echo -cut command pipeline divides an argument that looks
#  like -c8 into two parts, the minus sign (-) and the 8, and outputs
#  the number.  This value is then assigned to the nlines variable.
# The shift statement moves what had been n variable $2 to $1 and so on.
#  Thus the statements setting up pattern and filename don't have to be
#  repeated, depending on whether a -cnumber option was given.
#
case $# in
      3) case $1 in
          -c[0-9]*) nlines=`echo $1 | cut -dc -f2` ; shift ;;
                 *) echo $USAGE >&2; exit 1 ;;
         esac ;;
      2) ;;
      *) echo $USAGE >&2; exit 1 ;;
esac
#
# store the pattern argument in $1 and the file name in $2 variables
#
pattern=$1
filename=$2
#
# The grep command returns an exit status of true (0) if it finds a
#  match, and false (nonzero, usually 1) if it doesn't.
#  The exit code is tested with the if command.
#  The -n option causes grep to output the number of each line containing
#  a match before writing out the line.
#  The $pattern argument must be surrouonded by quotes to allow patterns
#  containing spaces and tabs.  The output is saved by redirection into
#  the temporary file.
#
#
#    The number of lines in the file is calculated using the wc command,
#     and the result stored in the variable len.  The file is given to
#     this command from the standard input stream to prevent wc from
#     displaying the file name along with the line count.
#
#
#    The input of the read statement is taken from the output of the cut
#     command, which chops off all of the matched lines except for the
#     line numbers.  The loop executes once for each line in the temporary
#     file.  The read statement returns false when it runs out of input.
#
#                                              loop through all matches
#
#     The tput clear statement clears the user's terminal. The TERM
#      environment variable must be set correctly for the screen clear
#      function to work properly.
#
#      tput clear                 # clear the terminal screen
#
#      The awk program does the bulk of the real work.  The program is
#      enclosed in double quotes instead of the more conventional single
#      quotes so that it can access shell variables used in the surround-
#      ing shell script.  This approach means that \ must be used to
#      quote metacharacters.
#
#      
#      Calculate the first and last lines to be displayed from the input
#       file.  Note the checks to make sure lines with negative numbers
#       or lines past the end of the file are not mistakenly tried to print.
#
#
#       Display the file name and pattern.  The backslashes are 
#       necessary here because the double quote character is special
#       both to the shell and to awk, and we want to display two of
#       them.  Where there are 3 backslashes in a row, the first one
#       prevents the shell from specially interpreting the second one,
#       and the third one prevents the shell from specially inter-
#       preting the following quote character.  The second backslash
#       then prevents ask from specially interpreting the quote character.
#
#
#       These lines actually display the line of the input file containing
#       the match to the pattern and the desired number of lines of context
#       before and after it.  The awk variables NR and $0 contain the line
#       number and input line from the file, respectively.  Note the back-
#       slash preceding $0 prevents the shell from replacing it with the
#       wgrep script file name.
#
if grep -n "$pattern" $filename > $tempfile; then
   len=`wc -l < $filename`       # get length of file
   echo "File: $filename       Pattern: $pattern"
   cut -d: -f1 $tempfile | while read nbr; do
      awk "
      BEGIN {
        begin = $nbr - $nlines;
	if (begin <= 0 ) begin = 1
        end = $nbr + $nlines;
	if (end > $len ) end = $len
      }
      NR == $nbr { 
         printf(\">%5d: %s\\n\",NR,\$0); next
         }
      NR == begin, NR == end {                 
         printf(\"%6d: %s\\n\", NR, \$0) ;
         }
      NR == end {
         exit
         }
         " $filename
#
#          The next line causes the script to wait for the user to press
#          the Return key.  Since the read statement occurs within the
#          while loop that has its input redirected from a pipe, it must
#          have its input specially redirected in order to read from the
#          keyboard.
#          The file /dev/tty is the special file that allows a program to
#          read from the keyboard of its terminal.  When I tried to
#          simply redirect the input of the read statement from /dev/tty
#          my shell quit with an "Illegal redirection" error because the
#          read command of my older Bourne shell didn't allow input
#          redirection.  However, as demonstrated at the top of the while
#          loop, a read statement enclosed within another shell statement
#          can have its input redirected; so I chose the simplest construc-
#          tion, the null-operating grouping symbolized using the braces {}.
#          The semicolon is necessary only to for the read statement on the
#          same line as the closing curly brace.
#
#         { read response; } < /dev/tty   # so can pause
   done | sort +0.1 -0.7 +0.0 -0.1r | sort +0.1 -0.7 -mu
else
   echo "\"$pattern\" pattern not found in file $filename"
fi        
---------- Cut Here if you wish ------------------------------
-- 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
It's not the size of your signature that 	Randy Roesler
counts - it's how you use it!			MacDonald Dettwiler & Assc.
email ...!uunet!van-bc!mdavcr!rdr		BC Canada 604-278-3411

bengsig@oracle.nl (Bjorn Engsig) (11/15/89)

Article <KANE.89Nov8224931@dacapo.urbana.mcd.mot.com> by kane@urbana.mcd.mot.com (Patrick E Kane) says:
|Hello,
|	I need a version of grep that will print several lines
|of context before and after a "hit".
GNU grep posted to comp.sources.unix does this.  It has options -A nnn, -B mmm
to print nnn lines after and mmm lines before the match, and option -C to
mean -A 2 -B 2.  It's also much faster the most normal greps.
-- 
Bjorn Engsig,	Domain:		bengsig@oracle.nl,
		Path:		uunet!mcsun!orcenl!bengsig
		USA Domain:	bengsig@nlsun1.oracle.com

mem@zinn.MV.COM (Mark E. Mallett) (11/19/89)

In article <KANE.89Nov8224931@dacapo.urbana.mcd.mot.com> 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 <stdio.h>
X#include <ctype.h>
X 
X#ifdef	SYSINC
X#include <sys/types.h>
X#include <sys/dir.h>
X#else	/* !SYSINC */
X#include <types.h>
X#include <dir.h>
X#endif	/* SYSINC */
X#endif /* OS_UNIX */
X
X#ifdef	OS_MSDOS
X#include <stdio.h>
X#include <ctype.h>
X#include <dos.h>
X#ifdef	CC_POWERC
X#include <direct.h>
X#else
X#ifdef	SYSINC
X#include <sys/types.h>
X#else	/* !SYSINC */
X#include <types.h>
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        <value>         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

djm@eng.umd.edu (David J. MacKenzie) (11/19/89)

Get GNU grep.  Besides being the world's fastest, it can print context.
--
David J. MacKenzie <djm@eng.umd.edu>