home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume15 / window-srch < prev    next >
Text File  |  1988-07-06  |  15KB  |  615 lines

  1. Subject:  v15i082:  Windowing search (not unlike context grep)
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: "Mark E. Mallett" <mem@zinn.mv.com>
  7. Posting-number: Volume 15, Issue 82
  8. Archive-name: window-srch
  9.  
  10. I got a few requests for this, and I figured I'd mail it to you for your
  11. consideration for posting in comp.sources.unix (or wherever it is appropriate).
  12. It is a short little program that allows one to find an occurance of a pattern
  13. in a text file, and print a window of lines around the match point(s).
  14.  
  15. -mm-
  16. --
  17. Mark E. Mallett  PO Box 4188/ Manchester NH/ 03103 
  18. Bus. Phone: 603 645 5069    Home: 603 424 8129
  19. uucp: mem@zinn.MV.COM  (...decvax!elrond!zinn!mem   or   ...sii!zinn!mem)
  20. BIX: mmallett
  21.  
  22. #------ cut here -------
  23. #! /bin/sh
  24. #
  25. # This is a shell archive; feed it to /bin/sh (not csh) to create:
  26. #   Makefile
  27. #   README
  28. #   wns.1
  29. #   wns.c
  30. if test -f 'Makefile'; then
  31.     echo shar: will not over-write existing file 'Makefile'
  32. else
  33. sed -e 's/^@//g' << 'SHAR_EOF' > Makefile
  34. @# Makefile for wns
  35. @#
  36. @# Define in CFLAGS:
  37. @#    SYSINC    if include file hierarchy includes the sys/ directory
  38. @#    REGEX    if using berkeley-style re_exec() and re_comp()
  39. @#    REGCMP    if using regcmp() and regex()
  40. @#    OS_UNIX if running under unix
  41. @#    OS_CPM    if running under CP/M80
  42. @#
  43. @#
  44. @CFLAGS=-DOS_UNIX -DREGCMP -DSYSINC
  45. @#
  46. @# Define LIBS to reflect the librar[y][ies] needed to fetch the r/e routines.
  47. @#
  48. @LIBS=-lPW
  49. @
  50. @#
  51. @WNSOBJS=wns.o
  52. @
  53. @wns:    $(WNSOBJS)
  54. @    cc -o wns $(WNSOBJS) $(LIBS)
  55. SHAR_EOF
  56. fi
  57. if test -f 'README'; then
  58.     echo shar: will not over-write existing file 'README'
  59. else
  60. sed -e 's/^@//g' << 'SHAR_EOF' > README
  61. @wns - Windowing Search        Mark E. Mallett   (mem@zinn.MV.COM)
  62. @
  63. @This is a program to search for occurances of a pattern in a text file, and
  64. @print a window of lines around (before and after) each match point.  The
  65. @size of the window is specified on the command line.
  66. @
  67. @This is one of my earliest C programs, so don't be too critical of the
  68. @implementation.  It was originally written on a CP/M system and later
  69. @moved to other environments (such as unix).
  70. @
  71. @As for installation - there is not much to explain.  The Makefile and the
  72. @manual source should be enough.
  73. @
  74. @-mm-
  75. @April 19, 1988
  76. SHAR_EOF
  77. fi
  78. if test -f 'wns.1'; then
  79.     echo shar: will not over-write existing file 'wns.1'
  80. else
  81. sed -e 's/^@//g' << 'SHAR_EOF' > wns.1
  82. @.TH WNS 1
  83. @.SH NAME
  84. @wns \- windowing search
  85. @.SH SYNOPSIS
  86. @.B wns
  87. @[-a nnn]
  88. @[-b nnn]
  89. @[-l nnn]
  90. @[-w nnn]
  91. @pattern
  92. @[file ... ]
  93. @.SH DESCRIPTION
  94. @.I wns
  95. @searches through a file or list of files for occurances of a particular
  96. @pattern, and prints a window of lines around each match point.
  97. @.PP
  98. @Options which may be given are as follows:
  99. @.TP
  100. @.B \-a\ nnn
  101. @(After) specifies that nnn lines following the matching line will be
  102. @printed.  default is 0.
  103. @.TP
  104. @.B \-b\ nnn
  105. @(Before) specifies that nnn lines preceding the matching line will be
  106. @printed.  default is 0.
  107. @.TP
  108. @.B \-d
  109. @Enables debugging information.  Not a very interesting option.
  110. @.TP
  111. @.B \-f
  112. @Suppress printing of the filename on each output line.
  113. @.TP
  114. @.B \-l\ nnn
  115. @Sets the maximum line length to nnn.  Lines longer than this will be
  116. @truncated to this length before attempting to match them to the pattern as
  117. @well as when printing them.  Default is 100.
  118. @.TP
  119. @.B \-n
  120. @Suppress printing of the line number on each output line.
  121. @.TP
  122. @.B \-w\ nnn
  123. @Sets the window size to nnn.  This is the same as -a nnn -b nnn.
  124. @.PP
  125. @.I wns
  126. @outputs lines in the following format:
  127. @.PP
  128. @filename @nnnnn: text
  129. @.PP
  130. @where
  131. @.I filename
  132. @is the name of the file containing the matching text and may be suppressed
  133. @with the -f option,
  134. @.I lnnnn
  135. @is the line number of the displayed line and may be suppressed with the
  136. @-n option, and
  137. @.I text
  138. @is the line from the file.
  139. @Additionally, if the total window size is greater than 1 (that is, more than
  140. @zero lines before or after), then non-adjacent text areas are separated by
  141. @a short dashed line.
  142. @.SH FILES
  143. @/usr/local/bin/wns /usr/local/src/wns/*
  144. @.SH "CREDITS TO"
  145. @M. Mallett  (mem@zinn.MV.COM)
  146. @.SH BUGS
  147. @You tell me..
  148. SHAR_EOF
  149. fi
  150. if test -f 'wns.c'; then
  151.     echo shar: will not over-write existing file 'wns.c'
  152. else
  153. awk << 'SHAR_EOF' > wns.c \
  154. '{\
  155. n=split($0,f,"@");\
  156. n=f[1];\
  157. while(n>=4){printf("    ");n=n-4}\
  158. while(n>=1){printf(" ");--n}\
  159. printf("%s\n",substr($0,length(f[1])+2,length))\
  160. }'
  161. @/* wns.c - Search for string and print window of lines around it.
  162.  
  163. 8@Nov 19 1984     Mark Mallett   (mem@zinn.MV.COM)
  164.  
  165. @mem    860224    Modified to do r/e (regular expression) parsing on unix
  166. @mem    860324    Added -f, -n; added code to number lines correctly on
  167. @        output.
  168. @mem    870325    Added support for regcmp()/regex() style regular expression
  169. @        library; redid some conditionals to provide better mix'n'match.
  170. @mem    870326    Don't try to print the filename if reading from stdin.
  171. @        Add -w option.  Fix a small problem which occasionally allowed
  172. @        the separator to come out between adjacent lines of the file.
  173. @mem    871119    Fix semantics of call to regcmp(): the NULL terminating the
  174. @        argument list was missing.  It worked, but probably only
  175. @        due to some bizarre coincidence.
  176.  
  177. @*/
  178.  
  179. @/* The appropriate defines are done in the makefile */
  180. @/* #define    OS_UNIX */    /* Define this for unix systems */
  181. @/* #define    SYSINC */    /* Define this for sys/ include hierarchy */
  182. @/* #define    REGEX */    /* Define this for re_comp/re_exec library */
  183. @/* #define    REGCMP */    /* Define this to use regcmp/regex */
  184. @/* #define    OS_CPM */    /* Define this for CP/M-80 */
  185.  
  186.  
  187. @/* Don't touch these */
  188. @#define    NOREGEXP        /* Set this for no regular expression */
  189. @#ifdef    REGEX
  190. @#undef    NOREGEXP
  191. @#endif    REGEX
  192.  
  193. @#ifdef    REGCMP
  194. @#undef    NOREGEXP
  195. @#endif    REGCMP
  196.  
  197.  
  198. @#ifdef OS_CPM
  199. @#include "stdio.h"
  200. @#include "ctype.h"
  201. @#endif OS_CPM
  202.  
  203. @#ifdef OS_UNIX
  204. @#include <stdio.h>
  205. @#include <ctype.h>
  206.  
  207. @#ifdef    SYSINC
  208. @#include <sys/types.h>
  209. @#include <sys/dir.h>
  210. @#else    /* !SYSINC */
  211. @#include <types.h>
  212. @#include <dir.h>
  213. @#endif    SYSINC
  214. @#endif OS_UNIX
  215.  
  216.  
  217. @/* Local definitions */
  218.  
  219. @#ifndef    NULL
  220. @#define    NULL    ((char *)0)
  221. @#endif    NULL
  222.  
  223. @#ifndef NUL
  224. @#define NUL     '\000'
  225. @#endif
  226.  
  227. @#ifndef TRUE
  228. @#define TRUE    1
  229. @#define FALSE   0
  230. @#endif
  231.  
  232.  
  233. @/* Internal data declared global */
  234.  
  235.  
  236. @/* Internal routines */
  237.  
  238.  
  239. @/* External data */
  240.  
  241.  
  242. @/* External routines */
  243.  
  244. @#ifdef    REGEX            /* re_comp/ re_exec */
  245. @extern    char    *re_comp();        /* r/e compile */
  246. @extern    int    re_exec();        /* r/e exec */
  247. @#endif    REGEX
  248.  
  249. @#ifdef    REGCMP            /* regcmp/regex */
  250. @extern    char    *regcmp();        /* r/e compile */
  251. @extern    char    *regex();        /* r/e exec */
  252. @#endif    REGCMP
  253.  
  254.  
  255. @/* Local data */
  256.  
  257. @static  int     Debug={FALSE};          /* Debug enabled flag */
  258. @static  int     Lcur = {0};             /* Current line (in Lines array) */
  259. @static  char    **Lines = {(char **)NULL};       /* Lines pointer array */
  260. @static  int     Linlen = {100};         /* Line length */
  261. @static  int     Lone = {0};             /* Line one (in Lines array) */
  262. @static    int    Nmr = {0};        /* Number of matched regions */
  263. @static  char    *Pat = {NULL};          /* Pattern */
  264. @static    char    Shwfile = {TRUE};    /* Show file name... */
  265. @static    char    Shwline = {TRUE};    /* Show line number */
  266. @static  int     Waft = {0};             /* Window after */
  267. @static  int     Wbef = {0};             /* Window before */
  268. @static  int     Wsiz = {0};             /* Window size */
  269.  
  270. @#ifdef    REGEX        /* regex style r/e manipulations */
  271. @char        *Re;        /* Result from re_comp() */
  272. @#endif    REGEX
  273.  
  274. @#ifdef    REGCMP        /* regcmp style r/e */
  275. @char        *Re;        /* Result from regcmp() */
  276. @#endif    REGCMP
  277.  
  278.  
  279. @main (argc, argv)
  280.  
  281. @int             argc;           /* Argument count */
  282. @char            **argv;         /* Argument values */
  283.  
  284. @{
  285. @int             i;              /* Scratch */
  286. @int             n;              /* Scratch again */
  287. @int             c;              /* A character */
  288. @char            *aptr;          /* Argument pointer */
  289. @int             nf;             /* number of files on command line */
  290.  
  291. @nf = 0;                         /* No files on line */
  292.  
  293. @for (i = 1; i < argc; i++)      /* Look at args */
  294. 4@{
  295. 4@if (argv[i][0] != '-')      /* If option */
  296. 8@{
  297. 8@if (Pat == NULL)        /* If no pattern yet given */
  298. @        {
  299. 12@Pat = argv[i];      /*  point here */
  300. @#ifdef    REGEX
  301. @        if ((Re = re_comp(Pat)) != NULL)
  302. @            {
  303. @        fprintf(stderr, "wns: %s\n", re);
  304. @        exit(1);
  305. @        }
  306. @#endif    REGEX
  307.  
  308. @#ifdef    REGCMP
  309. @        if ((Re = regcmp(Pat, NULL)) == NULL)
  310. @            {
  311. @        fprintf(stderr, "wns: error in regular expression.\n");
  312. @        exit(1);
  313. @        }
  314. @#endif    REGCMP
  315.  
  316. @        }
  317. 8@else                    /* This must be a file to search */
  318. 12@{
  319. 12@nf++;               /* Count it */
  320. 12@dosrch (argv[i]);   /* Search */
  321. 12@}
  322. 8@}
  323.  
  324. 4@else                        /* Option char */
  325. 8@{
  326. 8@c = argv[i][1];         /* Get option char */
  327. 8@if (isupper(c))         /* Trap idiot definition of tolower */
  328. 12@c = tolower(c);     /* Don't care about case */
  329. 8@n = i;
  330. 8@aptr = NULL;            /* Find arg, if any */
  331. 8@if (argv[i][2] != NUL)
  332. 12@{
  333. 12@aptr = &argv[i][2];
  334. 12@n = i;              /* Where to set i if we use this arg */
  335. 12@}
  336. 8@else if (i < argc-1)    /* use next.. */
  337. 12@{
  338. 12@n = i+1;
  339. 12@aptr = argv[n];
  340. 12@}
  341.  
  342. 8@switch (c)              /* Process the option */
  343. 12@{
  344. 12@case 'a':           /* Lines after */
  345. 16@Waft = atoi (aptr);
  346. 16@Lines = NULL;
  347. 16@i = n;
  348. 16@break;
  349.  
  350. 12@case 'b':           /* Lines before */
  351. 16@Wbef = atoi (aptr);
  352. 16@Lines = (char **)NULL;
  353. 16@i = n;
  354. 16@break;
  355.  
  356. 12@case 'd':           /* Enable debugging */
  357. 16@Debug = TRUE;
  358. 16@break;
  359.  
  360. @        case 'f':        /* Suppress filename on output */
  361. @            Shwfile = FALSE;
  362. @        break;
  363.  
  364. 12@case 'l':           /* Line length */
  365. 16@Linlen = atoi (aptr);
  366. 16@Lines = NULL;
  367. 16@i = n;
  368. 16@break;
  369.  
  370. @        case 'n':        /* Suppress line number on output */
  371. @            Shwline = FALSE;
  372. @        break;
  373.  
  374. 12@case 'w':           /* Window: lines before and after */
  375. 16@Waft = Wbef = atoi (aptr);
  376. 16@Lines = NULL;
  377. 16@i = n;
  378. 16@break;
  379.  
  380. 12@default:
  381. 16@fprintf (stderr, "Invalid option %s\n",argv[i]);
  382. 16@exit();
  383. 12@}
  384. 8@}
  385. 4@}
  386.  
  387. @if ( Pat == NULL )        /* If no pattern given */
  388. 4@{
  389. 4@fprintf(stderr, 
  390. @"usage: wns [-a n] [-b n] [-d] [-f] [-l n] [-n] [-w n] pattern [filename... ]\n");
  391. 4@exit(1);
  392. 4@}
  393.  
  394. @if (nf == 0)                    /* No files processed ? */
  395. 4@dosrch (NULL);              /* Do standard input */
  396. @}
  397. @/*
  398. @
  399. @*//* dosrch (ifnm)
  400.  
  401. 8@Perform the search
  402.  
  403. @Accepts :
  404.  
  405. 8@ifn             Input file name
  406.  
  407.  
  408. @Returns :
  409.  
  410.  
  411. @*/
  412.  
  413. @dosrch (ifnm)
  414.  
  415. @char            *ifnm;          /* Input filelname */
  416.  
  417. @{
  418. @FILE            *ifp;           /* Input fp */
  419. @char            *lptr;          /* Line pointer */
  420. @int             i;              /* Scratch */
  421. @int             prtaft;         /* Print-after count */
  422. @int             linnum;         /* Line number */
  423. @int        nlb;        /* Number of lines buffered */
  424.  
  425. @if (ifnm != NULL)               /* If file name given */
  426. 4@{
  427. 4@ifp = fopen (ifnm, "r");    /* Open it for read access */
  428. 4@if (ifp == NULL)
  429. 8@{
  430. 8@fprintf (stderr, "Can not open file %s\n", ifnm);
  431. 8@return;
  432. 8@}
  433. 4@}
  434. @else
  435. 4@ifp = stdin;
  436.  
  437. @if (Lines == NULL)              /* If no line table allocated.. */
  438. 4@{
  439. 4@Wsiz = Wbef+2;              /* Determine total window size */
  440. 4@Lines = (char **) calloc (Wsiz, sizeof (char *));
  441. 32@/* Allocate pointer table */
  442. 4@for (i = 0; i < Wsiz; i++)  /* Allocate line buffers */
  443. 8@Lines[i] = (char *) calloc (Linlen, sizeof(char));
  444. 4@}
  445.  
  446. @Lcur = Lone = 0;                /* Setup line pointers */
  447. @nlb = 0;            /* No lines buffered */
  448. @linnum = 0;                     /* Line number is zero */
  449. @prtaft = -(Wbef+1);        /* Make sure separator given first time */
  450.  
  451. @for (;;)                        /* Loop through the file */
  452. 4@{
  453. 4@lptr = Lines[Lcur];         /* Get pointer to current line */
  454. 4@if (++Lcur == Wsiz)         /* Bump curr pointer and wrap */
  455. 8@Lcur = 0;               /*  if hit end */
  456. 4@if (Lone == Lcur)           /* If wrapped to beginning of window */
  457. 8@if (++Lone == Wsiz)     /*  Bump beginning */
  458. 12@Lone = 0;           /*   and wrap if hit end */
  459.  
  460. 4@if (fgets (lptr, Linlen, ifp) != lptr)
  461. 8@break;                  /*  if end of file */
  462.  
  463. 4@linnum++;                   /* Count line number */
  464. 4@if (matlin (lptr))          /* If matching line */
  465. 8@{
  466. 8@if (prtaft < (-Wbef) )  /* Check for separator needed */
  467. 12@if ( (Nmr++ > 0 ) && ((Wbef > 0) || (Waft > 0)) )
  468. 16@printf ("-------------------\n");
  469. 8@while (Lone != Lcur)    /* Until we close the window */
  470. 12@{
  471. 12@shwlin (ifnm, linnum-nlb, Lines[Lone]);
  472. 32@/* Show the line */
  473. 12@if (++Lone == Wsiz)
  474. 16@Lone = 0;
  475. @        nlb--;
  476. 12@}
  477. @    nlb = 0;        /* No lines buffered */
  478. 8@prtaft = Waft;          /* Print n lines after */
  479. 8@}
  480.  
  481. 4@else                        /* Didn't match */
  482. 8@{
  483. 8@if (prtaft-- > 0)       /* If must print lines after */
  484. 12@{
  485. 12@shwlin (ifnm, linnum, lptr);
  486. 32@/* Show the line */
  487. 12@Lone = Lcur;        /* Match pointers */
  488. 12@}
  489. @    else if (nlb < Wbef)    /* Count lines buffered */
  490. @        nlb++;
  491. 8@}
  492. 4@}
  493.  
  494. @if (ifnm != NULL)
  495. 4@fclose (ifp);
  496. @}
  497. @/*
  498. @
  499. @*//* shwlin (fnm, linnum, line)
  500.  
  501. 8@Show a matching line
  502.  
  503.  
  504. @Accepts :
  505.  
  506. 8@fnm             File name
  507.  
  508. 8@linnum          Line number
  509.  
  510. 8@line            Line to show
  511.  
  512.  
  513. @Returns :
  514.  
  515.  
  516. @*/
  517.  
  518. @shwlin (fnm, linnum, line)
  519.  
  520. @char            *fnm;           /* File name */
  521. @int             linnum;         /* Line number */
  522. @char            *line;          /* Line (with newline at end) to print */
  523.  
  524. @{
  525. @if (Shwfile && ( fnm != NULL) )
  526. 4@printf("%s%s", fnm, Shwline?" ":":");
  527. @if (Shwline)
  528. 4@printf("@%05d%:", linnum);
  529. @printf ("%s", line);
  530. @}
  531. @/*
  532. @
  533. @*//* matlin (line)
  534.  
  535. 8@Perform match against pattern and line
  536.  
  537.  
  538. @Accepts :
  539.  
  540. 8@line            Address of line to match
  541.  
  542.  
  543. @Returns :
  544.  
  545. 8@<value>         TRUE if match
  546. 24@FALSE if not
  547.  
  548.  
  549. @*/
  550.  
  551.  
  552. @int matlin (line)
  553.  
  554. @char            *line;          /* Line to match */
  555.  
  556. @{
  557. @int        rtncode;        /* Return value from this routine */
  558.  
  559.  
  560. @#ifdef    NOREGEXP
  561. @char            *pptr, *lptr, *tlptr;
  562. @int             c1,c2;
  563. @#endif    NOREGEXP
  564.  
  565. @if (Debug)
  566. 4@printf ("Matching %s against %s", Pat, line);
  567.  
  568. @#ifdef    REGEX
  569. @rtncode = re_exec(line);    /* Hand off to r/e evaluator */
  570. @#endif    REGEX
  571.  
  572. @#ifdef    REGCMP
  573. @rtncode = ( regex( Re, line ) != NULL );
  574. @#endif    REGCMP
  575.  
  576. @#ifdef    NOREGEX        /* Have to do menial comparison.. */
  577. @lptr = line;                    /* Init line pointer */
  578.  
  579. @for ( rtncode = -1; rtncode < 0; )
  580. 4@{
  581. 4@tlptr = lptr++;             /* Get temp ptr to line */
  582. 4@pptr = Pat;                 /* Get ptr to pattern */
  583. 4@while (TRUE)
  584. 8@{
  585. 8@if ((c1 = *pptr++) == NUL)
  586. 12@{
  587. @        rtncode = 1;    /* GOOD return value */
  588. @        break;
  589. 12@}
  590. 8@if ((c2 = *tlptr++) == NUL)
  591. 12@{
  592. @        rtncode = 0;    /* BAD return value */
  593. @        break;
  594. 12@}
  595. 8@if (isupper(c1))
  596. 12@c1 = tolower(c1);
  597. 8@if (isupper(c2))
  598. 12@c2 = tolower(c2);
  599. 8@if (c1 != c2)
  600. 12@break;
  601. 8@}
  602. 4@}
  603. @#endif    NOREGEX
  604.  
  605.  
  606. @if (Debug)
  607. 4@printf("matlin returned %s\n", rtncode?"TRUE":"FALSE");
  608. @return(rtncode);
  609. @}
  610.  
  611.  
  612. SHAR_EOF
  613. fi
  614.  
  615.