home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_100 / 154_01 / grep2.c < prev    next >
Text File  |  1979-12-31  |  11KB  |  443 lines

  1. /* grep.c: attempt to get UNIX pattern-matching on a micro */
  2.  
  3. /* From DECUS C Tools package on DEC systems - for non-commercial
  4.     use only.  Modifications by Chuck Allison, April 1985:
  5.  
  6.         - handles quoted args (for embedded spaces)
  7.         - expands wildcards against indicated directory
  8.         - distinguishes case (ignore with -i)
  9. */
  10.  
  11. #include <makearg.c>    /* ..includes <stdio.h>, <ctype.h>, <dos.h>.. */
  12.  
  13. #define LMAX    512
  14. #define PMAX    256
  15. #define MAXFILES 150
  16. #define CHAR    1
  17. #define BOL     2
  18. #define EOL     3
  19. #define ANY     4
  20. #define CLASS   5
  21. #define NCLASS  6
  22. #define STAR    7
  23. #define PLUS    8
  24. #define MINUS   9
  25. #define ALPHA   10
  26. #define DIGIT   11
  27. #define NALPHA  12
  28. #define WHITE   13
  29. #define RANGE   14
  30. #define ENDPAT  15
  31. #define TRUE    1
  32. #define FALSE   0
  33.  
  34. int  cflag = FALSE,
  35.         fflag = FALSE,
  36.      nflag = FALSE,
  37.      vflag = FALSE,
  38.      iflag = FALSE;
  39.  
  40. char    *pp,
  41.         lbuf[LMAX],
  42.         pbuf[PMAX];
  43.  
  44.  
  45. main()
  46. {
  47.    register char   *p;
  48.    register int    i;
  49.    FILE            *f;
  50.    char *xargv[MAXFILES];
  51.    int xargc, maxarg = MAXFILES;
  52.  
  53.    /* ..this must be first; processes args.. */
  54.    makeargv();
  55.  
  56.    if (argc <= 1)
  57.       usage("No arguments");
  58.  
  59.    for (; *(p = *(argv+1)) == '-'; ++argv, --argc)
  60.            while (*++p)
  61.             switch(tolower(*p))
  62.             {
  63.                 case 'c': 
  64.                     cflag = !cflag;
  65.                        break;
  66.                 case 'f':
  67.                     fflag = !fflag;
  68.                        break;
  69.                 case 'n':
  70.                     nflag = !nflag;
  71.                        break;
  72.                 case 'v':
  73.                     vflag = !vflag;
  74.                        break;
  75.                 case 'i':
  76.                     iflag = !iflag;
  77.                        break;
  78.                 default:    usage("Unknown flag");
  79.             }
  80.  
  81.    compile(*++argv);
  82.    --argc;
  83.  
  84.    if (argc == 1)
  85.       grep(stdin, 0);
  86.    else
  87.    {
  88.       /* ..expand file arguments.. (Mark Williams C only!).. */
  89.       xargc = exargs("",argc,argv,xargv,maxarg);
  90.  
  91.       /* ..check file switch.. */
  92.       if (xargc > 1)
  93.           fflag = !fflag;
  94.  
  95.       for (i = 0; i < xargc; ++i)
  96.             if ((f = fopen(xargv[i],"r")) != NULL)
  97.             {
  98.                 grep(f,xargv[i]);
  99.                 fclose(f);
  100.             }
  101.             else
  102.                 fprintf(stderr,"can't open %s\n",xargv[i]);
  103.    }
  104. }
  105.  
  106.  
  107. usage(s)
  108. char *s;
  109. {
  110.    fprintf(stderr, "?GREP-E-%s\n", s);
  111.    fprintf(stderr,
  112.       "Usage: grep [-cfnv] pattern [file ...] \n");
  113.    exit(1);
  114. }
  115.  
  116.  
  117. compile(source)
  118. char *source;
  119. /* ..Compile the pattern into global pbuf[].. */
  120. {
  121.    register char  *s;         /* Source string pointer     */
  122.    register char  *lp;        /* Last pattern pointer      */
  123.    register int   c;          /* Current character         */
  124.    int            o;          /* Temp                      */
  125.    char           *spp;       /* Save beginning of pattern */
  126.    char           *cclass();  /* Compile class routine     */
  127.  
  128.    s = source;
  129.    pp = pbuf;
  130.  
  131.    while (c = *s++)
  132.    {
  133.       /* ..STAR, PLUS and MINUS are special.. */
  134.       if (c == '*' || c == '+' || c == '-')
  135.       {
  136.          if ( pp == pbuf ||
  137.               (o=pp[-1]) == BOL ||
  138.               o == EOL ||
  139.               o == STAR ||
  140.               o == PLUS ||
  141.               o == MINUS
  142.             )
  143.             badpat("Illegal occurrance op.", source, s);
  144.          store(ENDPAT);
  145.          store(ENDPAT);
  146.          spp = pp;               /* Save pattern end     */
  147.          while (--pp > lp)       /* Move pattern down    */
  148.             *pp = pp[-1];        /* one byte             */
  149.          *pp =   (c == '*') ? STAR :
  150.             (c == '-') ? MINUS : PLUS;
  151.          pp = spp;               /* Restore pattern end  */
  152.          continue;
  153.       }
  154.  
  155.       /* ..All the rest.. */
  156.       lp = pp;         /* ..Remember start.. */
  157.       switch(c)
  158.       {
  159.           case '^':
  160.              store(BOL);
  161.              break;
  162.           case '$':
  163.              store(EOL);
  164.              break;
  165.           case '.':
  166.              store(ANY);
  167.              break;
  168.           case '[':
  169.              s = cclass(source, s);
  170.              break;
  171.           case ':':
  172.              if (*s)
  173.              {
  174.                 c = *s++;
  175.                 switch(tolower(c))
  176.                 {
  177.                     case 'a':
  178.                        store(ALPHA);
  179.                        break;
  180.                     case 'd':
  181.                        store(DIGIT);
  182.                        break;
  183.                     case 'n':
  184.                        store(NALPHA);
  185.                        break;
  186.                     case ' ':
  187.                        store(WHITE);
  188.                        break;
  189.                     default:
  190.                        badpat("Unknown : type", source, s);
  191.                 }
  192.                 break;
  193.              }
  194.              else
  195.                 badpat("No : type", source, s);
  196.          case '\\':
  197.             if (*s)
  198.             c = *s++;
  199.          default:
  200.             store(CHAR);
  201.             store(iflag ? tolower(c) : c);
  202.       }
  203.    }
  204.    store(ENDPAT);
  205.    store('\0');
  206. }
  207.  
  208.  
  209. char *cclass(source, src)
  210. char *source;    /* ..Pattern start.. */
  211. char *src;      /* ..Class start.. */
  212. /* ..Compile a class (within []).. */
  213. {
  214.    register char   *s;        /* Source pointer    */
  215.    register char   *cp;       /* Pattern start     */
  216.    register int    c;         /* Current character */
  217.    int             o;                 /* ..Temp.. */
  218.  
  219.    s = src;
  220.    o = CLASS;
  221.    if (*s == '^')
  222.    {
  223.       ++s;
  224.       o = NCLASS;
  225.    }
  226.    store(o);
  227.    cp = pp;
  228.    store(0);                         /* ..Byte count.. */
  229.  
  230.    while ((c = *s++) && c!=']')
  231.    {
  232.       if (c == '\\')
  233.       {  /* ..Store quoted char.. */
  234.          if ((c = *s++) == '\0')     /* ..Gotta get something.. */
  235.             badpat("Class terminates badly", source, s);
  236.          else
  237.              store(iflag ? tolower(c) : c);
  238.       }
  239.       else if (c == '-' && (pp - cp) > 1 && *s != ']' && *s != '\0')
  240.       {
  241.          c = pp[-1];             /* Range start     */
  242.          pp[-1] = RANGE;         /* Range signal    */
  243.          store(c);               /* Re-store start  */
  244.          c = *s++;               /* Get end char and*/
  245.          store(iflag ? tolower(c) : c);
  246.       }
  247.       else
  248.          store(iflag ? tolower(c) : c);
  249.    }
  250.  
  251.    if (c != ']')
  252.       badpat("Unterminated class", source, s);
  253.    if ((c = (pp - cp)) >= 256)
  254.       badpat("Class too large", source, s);
  255.    if (c == 0)
  256.       badpat("Empty class", source, s);
  257.    *cp = c;
  258.    return(s);
  259. }
  260.  
  261.  
  262. store(op)
  263. {
  264.    if (pp >= &pbuf[PMAX])
  265.       error("Pattern too complex\n");
  266.    *pp++ = op;
  267. }
  268.  
  269.  
  270. badpat(message, source)
  271. char  *message,       /* ..Error message.. */
  272.       *source;        /* ..Pattern start.. */
  273. {
  274.    fprintf(stderr, "-GREP-E-%s, pattern is\"%s\"\n", message, source);
  275.    exit(1);
  276. }
  277.  
  278.  
  279.  
  280. grep(fp, fn)
  281. FILE       *fp;       /* File to process            */
  282. char       *fn;       /* File name (for -f option)  */
  283. /* ..Scan the file for the pattern in pbuf[].. */
  284. {
  285.    register int lno, count, m;
  286.  
  287.    lno = 0;
  288.    count = 0;
  289.    while (fgets(lbuf, LMAX, fp))
  290.    {
  291.       ++lno;
  292.       m = match();
  293.       if ((m && !vflag) || (!m && vflag))
  294.       {
  295.          ++count;
  296.          if (!cflag)
  297.          {
  298.             if (fflag && fn) 
  299.             {
  300.                fprintf(stdout,"\n\nFile: %s\n\n",fn);
  301.                fn = 0;
  302.             }
  303.             if (nflag)
  304.                printf("%d\t", lno);
  305.             fputs(lbuf,stdout);
  306.          }
  307.       }
  308.    }
  309.    if (cflag)
  310.    {
  311.       if (fflag && fn)
  312.             fprintf(stdout,"\n\nFile: %s\n\n",fn);
  313.       printf("%d\n", count);
  314.    }
  315. }
  316.  
  317.  
  318. match()
  319. /* ..Match the current line (in lbuf[]), return 1 if it does.. */
  320. {
  321.    register char *l;        /* ..Line pointer.. */
  322.    char *pmatch();
  323.  
  324.    for (l = lbuf; *l; l++)
  325.       if (pmatch(l, pbuf))
  326.          return(1);
  327.  
  328.    return(0);
  329. }
  330.  
  331.  
  332. char *pmatch(line, pattern)
  333. char *line,     /* ..(partial) line to match.. */
  334.      *pattern;  /* ..(partial) pattern to match.. */
  335. {
  336.    register char   *l;        /* ..Current line pointer.. */
  337.    register char   *p;        /* ..Current pattern pointer.. */
  338.    register char   c;         /* ..Current character.. */
  339.    register char   d;         /* ..Temporary character.. */
  340.    char            *e;        /* ..End for STAR and PLUS match.. */
  341.    int             op;        /* ..Pattern operation.. */
  342.    int             n;         /* ..Class counter.. */
  343.    char            *are;      /* ..Start of STAR match.. */
  344.  
  345.    l = line;
  346.    p = pattern;
  347.    while ((op = *p++) != ENDPAT)
  348.    {
  349.       switch(op)
  350.       {
  351.           case CHAR:
  352.              c = iflag ? tolower(*l++) : *l++;
  353.              d = iflag ? tolower(*p++) : *p++;
  354.              if (c != d)
  355.                 return(0);
  356.              break;
  357.           case BOL:
  358.              if (l != lbuf)
  359.                 return(0);
  360.              break;
  361.           case EOL:
  362.              if (*l != '\0' && *l != '\n')
  363.                 return(0);
  364.              break;
  365.           case ANY:
  366.              if (*l++ == '\0')
  367.                 return(0);
  368.              break;
  369.           case DIGIT:
  370.              if (!isdigit(c = *l++))
  371.                 return(0);
  372.              break;
  373.           case ALPHA:
  374.              if (!isalpha(c = *l++))
  375.                 return(0);
  376.              break;
  377.           case NALPHA:
  378.              if (!isalnum(c = *l++))
  379.                  return(0);
  380.              break;
  381.           case WHITE:
  382.              if (!isspace(c = *l++))
  383.                 return(0);
  384.              break;
  385.           case CLASS:
  386.           case NCLASS:
  387.              c = iflag ? tolower(*l++) : *l++;
  388.              n = *p++ & 0x00ff;
  389.              do
  390.              {
  391.                 if (*p == RANGE)
  392.                 {
  393.                    p += 3;
  394.                    n -= 2;
  395.                    if (c >= p[-2] && c <= p[-1])
  396.                       break;
  397.                 }
  398.                 else if (c == *p++)
  399.                    break;
  400.              } while (--n > 1);
  401.              if ((op == CLASS) == (n <= 1))
  402.                 return(0);
  403.              if (op == CLASS)
  404.                 p += n - 2;
  405.              break;
  406.           case MINUS:
  407.              e = pmatch(l, p);       /* ..Look for a match.. */
  408.              while (*p++ != ENDPAT); /* ..Skip over pattern.. */
  409.              if (e)                  /* ..Got a match?.. */
  410.                 l = e;               /* ..Yes, update string.. */
  411.              break;                  /* ..Always succeeds.. */
  412.           case PLUS:                 /* ..One or more.. */
  413.              if ((l = pmatch(l, p)) == 0)
  414.                 return(0);           /* ..Gotta have a match.. */
  415.           case STAR:                 /* ..Zero or more.. */
  416.              are = l;                /* ..Remember line start.. */
  417.              while (*l && (e = pmatch(l, p)))
  418.                 l = e;               /* ..Get longest match.. */
  419.              while (*p++ != ENDPAT); /* ..Skip over pattern.. */
  420.              while (l >= are)
  421.              {  /* ..Try to match rest.. */
  422.                 if (e = pmatch(l, p))
  423.                    return(e);
  424.                 --l;                 /* ..Nope, try earlier.. */
  425.              }
  426.              return(0);              /* ..Nothing else worked.. */
  427.           default:
  428.              printf("Bad op code %d\n", op);
  429.              error("Cannot happen -- match\n");
  430.       }
  431.    }
  432.    return(l);
  433. }
  434.  
  435.  
  436. error(s)
  437. char *s;
  438. {
  439.    fprintf(stderr, "%s", s);
  440.    exit(1);
  441. }
  442.  
  443.