home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
drdobbs
/
c_spec
/
execute
/
grep.c
< prev
next >
Wrap
C/C++ Source or Header
|
1986-02-20
|
10KB
|
473 lines
#include <stdio.h>
/*----------------------------------------------------------------
*
* Copyright (c) 1985 Allen Holub
* All rights reserved.
*
* Permission to copy this program or any part of this program
* is granted in the case of personal, non-commercial use only.
* Any use for profit or other commercial gain without written
* permission of the author is prohibited.
*
* If you've been give this program by a friend, and you find
* it worthwhile, I'd appreciate your sending $35 to me for the
* program.
*
* Software Engineering Consultants, P.O. Box 5679, Berkeley CA, 94705
*
*----------------------------------------------------------------
*
* GREP
*
* Search a file for a pattern.
*
* The algorithm used here is essentially the algorithm in
* Software Tools in Pascal (pp 145f.). Though the routines have
* been changed somewhat to put them into good 'C'. See tools1.c
* for details.
*
* This program is a healthy subset of the UNIX program of the same
* name. The differences are as follows:
*
* - the -s, -x and -b options are not supported.
* - the meta-characters ()+? are not supported.
* - the -y option cause case to be ignored.
*
* usage is:
* grep [-vclnhyef] [expression] files ...
*
* For more details see grep.doc and revision.doc
*/
#define OR_SYM '|' /* Used to get the OR of several
* regular expressions.
*/
#define MAXLINE 128 /* Maximum size of an input line
*/
#define MAX_EXPR 64 /* The maximum number of regular
* expressions separated by
* newlines or | allowed.
*/
typedef char *TOKEN; /* Dummy definition, use like FILE */
extern char *matchs ();
extern TOKEN *makepat ();
extern char *stoupper ();
extern char *strchr();
#define index(s,c) strchr(s,c)
/* The following global flags are true if a switch was set
* in the command line, false otherwise.
*/
int vflag, yflag, cflag, lflag, nflag, hflag, fflag;
/*----------------------------------------------------------------------*/
main(argc, argv)
int argc;
char **argv;
{
int i, j, linenum, count;
int line[MAXLINE];
int numfiles;
FILE *stream;
int exprc;
TOKEN *exprv[MAX_EXPR];
fprintf(stderr, "GREP - Copyright (C) 1984, Allen I. Holub,");
fprintf(stderr, " all rights reserved\n");
ctlc();
reargv(&argc, &argv);
i = 1;
if (argc < 2)
pr_usage(1);
if ( *argv[i] == '-')
{
/*
* Expand the switches on the command line
*/
expand_sw( argv[i++] );
if ( i == argc )
pr_usage(1);
}
/* Get the pattern string.
*/
if ( (exprc = get_expr( exprv, MAX_EXPR, &argv[i++])) == 0 )
pr_usage(2);
numfiles = argc - i; /* Get number of files left to
* process on the command line
*/
do
{
if ( numfiles)
{
stream = fopen( argv[i], "r");
if (stream == NULL)
{
fprintf(stderr, "Can't open %s\n", argv[i]);
continue;
}
}
else
{
stream = stdin;
}
count = 0;
linenum = 1;
while ( fgets(line, MAXLINE, stream) )
{
#ifdef CPM
if (!fflag || yflag )
stoupper(line);
#else
if ( yflag )
stoupper(line);
#endif
for( j = exprc ; --j >= 0 ; )
{
if ( matchs(line , exprv[j]) )
{
count++;
pr_match(linenum, line, argv[i], 1,
numfiles);
}
else
{
pr_match(linenum, line, argv[i], 0,
numfiles);
}
linenum++;
cntrl_c();
}
if( lflag && count )
break;
}
pr_count( numfiles, argv[i], count );
fclose (stream);
} while (++i < argc);
exit( 0 );
}
/*----------------------------------------------------------------------*/
pr_count( fcount, fname, count)
int fcount, count;
char *fname;
{
/* Process the -c flag by printing out a count and,
* if more than one file was listed on the command line,
* the file name too.
*/
if (!cflag)
return;
if (fcount > 1)
printf("%-12s: ", fname );
printf( "%d\n", count );
}
/*----------------------------------------------------------------------*/
pr_match(linenum, line, fname, match, numfiles)
int linenum, match;
char *line, *fname;
{
/* If a match is found print the correct thing
* as specified by the command line switches.
*/
char buf[80];
if (cflag)
return;
if ( (vflag && !match) || (!vflag && match) )
{
if (!hflag && ( (numfiles > 1) || lflag) )
printf("%s%s", fname, lflag ? "\n" : ":" );
if (nflag)
printf("%03d:", linenum );
if (!lflag)
printf("%s", line );
}
}
/*----------------------------------------------------------------------*/
expand_sw( str )
char *str;
{
/* Set global flags corresponding to specific switches
* if those switches are set
*/
vflag = 0;
cflag = 0;
lflag = 0;
nflag = 0;
hflag = 0;
fflag = 0;
yflag = 0;
while (*str)
{
switch ( toupper(*str))
{
case '-':
case 'E':
break;
case 'C':
cflag = 1;
break;
case 'F':
fflag = 1;
break;
case 'H':
hflag = 1;
break;
case 'L':
lflag = 1;
break;
case 'N':
nflag = 1;
break;
case 'V':
vflag = 1;
break;
case 'Y':
yflag = 1;
break;
default:
pr_usage(3);
break;
}
str++;
}
}
/*----------------------------------------------------------------------*/
int do_or( lp, expr, maxexpr )
char *lp;
TOKEN **expr;
int maxexpr;
{
int found;
TOKEN *pat;
char *op;
found = 0;
/*
* Extract regular expressions separated by OR_SYMs from
* lp and put them into expr. Extract only up to
* maxexpr expressions. If yflag is true map string to upper
* case first.
*/
if( yflag )
stoupper( lp );
while ( op = index(lp, OR_SYM) )
{
if(found <= maxexpr && (pat = makepat(lp, OR_SYM)) )
{
*expr++ = pat;
found++;
}
lp = ++op;
if ( pat == 0 )
goto fatal_err;
}
if (found <= maxexpr && (pat = makepat( lp, OR_SYM)) )
{
found++;
*expr = pat;
}
if ( pat == 0 )
{
fatal_err:
printf("Illegal expression: %s\n", lp);
exit();
}
return (found);
}
/*----------------------------------------------------------------------*/
get_expr( expr, maxexpr, defexpr )
TOKEN *expr[];
int maxexpr;
char **defexpr;
{
FILE *stream;
int count;
char line[MAXLINE];
#ifdef DEBUG
int i;
#endif
/* Get regular expressions separated by | or newlines
* either out of a file or off the command line depending
* on whether the -f flag is set. The expressions are
* converted into pattern templates (see tools.c) and
* pointers to the templates are put into the array expr[]
* (which works similar to argv).
*
* Return the number of expressions found (which can be used
* in a similar fashion to argc).
*/
count = 0;
if ( fflag )
{
/*
* Then *defexpr is the file name and expressions should
* be taken from that file.
*/
if ( (stream = fopen(*defexpr, "r")) == NULL )
{
fprintf(stderr, "Can't open %s\n", *defexpr);
exit( 1 );
}
while ( (maxexpr - count) && fgets(line, MAXLINE, stream) )
{
count += do_or(line, &expr[count], maxexpr - count );
}
fclose (stream);
}
else
{
/*
* *defexpr is the expression itself.
*/
if ( count += do_or( *defexpr, &expr[count], maxexpr - count))
*defexpr = " ";
}
#ifdef DEBUG
/* Print out all the regular expressions after they have been
* converted into pattern templates (see tools.c).
*/
for (i = count; --i >= 0 ; )
{
pr_tok( expr[i] );
printf("-------------------------------------------------\n");
}
#endif
return(count);
}
/*----------------------------------------------------------------------*/
cntrl_c()
{
#ifdef CPM
/* If any character was hit, and that character is a
* ^C, then abort.
*/
if ( bdos(11) && ((bdos(1,0) & 0x7f) == 0x03) )
exit(1);
#endif
}
/*----------------------------------------------------------------------*/
#define E(x) fprintf(stderr, "%s\n", x);
pr_usage(num)
int num;
{
# ifdef DEBUG
fprintf(stderr,"ERROR NUMBER %d ", num);
# endif
E("Useage: grep [-switchs] <pattern> [files ...]");
E("Prints all matches of <pattern> found in the indicated files");
E("or in standard input if no files are listed");
E("<pattern> can be any regular expression composed of:");
E(" . = matches any character");
E(" $ = end of line. ^ = start of line.");
E(" * = previous character 0 or more times");
E(" + = previous character 1 or more times");
E(" [] matches any of the characters enclosed in []. If a ^ is");
E(" the first character after the [, any character except");
E(" those in the class will be matched.");
E(" \\b=backspace \\f=FF \\n=LF \\r=CR \\t=HT (tab)");
E(" \\s=space \\e=ESC \\xDD=char composed of hex digits DD");
E(" any other character = that character.");
E("Optional command line switches are:");
E(" -c only a count of matching lines is printed");
E(" -e <expr> Take expression from next argument.");
E(" -f <file> Take expressions from file.");
E(" -h file name headers aren't printed");
E(" -l only names of files that contain match are printed");
E(" -n each output line preceeded by line number in file");
E(" -v print all lines except matching ones");
E(" -y Ignore case");
exit(1);
}