-
Notifications
You must be signed in to change notification settings - Fork 0
/
window-srch
614 lines (504 loc) · 14.5 KB
/
window-srch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
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