home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 14 / CD_ASCQ_14_0694.iso / maj / 653 / srchfile.c < prev    next >
C/C++ Source or Header  |  1994-04-03  |  6KB  |  226 lines

  1. /*
  2. **  SRCHFILE.C - Functions for searching files
  3. **
  4. **  public domain by Bob Stout
  5. **
  6. **  Note: Although this snippet demonstrates some useful techniques, even
  7. **        the fast text searching algorithm used can't provide particularly
  8. **        good performance. Left as an exercise for the user is to perform
  9. **        explicit buffering using fread() rather than fgets() as is used
  10. **        here. See CHBYTES.C in SNIPPETS for how to perform searches in
  11. **        user-managed buffers.
  12. */
  13.  
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17.  
  18. #define SUCCESS 0
  19.  
  20. /*
  21. **  Allocate a big buffer, use it to buffer a specified stream
  22. */
  23.  
  24. static size_t fsetup(FILE *fp, size_t minbuf)
  25. {
  26.       register size_t bufsize;
  27.       register char *buffer;
  28.  
  29.       /* Allocate the largest buffer we can */
  30.  
  31.       for (bufsize = 0x4000; bufsize >= minbuf; bufsize >>= 1)
  32.       {
  33.             if (NULL != (buffer = (char *) malloc(bufsize)))
  34.                   break;
  35.       }
  36.       if (NULL == buffer)
  37.             return 0;
  38.  
  39.       /* Use the buffer to buffer the file */
  40.  
  41.       if (SUCCESS == setvbuf(fp, buffer, _IOFBF, bufsize))
  42.             return bufsize;
  43.       else  return 0;
  44. }
  45.  
  46. /*
  47. **  Search a file for a pattern match (forward)
  48. **
  49. **  Arguments: FILE pointer
  50. **             pattern to search for
  51. **             size of pattern
  52. **             find Nth occurance
  53. **
  54. **  Returns: -1L if pattern not found
  55. **           -2L in case of error
  56. */
  57.  
  58. long ffsearch(FILE *fp, const char *pattern, const size_t size, int N)
  59. {
  60.       long pos = -2L, tempos = 0L;
  61.       char *sbuf, *p;
  62.       size_t i, skip;
  63.       int ch = 0;
  64.  
  65.       /* Allocate a search buffer */
  66.  
  67.       if (NULL == (sbuf = (char *)malloc(size - 1)))
  68.             goto FDONE;
  69.  
  70.       /* Buffer the file and position us within it */
  71.  
  72.       if (0 == fsetup(fp, size))
  73.             goto FDONE;
  74.       pos = -1L;
  75.       fseek(fp, 0L, SEEK_SET);
  76.  
  77.       /* Set up for smart searching */
  78.  
  79.       if (1 < strlen(pattern) && NULL != (p = strchr(pattern + 1, *pattern)))
  80.             skip = p - (char *)pattern;
  81.       else  skip = strlen(pattern);
  82.  
  83.       /* Look for the pattern */
  84.  
  85.       while (EOF != ch)
  86.       {
  87.             if (EOF == (ch = fgetc(fp)))
  88.                   break;
  89.             if ((int)*pattern == ch)
  90.             {
  91.                   tempos = ftell(fp);
  92.                   if (size - 1 > fread(sbuf, sizeof(char), size - 1, fp))
  93.                         goto FDONE;
  94.                   if (SUCCESS == memcmp(sbuf, &pattern[1], size - 1))
  95.                   {
  96.                         if (0 == --N)
  97.                         {
  98.                               pos = tempos - 1L;
  99.                               goto FDONE;
  100.                         }
  101.                   }
  102.                   fseek(fp, tempos + skip, SEEK_SET);
  103.             }
  104.       }
  105.  
  106.       /* Clean up and leave */
  107.  
  108. FDONE:
  109.       free(sbuf);
  110.       return pos;
  111. }
  112.  
  113. /*
  114. **  Search a file for a pattern match (backwards)
  115. **
  116. **  Arguments: FILE pointer
  117. **             pattern to search for
  118. **             size of pattern
  119. **             find Nth occurance
  120. **
  121. **  Returns: -1L if pattern not found
  122. **           -2L in case of error
  123. */
  124.  
  125. long rfsearch(FILE *fp, const char *pattern, const size_t size, int N)
  126. {
  127.       long pos = -2L, tempos;
  128.       char *sbuf, *p;
  129.       size_t i, skip;
  130.       int ch = 0;
  131.  
  132.       /* Allocate a search buffer */
  133.  
  134.       if (NULL == (sbuf = (char *)malloc(size - 1)))
  135.             goto RDONE;
  136.  
  137.       /* Buffer the file and position us within it */
  138.  
  139.       if (0 == fsetup(fp, size))
  140.             goto RDONE;
  141.       pos = -1L;
  142.       fseek(fp, -1L, SEEK_END);
  143.       tempos = ftell(fp) - strlen(pattern);
  144.  
  145.       /* Set up for smart searching */
  146.  
  147.       if (1 < strlen(pattern) && NULL != (p = strrchr(pattern + 1, *pattern)))
  148.             skip = strlen(pattern) - (p - (char *)pattern);
  149.       else  skip = strlen(pattern);
  150.  
  151.       /* Look for the pattern */
  152.  
  153.       while (0L <= tempos)
  154.       {
  155.             fseek(fp, tempos, SEEK_SET);
  156.             if (EOF == (ch = fgetc(fp)))
  157.                   break;
  158.             if ((int)*pattern == ch)
  159.             {
  160.                   if (size - 1 <= fread(sbuf, sizeof(char), size - 1, fp))
  161.                   {
  162.                         if (SUCCESS == memcmp(sbuf, &pattern[1], size - 1))
  163.                         {
  164.                               if (0 == --N)
  165.                               {
  166.                                     pos = tempos;
  167.                                     goto RDONE;
  168.                               }
  169.                         }
  170.                   }
  171.                   tempos -= skip;
  172.             }
  173.             else  --tempos;
  174.       }
  175.  
  176.       /* Clean up and leave */
  177.  
  178. RDONE:
  179.       free(sbuf);
  180.       return pos;
  181. }
  182.  
  183. #ifdef TEST
  184.  
  185. int main(int argc, char *argv[])
  186. {
  187.       long pos;
  188.       int N = 1;
  189.       size_t size = strlen(argv[1]);
  190.       char buf[256], *fname = "SRCHFILE.C";
  191.       FILE *fp;
  192.  
  193.       if (2 > argc)
  194.       {
  195.             puts("Usage: SRCHFILE string [N] [file]");
  196.             puts("where: N = find Nth occurance");
  197.             puts("       If file is specified, N must be given");
  198.             return EXIT_FAILURE;
  199.       }
  200.  
  201.       if (2 < argc)
  202.             N = atoi(argv[2]);
  203.  
  204.       if (3 < argc)
  205.             fname = strupr(argv[3]);
  206.  
  207.       fp = fopen(fname, "r");
  208.       printf("ffsearch(%s, %s) returned %ld\n", fname, argv[1],
  209.             pos = ffsearch(fp, argv[1], size, N));
  210.       fseek(fp, pos, SEEK_SET);
  211.       fgets(buf, 256, fp);
  212.       printf("...which contains \"%s\"\n\n", buf);
  213.       fclose(fp);
  214.  
  215.       fp = fopen(fname, "rb");
  216.       printf("rfsearch(%s, %s) returned %ld\n", fname, argv[1],
  217.             pos = rfsearch(fp, argv[1], size, N));
  218.       fseek(fp, pos, SEEK_SET);
  219.       fgets(buf, 256, fp);
  220.       printf("...which contains \"%s\"\n\n", buf);
  221.       fclose(fp);
  222.       return EXIT_SUCCESS;
  223. }
  224.  
  225. #endif /* TEST */
  226.