/*---------------------------------------------------------------------------
 *           GREP.C    a generalized regular expression parser 
 *
 *
 *                Copyright (c) 1984 Allen Holub
 *      Copyright (c) 1984 Software Engineering Consultants
 *                      P.O. Box 5679
 *                   Berkeley, CA.  94705
 *
 *                     All rights reserved.
 *
 *      This program may be copied for personal, non-commmercial use
 *      only, provided that this copyright notice is included in all
 *      copies and that this program is not modified in any way.
 *      Copying for any other use without previously obtaining the 
 *      written permission of the author is prohibited.
 *
 *---------------------------------------------------------------------------
 */

/* 
 *      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'.
 *
 *      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.
 *
 *      usage is:
 *              grep [-vclnhyef] [expression] files ...
 *
 */

#include <stdio.h>
#include <ctype.h>
#include <malloc.h>
#include <string.h>
#include "tools.h"

#define MAXLINE 128             /* Maximum size of an input line        */

#define MAX_EXPR 64             /* Maximum number of regular expressions 
                                 * seperated by newlines or |  allowed
                                 */
/*      The following global flags are true if a switch was set
 *      on 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];

        i = 1;

        if (argc < 2)
                abort(pr_usage(1));
        if (*argv[i] == '-')            /* command line switches ? */
        {
                expand_sw (argv[i++]);

                if ( i == argc )
                        abort(pr_usage(1));
        }

        /*      Pattern string          */

        if ((exprc = get_expr(exprv, MAX_EXPR, &argv[i++])) == 0)
                abort (pr_usage(2));

        numfiles = argc - i;            /* number of files left to process  */

        fprintf(stderr,"                          \n");  /* opening message */
        while (i < argc)
        {
                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))
                {
                        if (yflag)              /* MSC routine instead of */
                                strupr(line);   /* stoupper in tools.c    */   

                        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++;
                        }
                        if (lflag && count)     break;
                }
                pr_count(numfiles,argv[i],count);
                fclose(stream);
								i++ ;
        } ;
        abort();
}

/* ----------------------------------------------------------------------- */

pr_count (fcount,fname,count)
int     fcount, count;
char    *fname;
{
        if (!cflag) 
                return 0;
        if (fcount > 1)
                printf("%-12s: ",fname);
        printf("%d\n", count);
}

/* ----------------------------------------------------------------------- */

pr_match (linenum, line, fname, match, numfiles)
int     linenum, match, numfiles;
char    *line, *fname;
{
        char    buf[80];

        if (cflag)
                return 0;
        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);
        }
}

/* ----------------------------------------------------------------------- */

pr_usage (num)
int     num;
{
#ifdef DEBUG
        fprintf(stderr,"%d ", num);
#endif
        fprintf(stderr,"usage: grep [-cefhlnvy] [expression] <files...>\n");
}

/* ----------------------------------------------------------------------- */

abort()
{
        exit();
}

/* ----------------------------------------------------------------------- */

expand_sw(str)
char    *str;
{
        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);
                        abort();
                        break;
                }
                str++;
        }
}

/* ----------------------------------------------------------------------- */

int do_or( lp, expr, max )
char    *lp;
TOKEN   **expr;
int     max;
{
        int     found;
        TOKEN   *pat;
        char    *op;

        found = 0;

        /* 
         *      Extract regular expressions seperated by OR_SYM's from
         *      lp and put them into expr. Extract only up to max 
         *      expressions. If yflag is true map string to uppercase first
         */


        if (yflag) 
                strupr(lp);

        while (op = in_string(OR_SYM, lp))
        {
                if (found <= max && (pat = makepat(lp,OR_SYM)))
                {
                        *expr++ = pat;
                        found++;
                }
                lp = ++op;
                if (pat == 0)
                        goto fatal_err;
        }

        if (found <= max && (pat = makepat(lp,OR_SYM)))
        {
                found++;
                *expr = pat;
        }

        if (pat == 0)
        {
fatal_err:
                printf("Illegal expression\n");
                exit();
        }
        return (found);
}

/* ----------------------------------------------------------------------- */

get_expr (expr, max, defexpr)
TOKEN   *expr[];
int     max;
char    **defexpr;
{
        FILE    *stream;
        int     count;
        char    line[MAXLINE];

#ifdef DEBUG
        int     i;
#endif
        /*      Get regular expressions seperated 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 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)
        {
                if ((stream = fopen(*defexpr, "r")) == NULL )
                {
                        fprintf (stderr, "Can't open %s\n", *defexpr);
                        abort();
                }

                while ((max - count) && fgets (line,MAXLINE,stream))
                        count+=do_or(line,&expr[count],max-count);

                fclose(stream);
        }
        else 
               if(count+=do_or(*defexpr,&expr[count],max-count)) *defexpr = " ";
#ifdef DEBUG
        for (i = count; --i >= 0 ;)
        {
                pr_tok (expr[1]);
                printf("------------------------------------\n");
        }
#endif
        return (count);
}



ÿ