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