summaryrefslogtreecommitdiff
path: root/reference/C/CONTRIB/SNIP/srchfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'reference/C/CONTRIB/SNIP/srchfile.c')
-rwxr-xr-xreference/C/CONTRIB/SNIP/srchfile.c225
1 files changed, 225 insertions, 0 deletions
diff --git a/reference/C/CONTRIB/SNIP/srchfile.c b/reference/C/CONTRIB/SNIP/srchfile.c
new file mode 100755
index 0000000..d55fb88
--- /dev/null
+++ b/reference/C/CONTRIB/SNIP/srchfile.c
@@ -0,0 +1,225 @@
+/*
+** SRCHFILE.C - Functions for searching files
+**
+** public domain by Bob Stout
+**
+** Note: Although this snippet demonstrates some useful techniques, even
+** the fast text searching algorithm used can't provide particularly
+** good performance. Left as an exercise for the user is to perform
+** explicit buffering using fread() rather than fgets() as is used
+** here. See CHBYTES.C in SNIPPETS for how to perform searches in
+** user-managed buffers.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define SUCCESS 0
+
+/*
+** Allocate a big buffer, use it to buffer a specified stream
+*/
+
+static size_t fsetup(FILE *fp, size_t minbuf)
+{
+ register size_t bufsize;
+ register char *buffer;
+
+ /* Allocate the largest buffer we can */
+
+ for (bufsize = 0x4000; bufsize >= minbuf; bufsize >>= 1)
+ {
+ if (NULL != (buffer = (char *) malloc(bufsize)))
+ break;
+ }
+ if (NULL == buffer)
+ return 0;
+
+ /* Use the buffer to buffer the file */
+
+ if (SUCCESS == setvbuf(fp, buffer, _IOFBF, bufsize))
+ return bufsize;
+ else return 0;
+}
+
+/*
+** Search a file for a pattern match (forward)
+**
+** Arguments: FILE pointer
+** pattern to search for
+** size of pattern
+** find Nth occurance
+**
+** Returns: -1L if pattern not found
+** -2L in case of error
+*/
+
+long ffsearch(FILE *fp, const char *pattern, const size_t size, int N)
+{
+ long pos = -2L, tempos = 0L;
+ char *sbuf, *p;
+ size_t i, skip;
+ int ch = 0;
+
+ /* Allocate a search buffer */
+
+ if (NULL == (sbuf = (char *)malloc(size - 1)))
+ goto FDONE;
+
+ /* Buffer the file and position us within it */
+
+ if (0 == fsetup(fp, size))
+ goto FDONE;
+ pos = -1L;
+ fseek(fp, 0L, SEEK_SET);
+
+ /* Set up for smart searching */
+
+ if (1 < strlen(pattern) && NULL != (p = strchr(pattern + 1, *pattern)))
+ skip = p - (char *)pattern;
+ else skip = strlen(pattern);
+
+ /* Look for the pattern */
+
+ while (EOF != ch)
+ {
+ if (EOF == (ch = fgetc(fp)))
+ break;
+ if ((int)*pattern == ch)
+ {
+ tempos = ftell(fp);
+ if (size - 1 > fread(sbuf, sizeof(char), size - 1, fp))
+ goto FDONE;
+ if (SUCCESS == memcmp(sbuf, &pattern[1], size - 1))
+ {
+ if (0 == --N)
+ {
+ pos = tempos - 1L;
+ goto FDONE;
+ }
+ }
+ fseek(fp, tempos + skip, SEEK_SET);
+ }
+ }
+
+ /* Clean up and leave */
+
+FDONE:
+ free(sbuf);
+ return pos;
+}
+
+/*
+** Search a file for a pattern match (backwards)
+**
+** Arguments: FILE pointer
+** pattern to search for
+** size of pattern
+** find Nth occurance
+**
+** Returns: -1L if pattern not found
+** -2L in case of error
+*/
+
+long rfsearch(FILE *fp, const char *pattern, const size_t size, int N)
+{
+ long pos = -2L, tempos;
+ char *sbuf, *p;
+ size_t i, skip;
+ int ch = 0;
+
+ /* Allocate a search buffer */
+
+ if (NULL == (sbuf = (char *)malloc(size - 1)))
+ goto RDONE;
+
+ /* Buffer the file and position us within it */
+
+ if (0 == fsetup(fp, size))
+ goto RDONE;
+ pos = -1L;
+ fseek(fp, -1L, SEEK_END);
+ tempos = ftell(fp) - strlen(pattern);
+
+ /* Set up for smart searching */
+
+ if (1 < strlen(pattern) && NULL != (p = strrchr(pattern + 1, *pattern)))
+ skip = strlen(pattern) - (p - (char *)pattern);
+ else skip = strlen(pattern);
+
+ /* Look for the pattern */
+
+ while (0L <= tempos)
+ {
+ fseek(fp, tempos, SEEK_SET);
+ if (EOF == (ch = fgetc(fp)))
+ break;
+ if ((int)*pattern == ch)
+ {
+ if (size - 1 <= fread(sbuf, sizeof(char), size - 1, fp))
+ {
+ if (SUCCESS == memcmp(sbuf, &pattern[1], size - 1))
+ {
+ if (0 == --N)
+ {
+ pos = tempos;
+ goto RDONE;
+ }
+ }
+ }
+ tempos -= skip;
+ }
+ else --tempos;
+ }
+
+ /* Clean up and leave */
+
+RDONE:
+ free(sbuf);
+ return pos;
+}
+
+#ifdef TEST
+
+int main(int argc, char *argv[])
+{
+ long pos;
+ int N = 1;
+ size_t size = strlen(argv[1]);
+ char buf[256], *fname = "SRCHFILE.C";
+ FILE *fp;
+
+ if (2 > argc)
+ {
+ puts("Usage: SRCHFILE string [N] [file]");
+ puts("where: N = find Nth occurance");
+ puts(" If file is specified, N must be given");
+ return EXIT_FAILURE;
+ }
+
+ if (2 < argc)
+ N = atoi(argv[2]);
+
+ if (3 < argc)
+ fname = strupr(argv[3]);
+
+ fp = fopen(fname, "r");
+ printf("ffsearch(%s, %s) returned %ld\n", fname, argv[1],
+ pos = ffsearch(fp, argv[1], size, N));
+ fseek(fp, pos, SEEK_SET);
+ fgets(buf, 256, fp);
+ printf("...which contains \"%s\"\n\n", buf);
+ fclose(fp);
+
+ fp = fopen(fname, "rb");
+ printf("rfsearch(%s, %s) returned %ld\n", fname, argv[1],
+ pos = rfsearch(fp, argv[1], size, N));
+ fseek(fp, pos, SEEK_SET);
+ fgets(buf, 256, fp);
+ printf("...which contains \"%s\"\n\n", buf);
+ fclose(fp);
+ return EXIT_SUCCESS;
+}
+
+#endif /* TEST */