home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / compsrcs / unix / volume05 / bmgsubs < prev    next >
Encoding:
Text File  |  1988-09-11  |  17.1 KB  |  745 lines

  1. Subject: bmgsubs - Boyer-Moore-Gosper fast string search subroutines
  2. Newsgroups: mod.sources
  3. Approved: jpn@panda.UUCP
  4.  
  5. Mod.sources:  Volume 5, Issue 14
  6. Submitted by: Jeff Mogul <talcott!su-navajo.arpa:mogul>
  7.  
  8. : Run this shell script with "sh" not "csh"
  9. PATH=:/bin:/usr/bin:/usr/ucb
  10. export PATH
  11. all=FALSE
  12. if [ $1x = -ax ]; then
  13.     all=TRUE
  14. fi
  15. /bin/echo 'Extracting README'
  16. sed 's/^X//' <<'//go.sysin dd *' >README
  17. Here are routines to perform fast string searches using the
  18. Boyer-Moore-Gosper algorithm; they can be used in any Unix program (and
  19. should be portable to non-Unix systems).  You can search either a file
  20. or a buffer in memory.
  21.  
  22. The code is mostly due to James A. Woods (jaw@ames-aurora.arpa)
  23. although I have modified it heavily, so all bugs are my fault.  The
  24. original code is from his sped-up version of egrep, recently posted on
  25. mod.sources and available via anonymous FTP from ames-aurora.arpa as
  26. pub/egrep.one and pub/egrep.two.  That code handles regular
  27. expressions; mine does not.
  28.  
  29. The files included here are
  30.     README        This file
  31.     Makefile        Can be modified for 4.xBSD or Sys V compilation
  32.     bmgsubs.3l        Manual page
  33.     bmgsubs.c        The search code
  34.     bmgtest.c        Test program (example of file searching)
  35.     bmgtest2.c        Another test program, showing buffer searching
  36.  
  37. These have only been tested on 4.2BSD Vax systems.
  38.  
  39. -Jeff Mogul
  40. mogul@navajo.stanford.edu
  41. decwrl!glacier!navajo!mogul
  42. //go.sysin dd *
  43. made=TRUE
  44. if [ $made = TRUE ]; then
  45.     /bin/chmod 664 README
  46.     /bin/echo -n '    '; /bin/ls -ld README
  47. fi
  48. /bin/echo 'Extracting Makefile'
  49. sed 's/^X//' <<'//go.sysin dd *' >Makefile
  50. # Makefile for bmgsubs (Boyer-Moore-Gosper subroutines)
  51. #
  52.  
  53. #
  54. # Define BSD if you're compiling this for a 4.xBSD system
  55. #    (BSD has bcopy, has index() instead of strchr().)
  56. #
  57. ENV = -DBSD
  58.  
  59. CFLAGS = -O
  60.  
  61. bmgsubs.o: bmgsubs.c
  62.  
  63. bmgtest: bmgsubs.o bmgtest.o
  64.     cc -o bmgtest bmgsubs.o bmgtest.o
  65.  
  66. bmgtest2: bmgsubs.o bmgtest2.o
  67.     cc -o bmgtest2 bmgsubs.o bmgtest2.o
  68.  
  69. clean:
  70.     rm -f bmgtest bmgtest2 *.o *.BAK *.CKP
  71. //go.sysin dd *
  72. made=TRUE
  73. if [ $made = TRUE ]; then
  74.     /bin/chmod 664 Makefile
  75.     /bin/echo -n '    '; /bin/ls -ld Makefile
  76. fi
  77. /bin/echo 'Extracting bmgsubs.3l'
  78. sed 's/^X//' <<'//go.sysin dd *' >bmgsubs.3l
  79. X.TH BMGSUBS 3L "16 May 1986"
  80. X.SH NAME
  81. (bmgsubs) bmg_setup, bmg_search, bmg_fsearch \- Boyer-Moore-Gosper string search routines
  82. X.SH SYNOPSIS
  83. bmg_setup(search_string, case_fold_flag)
  84. X.br
  85. char *search_string;
  86. X.br
  87. int case_fold_flag;
  88. X.sp
  89. bmg_fsearch(file_des, action_func)
  90. X.br
  91. int file_des;
  92. X.br
  93. int (*action_func)();
  94. X.sp
  95. bmg_search(buffer_base, buffer_length, action_func)
  96. X.br
  97. char *buffer_base;
  98. X.br
  99. int buffer_length;
  100. X.br
  101. int (*action_func)();
  102. X.SH DESCRIPTION
  103. These routines perform fast searches for strings, using the
  104. Boyer-Moore-Gosper algorithm.  No meta-characters
  105. (such as `*' or `.')
  106. are interpreted, and the search string cannot contain newlines.
  107. X.PP
  108. X.I Bmg_setup
  109. must be called as the first step in performing a search.  The
  110. X.I search_string
  111. parameter is the string to be searched for.
  112. X.I Case_fold_flag
  113. should be false (zero) if characters should match exactly, and
  114. true (non-zero) if case should be ignored when checking for
  115. matches.
  116. X.PP
  117. Once a search string has been specified using
  118. X.IR bmg_setup ,
  119. one or more searches for that string may be performed.
  120. X.PP
  121. X.I Bmg_fsearch
  122. searches a file, open for reading on file descriptor
  123. X.I file_des
  124. (this is
  125. X.I not
  126. a
  127. X.I stdio
  128. file.)
  129. For each line that contains the search string,
  130. X.I bmg_fsearch
  131. will call the
  132. X.I action_func
  133. function specified by the caller as
  134. action_func(matching_line, byte_offset).
  135. The
  136. X.I matching_line
  137. parameter is a (char *) pointer to a temporary copy of the line;
  138. X.I byte_offset
  139. is the offset from the beginning of the file to the first occurence
  140. of the search string in that line.
  141. X.I Action_func
  142. should return true (non-zero) if the search should continue, or
  143. false (zero) if the search should terminate at this point.
  144. X.PP
  145. X.I Bmg_search
  146. is like
  147. X.IR bmg_fsearch ,
  148. except that instead of searching a file, it searches the buffer
  149. pointed to by
  150. X.IR buffer_base ;
  151. X.I buffer_length
  152. specifies the number of bytes in the buffer.
  153. The
  154. X.I byte_offset
  155. parameter to
  156. X.I action_func
  157. gives the offset from the beginning of the buffer.
  158. X.PP
  159. If the user merely wants the matching lines printed on the
  160. standard output, the
  161. X.I action_func
  162. parameter
  163. to
  164. X.I bmg_fsearch
  165. or
  166. X.I bmg_search
  167. can be NULL.
  168. X.SH AUTHOR
  169. Jeffrey Mogul (Stanford University), based on code written
  170. by James A. Woods (NASA Ames)
  171. X.SH BUGS
  172. Might be nice to have a version of this that handles regular expressions.
  173. X.PP
  174. There are large, but finite, limits on the length of both pattern
  175. strings and text lines.  When these limits are exceeded, all bets are off.
  176. X.PP
  177. The string pointer passed to
  178. X.I action_func
  179. points to a temporary copy of the matching line, and must be
  180. copied elsewhere before
  181. X.I action_func
  182. returns.
  183. X.PP
  184. X.I Bmg_search
  185. does not
  186. X.I permanently
  187. modify the buffer in any way, but during its execution (and therefore
  188. when
  189. X.I action_func
  190. is called), the last byte of the buffer may be temporarily changed.
  191. X.PP
  192. The Boyer-Moore algorithm cannot find lines that do not contain
  193. a given pattern (like "grep -v") or count lines ("grep -n").
  194. Although it is fast even for short search strings, it gets faster as
  195. the search string length increases.
  196. //go.sysin dd *
  197. made=TRUE
  198. if [ $made = TRUE ]; then
  199.     /bin/chmod 664 bmgsubs.3l
  200.     /bin/echo -n '    '; /bin/ls -ld bmgsubs.3l
  201. fi
  202. /bin/echo 'Extracting bmgsubs.c'
  203. sed 's/^X//' <<'//go.sysin dd *' >bmgsubs.c
  204. X/*
  205.  * bmgsubs.c
  206.  *
  207.  * Subroutines for fast string searching; no regular expressions
  208.  *
  209.  * Entries:
  210.  *
  211.  * bmg_setup(pattern_string, case_fold_flag)
  212.  * char *pattern_string;    -- the string you are searching for
  213.  * int case_fold_flag;        -- true if you want search to ignore case
  214.  *
  215.  * bmg_fsearch(file_des, action_func)
  216.  * int file_des;        -- file descriptor to read on
  217.  * int (*action_func)();    -- called on each hit
  218.  *
  219.  * bmg_search(buffer, buflen, action_func)
  220.  * char *buffer;        -- buffer to search
  221.  * int buflen;            -- bytes in buffer
  222.  * int (*action_func)();    -- called on each hit
  223.  *
  224.  * Usage:
  225.  *    Start by calling bmg_setup() to specify a pattern.  Then open
  226.  * the file you want to search and pass the file descriptor (NOT a
  227.  * stdio file pointer) to bmg_fsearch().  For each line that contains
  228.  * the pattern, bmg_fsearch() will call action_func(string, position)
  229.  * with string being a static copy of the matching line and position
  230.  * being the disntance in bytes from the beginning of the search to the
  231.  * matching substring.
  232.  *    action_func() should return a non-zero integer unless the
  233.  * search should be terminated, in which case it should return 0.
  234.  *    bmg_search() works the same as bmg_fsearch(), but searches
  235.  * a buffer rather than a file.
  236.  *
  237.  * Adapted from:
  238.  *
  239.      Boyer/Moore/Gosper-assisted 'egrep' search, with delta0 table as in
  240.      original paper (CACM, October, 1977).  No delta1 or delta2.  According to
  241.      experiment (Horspool, Soft. Prac. Exp., 1982), delta2 is of minimal
  242.      practical value.  However, to improve for worst case input, integrating
  243.      the improved Galil strategies (Apostolico/Giancarlo, Siam. J. Comput.,
  244.      February 1986) deserves consideration.
  245.  
  246.      James A. Woods                    Copyright (c) 1986
  247.      NASA Ames Research Center
  248.  *
  249.  * 29 April 1986    Jeff Mogul    Stanford
  250.  *    Adapted as a set of subroutines for use by a program. No
  251.  *    regular-expression support.
  252.  */
  253.  
  254. #include <stdio.h>
  255. #include <ctype.h>
  256. #include <sys/types.h>
  257.  
  258. #ifdef    BSD
  259. #define    strchr    index
  260. #endif
  261. #ifndef    BUFSIZE
  262. #define BUFSIZE    8192
  263. #endif    BUFSIZE
  264. #ifndef    PATSIZE
  265. #define PATSIZE 1000
  266. #endif    PATSIZE
  267. #define LARGE     BUFSIZE + PATSIZE
  268. #define NL    '\n'
  269. #define    EOS    '\0'
  270.  
  271. struct bmg_data {
  272.     int     bmg_delta0[256];        /* ascii only */
  273.     char    bmg_cmap[256];        /* (un)folded characters */
  274.     char    bmg_str[BUFSIZE + 2];
  275.     char    bmg_linetemp[BUFSIZE];
  276.     char    bmg_pattern[PATSIZE];
  277.     int    bmg_patlen;
  278.     int    bmg_nsuccess;
  279. } bmdata;
  280. #define delta0    bmdata.bmg_delta0
  281. #define cmap    bmdata.bmg_cmap
  282. #define str    bmdata.bmg_str
  283. #define linetemp    bmdata.bmg_linetemp
  284. #define    pattern    bmdata.bmg_pattern
  285. #define    patlen    bmdata.bmg_patlen
  286. #define    nsuccess    bmdata.bmg_nsuccess
  287.  
  288. char   *strcpy(), *strncpy(), *malloc();
  289.  
  290. bmg_search(buffer, buflen, action)
  291. char    *buffer;
  292. int    buflen;
  293. int    (*action)();
  294. {
  295.     register char  *k,
  296.                    *strend,
  297.                    *s;
  298.     register int    j;
  299.     char   *t;
  300.     char   *strbegin;
  301.     char   *gotamatch();
  302.     int     byte_offset = 0;
  303.     char    last_byte = buffer[buflen - 1];
  304.  
  305.     nsuccess = 0;
  306.  
  307.     /* make sure that buffer ends with NL */
  308.     if (last_byte != NL)
  309.         buffer[buflen - 1] = NL;
  310.  
  311.     /*
  312.      * We must process the buffer in chunks of BUFSIZE to make
  313.      * "LARGE" hack work right.
  314.      */
  315.     for (strbegin = buffer;
  316.         strbegin < &buffer[buflen]; strbegin += BUFSIZE) {
  317.         strend = strbegin + BUFSIZE;
  318.  
  319.         if (strend > &buffer[buflen])    /* stay inside buffer */
  320.         strend = &buffer[buflen];
  321.         
  322.         /* find end of last full line in this chunk of the buffer */
  323.         s = strbegin;
  324.         while ((strend[-1]) != NL && (strend > s))
  325.         strend--;
  326.         if (strend <= strbegin)    /* line longer than BUFSIZE, punt */
  327.         continue;
  328.  
  329.         k = strbegin + patlen - 1;
  330.  
  331.         for (;;) {
  332.         /* 
  333.          for a large class of patterns, upwards of 80% of 
  334.          match time is spent on the next line.  
  335.          we beat existing microcode (vax 'matchc') this way.
  336.          */
  337.         while ((k += delta0[*(unsigned char *) k]) < strend)
  338.             ;
  339.         if (k < (strbegin + LARGE))
  340.             break;
  341.         k -= LARGE;
  342.     
  343.         j = patlen - 1;
  344.         s = k - 1;
  345.         while (cmap[*s--] == pattern[--j]);
  346.         /* 
  347.          * delta-less shortcut for literati, but 
  348.          * short shrift for genetic engineers.
  349.          */
  350.         if (j >= 0)
  351.             k++;
  352.         else {        /* submatch */
  353.             t = k;
  354.             s = k - patlen + 1;
  355.             do
  356.             ;
  357.             while (*s != NL && --s >= strbegin);
  358.             k = s + 1;    /* at line start */
  359.     
  360.             if ((k = gotamatch( k,
  361.                     (t - buffer),
  362.                     action)) == NULL)
  363.             return;
  364.             if (k >= strend)
  365.             break;
  366.         }
  367.         }
  368.     }
  369.     if (buffer[buflen - 1] != last_byte)
  370.         buffer[buflen - 1] = last_byte;
  371.     return(nsuccess);
  372. }
  373.  
  374. bmg_fsearch(fd, action)
  375. int    fd;
  376. int    (*action)();
  377. {
  378.     register char  *k,
  379.                    *strend,
  380.                    *s;
  381.     register int    j;
  382.     char   *t;
  383.     char   *gotamatch();
  384.     int     nleftover,
  385.             count,
  386.         file_offset = 0;
  387.  
  388.     nleftover  = 0;
  389.     nsuccess = 0;
  390.  
  391.     while ((count = read(fd, str + nleftover, BUFSIZE - nleftover)) > 0) {
  392.         count += nleftover;
  393.         if (count != BUFSIZE && fd != 0) {
  394.         str[count++] = NL;    /* insurance for broken last line */
  395.         }
  396.         str[count] = 0;
  397.         for (j = count - 1; str[j] != NL && j >= 0;)
  398.         j--;
  399.         if (j < 0) {    /* break up long line */
  400.         str[count] = NL;
  401.         str[++count] = EOS;
  402.         strend = str + count;
  403.         linetemp[0] = EOS;
  404.         nleftover = 0;
  405.         }
  406.         else {        /* save partial line */
  407.         strend = str + j;
  408.         nleftover = count - j - 1;
  409.         strncpy(linetemp, str + j + 1, nleftover);
  410.         }
  411.         k = str + patlen - 1;
  412.  
  413.         for (;;) {
  414.         /* 
  415.          for a large class of patterns, upwards of 80% of 
  416.          match time is spent on the next line.  
  417.          we beat existing microcode (vax 'matchc') this way.
  418.          */
  419.         while ((k += delta0[*(unsigned char *) k]) < strend)
  420.             ;
  421.         if (k < (str + LARGE))
  422.             break;
  423.         k -= LARGE;
  424.  
  425.         j = patlen - 1;
  426.         s = k - 1;
  427.         while (cmap[*s--] == pattern[--j]);
  428.         /* 
  429.          * delta-less shortcut for literati, but 
  430.          * short shrift for genetic engineers.
  431.          */
  432.         if (j >= 0)
  433.             k++;
  434.         else {        /* submatch */
  435.             t = k;
  436.             s = k - patlen + 1;
  437.             do
  438.                 ;
  439.             while (*s != NL && --s >= str);
  440.             k = s + 1;    /* at line start */
  441.  
  442.             if ((k = gotamatch( k,
  443.                         (file_offset + (t - str)),
  444.                     action)) == NULL)
  445.             return;
  446.             if (k >= strend)
  447.             break;
  448.         }
  449.         }
  450.         file_offset += ( 1 + (strend - str));
  451.         strncpy(str, linetemp, nleftover);
  452.     }
  453.     return(nsuccess);
  454. }
  455.  
  456. bmg_setup(pat, folded)        /* compute "boyer-moore" delta table */
  457. char   *pat;        /* ... HAKMEM lives ... */
  458. int    folded;
  459. {
  460.     register int    j;
  461.     /* 
  462.      for multibyte characters (e.g. kanji), there are ways.
  463.      extrapolating 256 to 64K may be unwise, in favor of more
  464.      dynamics within boyermoore() itself. 
  465.      */
  466.     patlen = strlen(pat);
  467.     if (folded) {    /* fold case while saving pattern */
  468.         for (j = 0; j < patlen; j++) {
  469.         pattern[j] = (isupper((int) pat[j]) 
  470.                 ? (char) tolower((int) pat[j]) : pat[j]);
  471.         }
  472.     }
  473.     else
  474.         bcopy(pat, pattern, patlen);
  475.  
  476.     for (j = 0; j < 256; j++) {
  477.         delta0[j] = patlen;
  478.         cmap[j] = (char) j;    /* could be done at compile time */
  479.     }
  480.     for (j = 0; j < patlen - 1; j++)
  481.         delta0[pattern[j]] = patlen - j - 1;
  482.     delta0[pattern[patlen - 1]] = LARGE;
  483.  
  484.     if (folded) {
  485.         for (j = 0; j < patlen - 1; j++)
  486.         if (islower((int) pattern[j]))
  487.             delta0[toupper((int) pattern[j])] = patlen - j - 1;
  488.         if (islower((int) pattern[patlen - 1]))
  489.         delta0[toupper((int) pattern[patlen - 1])] = LARGE;
  490.         for (j = 'A'; j <= 'Z'; j++)
  491.         cmap[j] = (char) tolower((int) j);
  492.     }
  493. }
  494.  
  495. static char *gotamatch(s, pos, action)
  496. register char *s;
  497. register int pos;
  498. int (*action)();
  499. {
  500.     static char    result[BUFSIZE];
  501.     register char *r = result;
  502.  
  503.     nsuccess++;
  504.     do
  505.         *r++ = *s;
  506.     while (*s++ != NL);
  507.     *r = 0;
  508.     if (action == NULL) {
  509.         printf("%s", result);
  510.         return(s);
  511.     }
  512.     else
  513.         if (action(result, pos))
  514.         return(s);
  515.         else
  516.             return(NULL);
  517. }
  518.  
  519. #ifndef    BSD
  520. bcopy(from, to, len)
  521. register char *from;
  522. register char *to;
  523. register int len;
  524. {
  525.     while (len-- > 0) {
  526.         *to++ = *from++;
  527.     }
  528. }
  529. #endif    BSD
  530. //go.sysin dd *
  531. made=TRUE
  532. if [ $made = TRUE ]; then
  533.     /bin/chmod 664 bmgsubs.c
  534.     /bin/echo -n '    '; /bin/ls -ld bmgsubs.c
  535. fi
  536. /bin/echo 'Extracting bmgtest.c'
  537. sed 's/^X//' <<'//go.sysin dd *' >bmgtest.c
  538. X/*
  539.  * bmgtest.c
  540.  *
  541.  * Test driver/example program for Boyer-Moore-Gosper search routines
  542.  *
  543.  * Works like a stupid grep; takes only a few flags (-i, -n)
  544.  */
  545.  
  546. #include <stdio.h>
  547. #include <ctype.h>
  548. #include <sys/types.h>
  549.  
  550. #ifdef    BSD
  551. #define    strchr    index
  552. #endif
  553.  
  554. int     iflag = 0,
  555.         nflag = 0;
  556.  
  557. X/*
  558.  * Called by bmg_fsearch for each line that matches the pattern
  559.  */
  560. printit(string, pos)
  561. char   *string;            /* pointer to temporary copy of line */
  562. int     pos;            /* byte offset from beginning of file */
  563. {
  564.     if (nflag)
  565.         printf("%d: %s", pos, string);
  566.     else
  567.         printf("%s", string);
  568.     return(1);    /* tells bmg_fsearch to continue the search */
  569. }
  570.  
  571. main(argc, argv)
  572. int     argc;
  573. char  **argv;
  574. {
  575.     int     nsuccess,
  576.             fd;
  577.     char   *pattern;
  578.  
  579.     while ((argc > 1) && (argv[1][0] == '-')) {
  580.         switch (argv[1][1]) {
  581.         case 'i': 
  582.             iflag++;
  583.             break;
  584.         case 'n': 
  585.             nflag++;
  586.             break;
  587.         default: 
  588.             oops("usage: bmgtest [-i] [-n] pattern [file ...]");
  589.         }
  590.         argc--;
  591.         argv++;
  592.     }
  593.     argv++;
  594.     if (argc <= 1)
  595.          oops("bmgtest: pattern argument missing");
  596.     pattern = *argv;
  597.     argc--;
  598.     argv++;
  599.  
  600.     bmg_setup(pattern, iflag);
  601.  
  602.     if (argc <= 1) {    /* process stdin */
  603.         fd = 0;
  604.         bmg_fsearch(fd, printit);
  605.     }
  606.     else {
  607.         while (--argc > 0) {
  608.         if ((fd = open(*argv, 0)) <= 0) {
  609.             fprintf(stderr, "bmgtest: can't open %s\n", *argv);
  610.             nsuccess = 2;
  611.             argv++;
  612.             continue;
  613.         }
  614.         bmg_fsearch(fd, printit);
  615.         close(fd);
  616.         argv++;
  617.         }
  618.     }
  619.     exit((nsuccess == 2) ? 2 : (nsuccess == 0));
  620. }
  621.  
  622. oops(message)
  623. char   *message;
  624. {
  625.     fprintf(stderr, "%s\n", message);
  626.     exit(2);
  627. }
  628. //go.sysin dd *
  629. made=TRUE
  630. if [ $made = TRUE ]; then
  631.     /bin/chmod 664 bmgtest.c
  632.     /bin/echo -n '    '; /bin/ls -ld bmgtest.c
  633. fi
  634. /bin/echo 'Extracting bmgtest2.c'
  635. sed 's/^X//' <<'//go.sysin dd *' >bmgtest2.c
  636. X/*
  637.  * bmgtest2.c
  638.  *
  639.  * Test driver/example program for Boyer-Moore-Gosper search routines
  640.  *    does buffer search instead of file search.
  641.  *
  642.  * Works like a very stupid grep; takes only a few flags (-i, -n)
  643.  */
  644.  
  645. #include <stdio.h>
  646. #include <ctype.h>
  647. #include <sys/types.h>
  648. #include <sys/stat.h>
  649.  
  650. char *malloc();
  651.  
  652. #ifdef    BSD
  653. #define    strchr    index
  654. #endif
  655.  
  656. int     iflag = 0,
  657.         nflag = 0;
  658.  
  659. X/*
  660.  * Called by bmg_search for each line that matches the pattern
  661.  */
  662. printit(string, pos)
  663. char   *string;            /* pointer to temporary copy of line */
  664. int     pos;            /* byte offset from beginning of file */
  665. {
  666.     if (nflag)
  667.         printf("%d: %s", pos, string);
  668.     else
  669.         printf("%s", string);
  670.     return(1);    /* tells bmg_fsearch to continue the search */
  671. }
  672.  
  673. main(argc, argv)
  674. int     argc;
  675. char  **argv;
  676. {
  677.     int     nsuccess,
  678.             fd;
  679.     char   *pattern;
  680.     struct stat statbuf;
  681.     char    *buffer;
  682.  
  683.     while ((argc > 1) && (argv[1][0] == '-')) {
  684.         switch (argv[1][1]) {
  685.         case 'i': 
  686.             iflag++;
  687.             break;
  688.         case 'n': 
  689.             nflag++;
  690.             break;
  691.         default: 
  692.             oops("usage: bmgtest [-i] [-n] pattern [file ...]");
  693.         }
  694.         argc--;
  695.         argv++;
  696.     }
  697.     argv++;
  698.     if (argc <= 1)
  699.          oops("bmgtest: pattern argument missing");
  700.     pattern = *argv;
  701.     argc--;
  702.     argv++;
  703.  
  704.     bmg_setup(pattern, iflag);
  705.  
  706.     if (argc <= 1) {    /* process stdin */
  707.         fd = 0;
  708.         bmg_fsearch(fd, printit);
  709.     }
  710.     else {
  711.         while (--argc > 0) {
  712.         if ((fd = open(*argv, 0)) <= 0) {
  713.             fprintf(stderr, "bmgtest: can't open %s\n", *argv);
  714.             nsuccess = 2;
  715.             argv++;
  716.             continue;
  717.         }
  718.         fstat(fd, &statbuf);
  719.         buffer = malloc(statbuf.st_size);
  720.         if (buffer == 0)
  721.             oops("malloc failure");
  722.         read(fd, buffer, statbuf.st_size);
  723.         bmg_search(buffer, statbuf.st_size, printit);
  724.         close(fd);
  725.         free(buffer);
  726.         argv++;
  727.         }
  728.     }
  729.     exit((nsuccess == 2) ? 2 : (nsuccess == 0));
  730. }
  731.  
  732. oops(message)
  733. char   *message;
  734. {
  735.     fprintf(stderr, "%s\n", message);
  736.     exit(2);
  737. }
  738. //go.sysin dd *
  739. made=TRUE
  740. if [ $made = TRUE ]; then
  741.     /bin/chmod 664 bmgtest2.c
  742.     /bin/echo -n '    '; /bin/ls -ld bmgtest2.c
  743. fi
  744.  
  745.