home *** CD-ROM | disk | FTP | other *** search
- Subject: v15i082: Windowing search (not unlike context grep)
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: "Mark E. Mallett" <mem@zinn.mv.com>
- Posting-number: Volume 15, Issue 82
- Archive-name: window-srch
-
- I got a few requests for this, and I figured I'd mail it to you for your
- consideration for posting in comp.sources.unix (or wherever it is appropriate).
- It is a short little program that allows one to find an occurance of a pattern
- in a text file, and print a window of lines around the match point(s).
-
- -mm-
- --
- Mark E. Mallett PO Box 4188/ Manchester NH/ 03103
- Bus. Phone: 603 645 5069 Home: 603 424 8129
- uucp: mem@zinn.MV.COM (...decvax!elrond!zinn!mem or ...sii!zinn!mem)
- BIX: mmallett
-
- #------ cut here -------
- #! /bin/sh
- #
- # This is a shell archive; feed it to /bin/sh (not csh) to create:
- # Makefile
- # README
- # wns.1
- # wns.c
- if test -f 'Makefile'; then
- echo shar: will not over-write existing file 'Makefile'
- else
- sed -e 's/^@//g' << 'SHAR_EOF' > Makefile
- @# Makefile for wns
- @#
- @# Define in CFLAGS:
- @# SYSINC if include file hierarchy includes the sys/ directory
- @# REGEX if using berkeley-style re_exec() and re_comp()
- @# REGCMP if using regcmp() and regex()
- @# OS_UNIX if running under unix
- @# OS_CPM if running under CP/M80
- @#
- @#
- @CFLAGS=-DOS_UNIX -DREGCMP -DSYSINC
- @#
- @# Define LIBS to reflect the librar[y][ies] needed to fetch the r/e routines.
- @#
- @LIBS=-lPW
- @
- @#
- @WNSOBJS=wns.o
- @
- @wns: $(WNSOBJS)
- @ cc -o wns $(WNSOBJS) $(LIBS)
- SHAR_EOF
- fi
- if test -f 'README'; then
- echo shar: will not over-write existing file 'README'
- else
- sed -e 's/^@//g' << 'SHAR_EOF' > README
- @wns - Windowing Search Mark E. Mallett (mem@zinn.MV.COM)
- @
- @This is a program to search for occurances of a pattern in a text file, and
- @print a window of lines around (before and after) each match point. The
- @size of the window is specified on the command line.
- @
- @This is one of my earliest C programs, so don't be too critical of the
- @implementation. It was originally written on a CP/M system and later
- @moved to other environments (such as unix).
- @
- @As for installation - there is not much to explain. The Makefile and the
- @manual source should be enough.
- @
- @-mm-
- @April 19, 1988
- SHAR_EOF
- fi
- if test -f 'wns.1'; then
- echo shar: will not over-write existing file 'wns.1'
- else
- sed -e 's/^@//g' << 'SHAR_EOF' > wns.1
- @.TH WNS 1
- @.SH NAME
- @wns \- windowing search
- @.SH SYNOPSIS
- @.B wns
- @[-a nnn]
- @[-b nnn]
- @[-l nnn]
- @[-w nnn]
- @pattern
- @[file ... ]
- @.SH DESCRIPTION
- @.I wns
- @searches through a file or list of files for occurances of a particular
- @pattern, and prints a window of lines around each match point.
- @.PP
- @Options which may be given are as follows:
- @.TP
- @.B \-a\ nnn
- @(After) specifies that nnn lines following the matching line will be
- @printed. default is 0.
- @.TP
- @.B \-b\ nnn
- @(Before) specifies that nnn lines preceding the matching line will be
- @printed. default is 0.
- @.TP
- @.B \-d
- @Enables debugging information. Not a very interesting option.
- @.TP
- @.B \-f
- @Suppress printing of the filename on each output line.
- @.TP
- @.B \-l\ nnn
- @Sets the maximum line length to nnn. Lines longer than this will be
- @truncated to this length before attempting to match them to the pattern as
- @well as when printing them. Default is 100.
- @.TP
- @.B \-n
- @Suppress printing of the line number on each output line.
- @.TP
- @.B \-w\ nnn
- @Sets the window size to nnn. This is the same as -a nnn -b nnn.
- @.PP
- @.I wns
- @outputs lines in the following format:
- @.PP
- @filename @nnnnn: text
- @.PP
- @where
- @.I filename
- @is the name of the file containing the matching text and may be suppressed
- @with the -f option,
- @.I lnnnn
- @is the line number of the displayed line and may be suppressed with the
- @-n option, and
- @.I text
- @is the line from the file.
- @Additionally, if the total window size is greater than 1 (that is, more than
- @zero lines before or after), then non-adjacent text areas are separated by
- @a short dashed line.
- @.SH FILES
- @/usr/local/bin/wns /usr/local/src/wns/*
- @.SH "CREDITS TO"
- @M. Mallett (mem@zinn.MV.COM)
- @.SH BUGS
- @You tell me..
- SHAR_EOF
- fi
- if test -f 'wns.c'; then
- echo shar: will not over-write existing file 'wns.c'
- else
- awk << 'SHAR_EOF' > wns.c \
- '{\
- n=split($0,f,"@");\
- n=f[1];\
- while(n>=4){printf(" ");n=n-4}\
- while(n>=1){printf(" ");--n}\
- printf("%s\n",substr($0,length(f[1])+2,length))\
- }'
- @/* wns.c - Search for string and print window of lines around it.
-
- 8@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.
-
- @*/
-
- @/* The appropriate defines are done in the makefile */
- @/* #define OS_UNIX */ /* Define this for unix systems */
- @/* #define SYSINC */ /* Define this for sys/ include hierarchy */
- @/* #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 <stdio.h>
- @#include <ctype.h>
-
- @#ifdef SYSINC
- @#include <sys/types.h>
- @#include <sys/dir.h>
- @#else /* !SYSINC */
- @#include <types.h>
- @#include <dir.h>
- @#endif SYSINC
- @#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 */
-
-
- @/* External data */
-
-
- @/* External routines */
-
- @#ifdef REGEX /* re_comp/ re_exec */
- @extern char *re_comp(); /* r/e compile */
- @extern int re_exec(); /* r/e exec */
- @#endif REGEX
-
- @#ifdef REGCMP /* regcmp/regex */
- @extern char *regcmp(); /* r/e compile */
- @extern char *regex(); /* r/e exec */
- @#endif REGCMP
-
-
- @/* Local data */
-
- @static int Debug={FALSE}; /* Debug enabled flag */
- @static int Lcur = {0}; /* Current line (in Lines array) */
- @static char **Lines = {(char **)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 */
-
- @#ifdef REGEX /* regex style r/e manipulations */
- @char *Re; /* Result from re_comp() */
- @#endif REGEX
-
- @#ifdef REGCMP /* regcmp style r/e */
- @char *Re; /* Result from regcmp() */
- @#endif REGCMP
-
-
- @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 */
- 4@{
- 4@if (argv[i][0] != '-') /* If option */
- 8@{
- 8@if (Pat == NULL) /* If no pattern yet given */
- @ {
- 12@Pat = argv[i]; /* point here */
- @#ifdef REGEX
- @ if ((Re = re_comp(Pat)) != NULL)
- @ {
- @ fprintf(stderr, "wns: %s\n", re);
- @ exit(1);
- @ }
- @#endif REGEX
-
- @#ifdef REGCMP
- @ if ((Re = regcmp(Pat, NULL)) == NULL)
- @ {
- @ fprintf(stderr, "wns: error in regular expression.\n");
- @ exit(1);
- @ }
- @#endif REGCMP
-
- @ }
- 8@else /* This must be a file to search */
- 12@{
- 12@nf++; /* Count it */
- 12@dosrch (argv[i]); /* Search */
- 12@}
- 8@}
-
- 4@else /* Option char */
- 8@{
- 8@c = argv[i][1]; /* Get option char */
- 8@if (isupper(c)) /* Trap idiot definition of tolower */
- 12@c = tolower(c); /* Don't care about case */
- 8@n = i;
- 8@aptr = NULL; /* Find arg, if any */
- 8@if (argv[i][2] != NUL)
- 12@{
- 12@aptr = &argv[i][2];
- 12@n = i; /* Where to set i if we use this arg */
- 12@}
- 8@else if (i < argc-1) /* use next.. */
- 12@{
- 12@n = i+1;
- 12@aptr = argv[n];
- 12@}
-
- 8@switch (c) /* Process the option */
- 12@{
- 12@case 'a': /* Lines after */
- 16@Waft = atoi (aptr);
- 16@Lines = NULL;
- 16@i = n;
- 16@break;
-
- 12@case 'b': /* Lines before */
- 16@Wbef = atoi (aptr);
- 16@Lines = (char **)NULL;
- 16@i = n;
- 16@break;
-
- 12@case 'd': /* Enable debugging */
- 16@Debug = TRUE;
- 16@break;
-
- @ case 'f': /* Suppress filename on output */
- @ Shwfile = FALSE;
- @ break;
-
- 12@case 'l': /* Line length */
- 16@Linlen = atoi (aptr);
- 16@Lines = NULL;
- 16@i = n;
- 16@break;
-
- @ case 'n': /* Suppress line number on output */
- @ Shwline = FALSE;
- @ break;
-
- 12@case 'w': /* Window: lines before and after */
- 16@Waft = Wbef = atoi (aptr);
- 16@Lines = NULL;
- 16@i = n;
- 16@break;
-
- 12@default:
- 16@fprintf (stderr, "Invalid option %s\n",argv[i]);
- 16@exit();
- 12@}
- 8@}
- 4@}
-
- @if ( Pat == NULL ) /* If no pattern given */
- 4@{
- 4@fprintf(stderr,
- @"usage: wns [-a n] [-b n] [-d] [-f] [-l n] [-n] [-w n] pattern [filename... ]\n");
- 4@exit(1);
- 4@}
-
- @if (nf == 0) /* No files processed ? */
- 4@dosrch (NULL); /* Do standard input */
- @}
- @/*
- @
- @*//* dosrch (ifnm)
-
- 8@Perform the search
-
- @Accepts :
-
- 8@ifn Input file name
-
-
- @Returns :
-
-
- @*/
-
- @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 */
- 4@{
- 4@ifp = fopen (ifnm, "r"); /* Open it for read access */
- 4@if (ifp == NULL)
- 8@{
- 8@fprintf (stderr, "Can not open file %s\n", ifnm);
- 8@return;
- 8@}
- 4@}
- @else
- 4@ifp = stdin;
-
- @if (Lines == NULL) /* If no line table allocated.. */
- 4@{
- 4@Wsiz = Wbef+2; /* Determine total window size */
- 4@Lines = (char **) calloc (Wsiz, sizeof (char *));
- 32@/* Allocate pointer table */
- 4@for (i = 0; i < Wsiz; i++) /* Allocate line buffers */
- 8@Lines[i] = (char *) calloc (Linlen, sizeof(char));
- 4@}
-
- @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 */
- 4@{
- 4@lptr = Lines[Lcur]; /* Get pointer to current line */
- 4@if (++Lcur == Wsiz) /* Bump curr pointer and wrap */
- 8@Lcur = 0; /* if hit end */
- 4@if (Lone == Lcur) /* If wrapped to beginning of window */
- 8@if (++Lone == Wsiz) /* Bump beginning */
- 12@Lone = 0; /* and wrap if hit end */
-
- 4@if (fgets (lptr, Linlen, ifp) != lptr)
- 8@break; /* if end of file */
-
- 4@linnum++; /* Count line number */
- 4@if (matlin (lptr)) /* If matching line */
- 8@{
- 8@if (prtaft < (-Wbef) ) /* Check for separator needed */
- 12@if ( (Nmr++ > 0 ) && ((Wbef > 0) || (Waft > 0)) )
- 16@printf ("-------------------\n");
- 8@while (Lone != Lcur) /* Until we close the window */
- 12@{
- 12@shwlin (ifnm, linnum-nlb, Lines[Lone]);
- 32@/* Show the line */
- 12@if (++Lone == Wsiz)
- 16@Lone = 0;
- @ nlb--;
- 12@}
- @ nlb = 0; /* No lines buffered */
- 8@prtaft = Waft; /* Print n lines after */
- 8@}
-
- 4@else /* Didn't match */
- 8@{
- 8@if (prtaft-- > 0) /* If must print lines after */
- 12@{
- 12@shwlin (ifnm, linnum, lptr);
- 32@/* Show the line */
- 12@Lone = Lcur; /* Match pointers */
- 12@}
- @ else if (nlb < Wbef) /* Count lines buffered */
- @ nlb++;
- 8@}
- 4@}
-
- @if (ifnm != NULL)
- 4@fclose (ifp);
- @}
- @/*
- @
- @*//* shwlin (fnm, linnum, line)
-
- 8@Show a matching line
-
-
- @Accepts :
-
- 8@fnm File name
-
- 8@linnum Line number
-
- 8@line Line to show
-
-
- @Returns :
-
-
- @*/
-
- @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) )
- 4@printf("%s%s", fnm, Shwline?" ":":");
- @if (Shwline)
- 4@printf("@%05d%:", linnum);
- @printf ("%s", line);
- @}
- @/*
- @
- @*//* matlin (line)
-
- 8@Perform match against pattern and line
-
-
- @Accepts :
-
- 8@line Address of line to match
-
-
- @Returns :
-
- 8@<value> TRUE if match
- 24@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)
- 4@printf ("Matching %s against %s", Pat, line);
-
- @#ifdef REGEX
- @rtncode = re_exec(line); /* Hand off to r/e evaluator */
- @#endif REGEX
-
- @#ifdef REGCMP
- @rtncode = ( regex( Re, line ) != NULL );
- @#endif REGCMP
-
- @#ifdef NOREGEX /* Have to do menial comparison.. */
- @lptr = line; /* Init line pointer */
-
- @for ( rtncode = -1; rtncode < 0; )
- 4@{
- 4@tlptr = lptr++; /* Get temp ptr to line */
- 4@pptr = Pat; /* Get ptr to pattern */
- 4@while (TRUE)
- 8@{
- 8@if ((c1 = *pptr++) == NUL)
- 12@{
- @ rtncode = 1; /* GOOD return value */
- @ break;
- 12@}
- 8@if ((c2 = *tlptr++) == NUL)
- 12@{
- @ rtncode = 0; /* BAD return value */
- @ break;
- 12@}
- 8@if (isupper(c1))
- 12@c1 = tolower(c1);
- 8@if (isupper(c2))
- 12@c2 = tolower(c2);
- 8@if (c1 != c2)
- 12@break;
- 8@}
- 4@}
- @#endif NOREGEX
-
-
- @if (Debug)
- 4@printf("matlin returned %s\n", rtncode?"TRUE":"FALSE");
- @return(rtncode);
- @}
-
-
- SHAR_EOF
- fi
-
-