home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / snip9707.zip / SRCHFILE.C < prev    next >
C/C++ Source or Header  |  1997-07-05  |  6KB  |  227 lines

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