home *** CD-ROM | disk | FTP | other *** search
/ Hot Shareware 35 / hot35.iso / ficheros / 9TXT / ZE32V270.ZIP / GREP.C_ / GREP.C
C/C++ Source or Header  |  1998-04-02  |  21KB  |  761 lines

  1. /*
  2.  *
  3.  * The   information  in  this  document  is  subject  to  change
  4.  * without  notice  and  should not be construed as a commitment
  5.  * by Digital Equipment Corporation or by DECUS.
  6.  *
  7.  * Neither Digital Equipment Corporation, DECUS, nor the authors
  8.  * assume any responsibility for the use or reliability of  this
  9.  * document or the described software.
  10.  *
  11.  *   Copyright (C) 1980, DECUS
  12.  *
  13.  * General permission to copy or modify, but not for profit,  is
  14.  * hereby  granted,  provided that the above copyright notice is
  15.  * included and reference made to  the   fact  that  reproduction
  16.  * privileges were granted by DECUS.
  17.  *
  18.  */
  19. #include <dir.h>
  20. #include <dos.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <ctype.h>
  25. /*
  26.  * grep.
  27.  *
  28.  * Runs on the Decus compiler or on vms.
  29.  * Converted for BDS compiler (under CP/M-80), 20-Jan-83, by Chris Kern.
  30.  *
  31.  * Converted to IBM PC with CI-C86 C Compiler June 1983 by David N. Smith
  32.  *
  33.  * On vms, define as:
  34.  *
  35.  *   grep :== "$disk:[account]grep"     (native)
  36.  *   grep :== "$disk:[account]grep grep"     (Decus)
  37.  *
  38.  * See below for more information.
  39.  *
  40.  */
  41.  
  42. /*****************************************************************/
  43. /* Changed by JAJ 5/96 to write to STDOUT and not to STDERR so   */
  44. /* that the output is easier to capture to file. Also added a    */
  45. /* basic form of wildcard support was added                      */
  46. /*****************************************************************/
  47.  
  48. /*****************************************************************/
  49. /* Changed by BKB 5/97 to support wildcards along with a path    */
  50. /* Now prints the path along with the filename                   */
  51. /* Now is case sensitive by default, ignore case with -i option  */
  52. /* All non ANSI-C code is rewritten                              */
  53. /* Don't run if no files is given (don't use stdin)              */
  54. /*****************************************************************/
  55.  
  56. /*****************************************************************/
  57. /* Changed by BKB 11/97 to support searching subdirectories      */
  58. /*****************************************************************/
  59.  
  60. /*****************************************************************/
  61. /* Changed by BKB 03/98                                          */
  62. /*   Fixed a bug when searching for a string in uppercace and    */
  63. /*   the ignore_case flag is set                                 */
  64. /*   Now don't print the name of the program to stdout, in order */
  65. /*   to prevent Zeus from opening the exe file, when using       */
  66. /*   StandardOutputPrevious                                      */
  67. /*****************************************************************/
  68.  
  69. static void usage(char *s);
  70. static void help(char **hp);
  71. static void cant(char *s);
  72. static void compile(char *source);
  73. static void badpat(char *message, char *source, char *stop);
  74. static int match(void);
  75. static void grep(char *fn);
  76. static char *split_file_name(char *file_name);
  77. static int  find_files(char *pattern, char *path);
  78. static void error(char *s);
  79. static void file(char *s);
  80. static void store(char op);
  81. static char *cclass(char *source, char *src);
  82. static char *pmatch(char *line, char *pattern);
  83. static char *grep_strtok(char **str, char *match, char *found);
  84. static char grep_tolower(char ch);
  85. static char *documentation[] =
  86. {
  87.   "grep searches files for a given pattern.  Execute by",
  88.   "   grep [flags] regular_expression file_list",
  89.   "",
  90.   "Flags are single characters preceeded by '-':",
  91.   "   -c      Only a count of matching lines is printed",
  92.   "   -f      Print file name for matching lines switch, see below",
  93.   "   -n      Each line is preceeded by its line number",
  94.   "   -v      Only print non-matching lines",
  95.   "   -i      Ignore case",
  96.   "   -d      Search subdirectories",
  97.   "",
  98. /* -- JAJ  "The file_list is a list of files (wildcards are acceptable on RSX modes).", */
  99.   "The file_list is a list of files (wildcards are acceptable modes).",
  100.   "Eg. [file1.c file2.c] or [*.c *.h] or [\prog\*.c;*.h]",
  101.   0
  102. };
  103.  
  104.  
  105. char *patdoc[] =
  106. {
  107.   "The regular_expression defines the pattern to search for."
  108.   "Blank lines never match."
  109.   "The expression should be quoted to prevent file-name translation.",
  110.   "x      An ordinary character (not mentioned below) matches that character.",
  111.   "'\\'    The backslash quotes any character.  \"\\$\" matches a dollar-sign.",
  112.   "'^'    A circumflex at the beginning of an expression matches the",
  113.   "       beginning of a line.",
  114.   "'$'    A dollar-sign at the end of an expression matches the end of a line.",
  115.   "'.'    A period matches any character except \"new-line\".",
  116.   "':a'   A colon matches a class of characters described by the following",
  117.   "':d'     character.  \":a\" matches any alphabetic, \":d\" matches digits,",
  118.   "':n'     \":n\" matches alphanumerics, \": \" matches spaces, tabs, and",
  119.   "': '     other control characters, such as new-line.",
  120.   "'*'    An expression followed by an asterisk matches zero or more",
  121.   "       occurrances of that expression: \"fo*\" matches \"f\", \"fo\"",
  122.   "       \"foo\", etc.",
  123.   "'+'    An expression followed by a plus sign matches one or more",
  124.   "       occurrances of that expression: \"fo+\" matches \"fo\", etc.",
  125.   "'-'    An expression followed by a minus sign optionally matches",
  126.   "       the expression.",
  127.   "'[]'   A string enclosed in square brackets matches any character in",
  128.   "       that string, but no others.  If the first character in the",
  129.   "       string is a circumflex, the expression matches any character",
  130.   "       except \"new-line\" and the characters in the string.  For",
  131.   "       example, \"[xyz]\" matches \"xx\" and \"zyx\", while \"[^xyz]\"",
  132.   "       matches \"abc\" but not \"axb\".  A range of characters may be",
  133.   "       specified by two characters separated by \"-\".  Note that,",
  134.   "       [a-z] matches alphabetics, while [z-a] never matches.",
  135.   "The concatenation of regular expressions is a regular expression.",
  136.   0
  137. };
  138.  
  139.  
  140. #define LMAX   512
  141. #define PMAX   256
  142. #define CHAR     1
  143. #define BOL      2
  144. #define EOL      3
  145. #define ANY      4
  146. #define CLASS    5
  147. #define NCLASS   6
  148. #define STAR     7
  149. #define PLUS     8
  150. #define MINUS    9
  151. #define ALPHA   10
  152. #define DIGIT   11
  153. #define NALPHA  12
  154. #define PUNCT   13
  155. #define RANGE   14
  156. #define ENDPAT  15
  157.  
  158. static int  cflag;
  159. static int  fflag;
  160. static int  nflag;
  161. static int  vflag;
  162. static int  nfile;
  163. static int  ignore_case_flag = 0; /* BKB */
  164. static int  search_subdirectories = 0;
  165. static int  debug = 0;     /* Set for debug code      */
  166. static char *pp;
  167. static char lbuf[LMAX];
  168. static char pbuf[PMAX];
  169. /*******************************************************/
  170.  
  171. int main(int argc, char *argv[])
  172. {
  173.   char *p, *t;
  174.   char *path;
  175.   char found;
  176.   int  c, i;
  177.   int  gotpattern;
  178.  
  179.   if(argc <= 1)
  180.     usage("No arguments");
  181.   if(argc == 2 && argv[1][0] == '?' && argv[1][1] == 0)
  182.   {
  183.     help(documentation);
  184.     help(patdoc);
  185.     return 1;
  186.   }
  187.  
  188.   printf("\nGrep ");
  189.   for(c = 1; c < argc; c++)
  190.     printf("%s ", argv[c]);
  191.   printf("\n");
  192.  
  193.   nfile = argc - 1;
  194.   gotpattern = 0;
  195.   c = 0;
  196.   for(i = 1; i < argc; ++i)
  197.   {
  198.     p = argv[i];
  199.     if(*p == '-')
  200.     {
  201.       ++p;
  202.       while((c = *p++) != 0)
  203.       {
  204.         switch(c)
  205.         {
  206.           case '?':
  207.             help(documentation);
  208.             break;
  209.           case 'c':
  210.             ++cflag;
  211.             break;
  212.           case 't':
  213.             ++debug;
  214.             break;
  215.           case 'f':
  216.             ++fflag;
  217.             break;
  218.           case 'n':
  219.             ++nflag;
  220.             break;
  221.           case 'v':
  222.             ++vflag;
  223.             break;
  224.           case 'i':
  225.             ignore_case_flag++;
  226.             break;
  227.           case 'd':
  228.             search_subdirectories++;
  229.             break;
  230.           default:
  231.             usage("Unknown flag");
  232.             break;
  233.         }
  234.       }
  235.       argv[i] = 0;
  236.       --nfile;
  237.     }
  238.     else if(!gotpattern)
  239.     {
  240.       compile(p);
  241.       argv[i] = 0;
  242.       ++gotpattern;
  243.       --nfile;
  244.     }
  245.   }
  246.   if(!gotpattern)
  247.     usage("No pattern");
  248.   if(nfile == 0)
  249.     usage("No files"); /* Let grep terminate if no filename is set (don't use stdin) BKB */
  250.   else
  251.   {
  252.     i = 0;
  253.     for(c = 1; c < argc; c++)
  254.     {
  255.       if(argv[c] != NULL)
  256.       {
  257.         t = p = argv[c];
  258.         p = grep_strtok(&t, ";", &found);
  259.         path = split_file_name(p);
  260.         while(p)
  261.         {
  262.           i += find_files(p, path);
  263.           p = grep_strtok(&t, ";", &found);
  264.         }
  265.       }
  266.     }
  267.     if(i == 0)
  268.       usage("No files found");
  269.   }
  270.   return 0;
  271. }
  272.  
  273. static char *split_file_name(char *file_name)
  274. {
  275.   static char path[256];  /* Path must be static since it is used by main BKB */
  276.   char *s;
  277.   int a;
  278.  
  279.   for(a = 0; file_name[a] != '\0'; a++)
  280.     path[a] = toupper(file_name[a]);
  281.   path[a] = '\0';
  282.  
  283.   /* Remove all char's from the end until the first '\\' or ':' is met, BKB */
  284.   for(a = strlen(path); path[a] != '\\' && path[a] != ':' && a >= 0; a--)
  285.     path[a] = '\0';
  286.   path[a] = '\0';
  287.  
  288.   /* Put the search pattern into file_name */
  289.   for(s = &file_name[strlen(file_name) - 1]; *s != '\\' && *s != ':' && *s != '\0'; s--);
  290.   if(*s != '\0')
  291.     strcpy(file_name, s);
  292.   else
  293.   { /* If no path is specified get the current working directory */
  294.     if(!getcwd(path, 256))
  295.       error("Unable to get dir");
  296.     if(strlen(path) == 3 && path[1] == ':')
  297.       path[2] = '\0';
  298.   }
  299.   return path;
  300. }
  301.  
  302. /*******************************************************/
  303. static void file(char *s)
  304. {
  305.   /*-- JAJ better file handling for Zeus */
  306.   /*   printf("File %s:\n", s);          */
  307.   printf("%-13s |", s);
  308. }
  309.  
  310. /*******************************************************/
  311. static void cant(char *s)
  312. {
  313.   /*-- JAJ pipe to stdout so Zeus can see it    */
  314.   /*   fprintf(stderr, "%s: cannot open\n", s); */
  315.   fprintf(stdout, "%s: cannot open\n", s);
  316. }
  317.  
  318. /*******************************************************/
  319. static void help(char **hp) /* Give good help */
  320. {
  321.   register char   **dp;
  322.   for(dp = hp; *dp; dp++)
  323.     printf("%s\n", *dp);
  324. }
  325.  
  326. /*******************************************************/
  327. static void usage(char *s)
  328. {
  329.   /*-- JAJ pipe to stdout so Zeus can see it
  330.   //   fprintf(stderr, "?GREP-E-%s\n", s);
  331.   //   fprintf(stderr,
  332.   //   "Usage: grep [-cfnv] pattern [file ...].  grep ? for help\n"); */
  333.   fprintf(stdout, "?GREP-E-%s\n", s);
  334.   fprintf(stdout, "Usage: grep [-cfnvid] pattern [file ...].  grep ? for help\n");
  335.   exit(1);
  336. }
  337. /*******************************************************/
  338. static void compile(char *source) /* Pattern to compile     */
  339. { /* Compile the pattern into global pbuf[] */
  340.   register char  *s;           /* Source string pointer     */
  341.   register char  *lp = NULL;   /* Last pattern pointer    */
  342.   register int   c;            /* Current character     */
  343.   int       o;                 /* Temp        */
  344.   char      *spp;              /* Save beginning of pattern */
  345.  
  346.   s = source;
  347.   if(debug)
  348.     printf("Pattern = \"%s\"\n", s);
  349.   pp = pbuf;
  350.   while((c = *s++) != 0)
  351.   { /* STAR, PLUS and MINUS are special. */
  352.     if(c == '*' || c == '+' || c == '-')
  353.     {
  354.       if(pp == pbuf || (o = pp[-1]) == BOL || o == EOL ||
  355.          o == STAR ||  o == PLUS || o == MINUS)
  356.         badpat("Illegal occurrance op.", source, s);
  357.       store(ENDPAT);
  358.       store(ENDPAT);
  359.       spp = pp;     /* Save pattern end   */
  360.       while(--pp > lp)   /* Move pattern down  */
  361.       *pp = pp[-1];  /* one byte     */
  362.       *pp = (c == '*') ? STAR : (c == '-') ? MINUS : PLUS;
  363.       pp = spp;     /* Restore pattern end  */
  364.       continue;
  365.     }
  366.     /* All the rest. */
  367.     lp = pp;          /* Remember start       */
  368.     switch(c)
  369.     {
  370.       case '^':
  371.         store(BOL);
  372.         break;
  373.       case '$':
  374.         store(EOL);
  375.         break;
  376.       case '.':
  377.         store(ANY);
  378.         break;
  379.       case '[':
  380.         s = cclass(source, s);
  381.         break;
  382.       case ':':
  383.         if(*s)
  384.         {
  385.           c = *s++;
  386.           switch(c)
  387.           {
  388.             case 'a':
  389.             case 'A':
  390.               store(ALPHA);
  391.               break;
  392.             case 'd':
  393.             case 'D':
  394.               store(DIGIT);
  395.               break;
  396.             case 'n':
  397.             case 'N':
  398.               store(NALPHA);
  399.               break;
  400.             case ' ':
  401.               store(PUNCT);
  402.               break;
  403.             default:
  404.               badpat("Unknown : type", source, s);
  405.               break;
  406.           }
  407.           break;
  408.         }
  409.         else
  410.           badpat("No : type", source, s);
  411.       case '\\':
  412.         if(*s)
  413.           c = *s++;
  414.       default:
  415.         store(CHAR);
  416.         store(c);
  417.         break;
  418.     }
  419.   }
  420.   store(ENDPAT);
  421.   store(0);         /* Terminate string     */
  422.  
  423.   if(debug)
  424.   {
  425.     for(lp = pbuf; lp < pp;)
  426.     {
  427.       if((c = (*lp++ & 0377)) < ' ')
  428.         printf("\\%o ", c);
  429.       else
  430.         printf("%c ", c);
  431.     }
  432.     printf("\n");
  433.   }
  434. }
  435.  
  436. /*******************************************************/
  437. static char *cclass(char *source, char *src)
  438. /* Compile a class (within []) */
  439. {
  440.   register char   *s;       /* Source pointer    */
  441.   register char   *cp;      /* Pattern start      */
  442.   register int    c;        /* Current character */
  443.   int        o;             /* Temp      */
  444.   s = src;
  445.   o = CLASS;
  446.  
  447.   if(*s == '^')
  448.   {
  449.     ++s;
  450.     o = NCLASS;
  451.   }
  452.   store(o);
  453.   cp = pp;
  454.   store(0);             /* Byte count  */
  455.  
  456.   while((c = *s++) != 0 && c != ']')
  457.   {
  458.     if(c == '\\')  /* Store quoted char    */
  459.     {
  460.       if((c = *s++) == '\0')      /* Gotta get something  */
  461.         badpat("Class terminates badly", source, s);
  462.       else
  463.         store(c);
  464.     }
  465.     else if(c == '-' && (pp - cp) > 1 && *s != ']' && *s != '\0')
  466.     {
  467.       c = pp[-1];       /* Range start     */
  468.       pp[-1] = RANGE;   /* Range signal    */
  469.       store(c);     /* Re-store start  */
  470.       c = *s++;     /* Get end char and*/
  471.       store(c);  /* Store it      */
  472.     }
  473.     else
  474.     {
  475.       store(c);  /* Store normal char */
  476.     }
  477.   }
  478.   if(c != ']')
  479.     badpat("Unterminated class", source, s);
  480.   if((c = (int )(pp - cp)) >= 256)
  481.     badpat("Class too large", source, s);
  482.   if(c == 0)
  483.     badpat("Empty class", source, s);
  484.   *cp = c;
  485.  
  486.   return s;
  487. }
  488. /*******************************************************/
  489. static void store(char op)
  490. {
  491.   if(pp >= &pbuf[PMAX])
  492.     error("Pattern too complex\n");
  493.   *pp++ = op;
  494. }
  495. /*******************************************************/
  496.  
  497. static void badpat(char *message, char *source, char *stop)
  498. {
  499.   /*-- JAJ pipe to stdout so Zeus can see it
  500.   //   fprintf(stderr, "-GREP-E-%s, pattern is\"%s\"\n", message, source);
  501.   //   fprintf(stderr, "-GREP-E-Stopped at byte %d, '%c'\n",
  502.   //    stop-source, stop[-1]); */
  503.   fprintf(stdout, "-GREP-E-%s, pattern is\"%s\"\n", message, source);
  504.   fprintf(stdout, "-GREP-E-Stopped at byte %d, '%c'\n", stop-source, stop[-1]);
  505.   error("?GREP-E-Bad pattern\n");
  506. }
  507.  
  508. static void grep(char *fn)
  509. { /* Scan the file for the pattern in pbuf[] */
  510.   register int lno = 0, count = 0, m;
  511.  
  512.   FILE *fp = fopen(fn, "r");
  513.   if(!fp)
  514.     cant(fn);
  515.  
  516.   while (fgets(lbuf, LMAX, fp))
  517.   {
  518.     ++lno;
  519.     m = match();
  520.     if((m && !vflag) || (!m && vflag))
  521.     {
  522.       ++count;
  523.       if(!cflag)
  524.       {
  525.         if(fflag && fn)
  526.         {
  527.           file(fn);
  528.           /*-- JAJ better file handling for Zeus */
  529.           /*  fn = 0;  */
  530.         }
  531.         if(nflag)
  532.           printf(" %5d | ", lno);
  533.  
  534.         if(lbuf[strlen(lbuf) - 1] == '\n')  /* Remove '\n' from line before it is printed */
  535.           lbuf[strlen(lbuf) - 1] = '\0';
  536.         printf("%s\n", lbuf);
  537.       }
  538.     }
  539.   }
  540.   if(cflag)
  541.   {
  542.     if(fflag && fn)
  543.       file(fn);
  544.     printf(" Count: %d\n", count);
  545.   }
  546.   fclose(fp);
  547. }
  548. /*******************************************************/
  549. static int match(void)
  550. /* Match the current line (in lbuf[]), return 1 if it does. */
  551. {
  552.   register char   *l;         /* Line pointer     */
  553.  
  554.   for(l = lbuf; *l; l++)
  555.   {
  556.     if(pmatch(l, pbuf))
  557.       return(1);
  558.   }
  559.   return(0);
  560. }
  561.  
  562. /*******************************************************/
  563. static char *pmatch(char *line, char *pattern)
  564. {
  565.   register char   *l;         /* Current line pointer       */
  566.   register char   *p;         /* Current pattern pointer      */
  567.   register char   c;          /* Current character        */
  568.   char       *e;              /* End for STAR and PLUS match  */
  569.   int        op;              /* Pattern operation        */
  570.   int        n;               /* Class counter          */
  571.   char       *are;            /* Start of STAR match        */
  572.  
  573.   l = line;
  574.   if(debug > 1)
  575.     printf("pmatch(\"%s\")\n", line);
  576.   p = pattern;
  577.   while ((op = *p++) != ENDPAT)
  578.   {
  579.     if(debug > 1)
  580.       printf("byte[%d] = 0%o, '%c', op = 0%o\n", l-line, *l, *l, op);
  581.     switch(op)
  582.     {
  583.       case CHAR:
  584.         if(grep_tolower(*l) != grep_tolower(*p++))
  585.           return(0);
  586.         l++;
  587.         break;
  588.       case BOL:
  589.         if(l != lbuf)
  590.           return(0);
  591.         break;
  592.       case EOL:
  593.         if(*l != '\0')
  594.           return(0);
  595.         break;
  596.       case ANY:
  597.         if(*l++ == '\0')
  598.           return(0);
  599.         break;
  600.       case DIGIT:
  601.         if((c = *l++) < '0' || (c > '9'))
  602.           return(0);
  603.         break;
  604.       case ALPHA:
  605.         c = grep_tolower(*l);
  606.         l++;
  607.         if(c < 'a' || c > 'z')
  608.           return(0);
  609.         break;
  610.       case NALPHA:
  611.         c = grep_tolower(*l);
  612.         l++;
  613.         if(c >= 'a' && c <= 'z')
  614.           break;
  615.         else if(c < '0' || c > '9')
  616.           return(0);
  617.         break;
  618.       case PUNCT:
  619.         c = *l++;
  620.         if(c == 0 || c > ' ')
  621.           return(0);
  622.         break;
  623.       case CLASS:
  624.       case NCLASS:
  625.         c = grep_tolower(*l);
  626.         l++;
  627.         n = *p++ & 0377;
  628.         do
  629.         {
  630.           if(*p == RANGE)
  631.           {
  632.             p += 3;
  633.             n -= 2;
  634.             if(c >= p[-2] && c <= p[-1])
  635.               break;
  636.           }
  637.           else if(c == *p++)
  638.             break;
  639.         }
  640.         while (--n > 1);
  641.         if((op == CLASS) == (n <= 1))
  642.           return(0);
  643.         if(op == CLASS)
  644.           p += n - 2;
  645.         break;
  646.       case MINUS:
  647.         e = pmatch(l, p);   /* Look for a match  */
  648.         while (*p++ != ENDPAT); /* Skip over pattern */
  649.         if(e)      /* Got a match?  */
  650.           l = e;     /* Yes, update string  */
  651.         break;      /* Always succeeds */
  652.       case PLUS:      /* One or more ... */
  653.         if((l = pmatch(l, p)) == 0)
  654.           return(0);     /* Gotta have a match  */
  655.       case STAR:      /* Zero or more ...  */
  656.         are = l;    /* Remember line start */
  657.         while(*l != 0 && (e = pmatch(l, p)) != 0)
  658.           l = e;     /* Get longest match */
  659.         while (*p++ != ENDPAT); /* Skip over pattern */
  660.         while (l >= are)
  661.         {  /* Try to match rest */
  662.           if((e = pmatch(l, p)) != 0)
  663.             return(e);
  664.           --l;     /* Nope, try earlier */
  665.         }
  666.         return(0);    /* Nothing else worked */
  667.       default:
  668.         printf("Bad op code %d\n", op);
  669.         error("Cannot happen -- match\n");
  670.     }
  671.   }
  672.   return(l);
  673. }
  674. /*******************************************************/
  675. static void error(char *s)
  676. {
  677.   /*-- JAJ pipe to stdout so Zeus can see it
  678.   //   fprintf(stderr, "%s", s); */
  679.   fprintf(stdout, "%s", s);
  680.   exit(1);
  681. }
  682.  
  683. static int find_files(char *pattern, char *path)
  684. {
  685.   struct ffblk ffblk;
  686.   int done;
  687.   char *str;
  688.   char *t_path;
  689.   int count = 0;
  690.  
  691.   str = malloc(256);
  692.   t_path = malloc(256);
  693.   if(!str || !t_path)
  694.     error("Out of mem");
  695.  
  696.   if(search_subdirectories)
  697.   { /* First scan all subdirectories when the -d option is set */
  698.     strcpy(str, path);
  699.     strcat(str, "\\*.*");
  700.  
  701.     done = findfirst(str, &ffblk, FA_DIREC);
  702.     while(!done)
  703.     {
  704.       if(ffblk.ff_attrib & FA_DIREC)
  705.       {
  706.         if(strcmp(ffblk.ff_name, ".") && strcmp(ffblk.ff_name, ".."))
  707.         {
  708.           strcpy(t_path, path);
  709.           strcat(t_path, "\\");
  710.           strcat(t_path, ffblk.ff_name);
  711.           count += find_files(pattern, t_path);
  712.         }
  713.       }
  714.       done = findnext(&ffblk);
  715.     }
  716.   }
  717.   strcpy(str, path);
  718.   strcat(str, "\\");
  719.   strcat(str, pattern);
  720.  
  721.   done = findfirst(str, &ffblk, 0);
  722.   while(!done)
  723.   {
  724.     strcpy(t_path, path);
  725.     strcat(t_path, "\\");
  726.     strcat(t_path, ffblk.ff_name);
  727.     grep(t_path);
  728.     count++;
  729.     done = findnext(&ffblk);
  730.   }
  731.  
  732.   free(str);
  733.   free(t_path);
  734.   return count;
  735. }
  736.  
  737. static char *grep_strtok(char **str, char *match, char *found)
  738. {
  739.   char *s = *str, *s2, *s3 = *str;
  740.   if(*str == NULL)
  741.     return NULL;
  742.   while((s2 = strchr(match, *s)) == NULL)
  743.     s++;
  744.   *found = *s2;
  745.   if(*s == '\0')
  746.     *str = NULL;
  747.   else
  748.   {
  749.     *s = '\0';
  750.     *str = &s[1];
  751.   }
  752.   return s3;
  753. }
  754.  
  755. static char grep_tolower(char ch)
  756. {
  757.   return ignore_case_flag ? tolower(ch) : ch;
  758.  
  759. }
  760.  
  761.