/*              Find Pattern
*
*      This is a program which prints out all lines in a file with a
* given pattern.  It can be conditionally compiled for either CP/M or
* Unix.  In either case, it is invoked by:
*
*              fp <pattern> <file(s)>
*
*      The <file(s)> specification can use normal file widcards, as
* defined by wildexp in CP/M and the shell in Unix.
*      The <pattern> is a string of characters, some of which have special
* meanings:
*
*              <char> - any character not listed below matches exactly that
*                       character.
*              ? - matches any single character.
*              * - matches zero or more of any character.
*              [...] - matches one of any of the characters included between
*                      the brackets; character ranges can also be indicated
*                      by <char>-<char>.  E.g., [a-z0-9] will match any
*                      letter or digit.
*              [-...] - matches one of any of the characters not included
*                       between the brackets.
*
*      Also, backslash (\) can be used to quote characters (i.e., keep them
* from being interpreted specially).
*
*      To compile and load the program, make sure that one of UNIX or CPM
* is defined (not both!) in fp.c, and that you have pat.h and pat.c (and
* wildexp.crl).  On CP/M, then do:
*
*              cc1 pat.c
*              cc1 fp.c
*              clink fp pat wildexp
*
*      On Unix, then do:
*
*              cc -O -o fp fp.c pat.c
*
*      Note: On Unix, fp runs about three times slower than grep, so it's
* not clear why you'd want to use it.  This is probably because I use
* recursion.  Maybe I'll do a non-recursive version later, but this way
* is much simpler.
*
*
*      Initial coding 8/18/82 by Harry R. Chesley.
*
*
*      Copyright 1982 by Harry R. Chesley.
*      Unlimited permission granted for non-profit use only.
*/

#include "pat.h"

/* UNIX - defined for use on Unix.
* CPM - defined for use on CP/M (with BDS-C).
*
* MAXBSZ - max size of text buffer (big to minimize IO); should be a multiple
*          of 128 for CPM, but doesn't really have to be.  One more char is
*          allocated so that a zero byte can be appended when printing
*          strings.
* MAXPSZ - max size of pattern string.
*/

#define UNIX
/*#define CPM*/

#define MAXBSZ 10240+1
#define MAXPSZ 100

/*      main()
*
*      Function: Invoked by "fp <pattern> <files>".  Prints every line in
* each file containing the pattern.
*
*      Algorithm: Use srchpat() to locate each subsequent line to be output.
*
*      Comments: The only tricky things here are: (1) The search pattern is
* surrounded with "*"s because srchpat() will only do exact matches;
* inserting the "*"s makes it match the pattern anywhere on the line.  And
* (2) when we find outselves at the end of a buffer, we read in a new buffer
* of text, but keep any partial lines to concatenate with the next buffer
* load.
*      I use puts() in the CP/M version because BDS-C printf breaks on long
* lines.  I don't use it in the Unix version because Unix puts() appends
* newlines to the string.
*/

main(argc,argv)

int argc;
char *argv[];

{
       int fd;                 /* File descriptor. */
       char tbuf[MAXBSZ];      /* Input buffer. */
       char pat[MAXPSZ];       /* Search pattern. */
       char *pptr;             /* Pattern string pointer. */
       char *aptr;             /* Argv pattern pointer. */
       char *nptr;             /* New pointer (in copying partials). */
       char *tptr;             /* Text pointer (while searching). */
       char *retstr;           /* Srchpat() return value. */
       char *eosret;           /* EOS pointer return from srchpat(). */
       char ctmp;              /* Temp storage. */
       int sz, osz;            /* Bytes remaining sizes. */

#ifdef CPM
       /* Fake command name. */
       argv[0] = "FP";
#endif

       /* Verify proper calling procedure: */
       if (argc < 3) {
               printf("Usage: %s <pattern> <file(s)>\n",argv[0]);
               exit(1);
       };

       /* Copy search pattern, prepend and postpend "*". */
       pptr = pat;
       *pptr++ = '*';
       for (aptr = argv[1]; *aptr != 0; *pptr++ = *aptr++);
       *pptr++ = '*';
       *pptr = 0;

       /* Compile search pattern; normal EOL, ignore case. */
       comppat(pat,'\n',TRUE);

#ifdef CPM
       /* Remove search pattern from argv, and expand file names. */
       argv[1] = "NOARG";
       wildexp(&argc, &argv);
#endif

       /* Go thru the files one by one. */
       argc--; argv++; argc--; argv++; /* Skip command name and pattern. */
       while (argc-- > 0) {
               if ((fd = open(argv[0],0)) == -1) {
                       printf("Bad file name: %s!\n",argv[0]);
                       argv++;
                       continue;
               };

               /* Read & write, read & write, ... */
               osz = 0;
#ifdef UNIX
               while ((sz = read(fd,tbuf+osz,(MAXBSZ-1)-osz)) > 0) {
#endif
#ifdef CPM
               while ((sz = 128*read(fd,tbuf+osz,((MAXBSZ-1)-osz)/128)) > 0){
#endif
                       osz += sz;
                       tptr = tbuf;

                       /* While there's something worth printing. */
                       while ((retstr = srchpat(tptr,osz,&eosret)) != 0) {
                               ctmp = *eosret;
                               *eosret = 0;
#ifdef UNIX
                               printf("%s: %s",argv[0],retstr);
#endif
#ifdef CPM
                               puts(argv[0]); puts(": "); puts(retstr);
#endif
                               *eosret = ctmp;
                               osz -= eosret - tptr;
                               tptr = eosret;
                       };

                       /* Find partial line at end. */
                       tptr += osz-1;
                       for (sz = 0; sz != osz; sz++) {
                               if (*tptr == '\n') break;
                               tptr--;
                       };

                       /* Copy partial. */
                       tptr++;
                       osz = sz;
                       for (nptr = tbuf; sz != 0; sz--) *nptr++ = *tptr++;
               };

               close(fd);
               argv++;
       };
}