home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / os2sdk / os2sdk10 / apps / cpgrep / cpgrep.c next >
Encoding:
C/C++ Source or Header  |  1988-08-11  |  29.3 KB  |  1,002 lines

  1. /* cpgrep
  2. *
  3. * HISTORY:
  4. * 23-Mar-87     danl    exit(x) -> DOSEXIT(1, x)
  5. *
  6. */
  7.  
  8. #include        <stdio.h>
  9. #include        <fcntl.h>
  10. #include        <ctype.h>
  11.  
  12. int far pascal        DOSCREATETHREAD(void (far *)(),int far *,int far *);
  13. int far pascal        DOSGETMACHINEMODE(char far *);
  14. int far pascal        DOSQHANDTYPE(int,int far *,int far *);
  15. int far pascal        DOSREAD(int,char far *,int,int far *);
  16. int far pascal        DOSSEMCLEAR(long far *);
  17. int far pascal        DOSSEMREQUEST(long far *,long);
  18. int far pascal        DOSSEMSET(long far *);
  19. int far pascal        DOSSEMWAIT(long far *,long);
  20. int far pascal        DOSSLEEP(long);
  21. int far pascal        DOSWRITE(int,char far *,int,int far *);
  22. int far pascal        DOSEXIT(int, int);
  23.  
  24. #define    BEGLINE        0x40
  25. #define    DEBUG        0x08
  26. #define    ENDLINE        0x80
  27. #define    FILBUFLEN    (SECTORLEN*30)
  28. #define    FILNAMLEN    80
  29. #define    INVERT        0x10
  30. #define    ISCOT        0x0002
  31. #define    LG2SECLEN    9
  32. #define    LINELEN        128
  33. #define    LINENOS        0x04
  34. #define    LNOLEN        8
  35. #define    MAXSTRLEN    128
  36. #define    NAMEONLY    0x02
  37. #define    OUTBUFLEN    (SECTORLEN*4)
  38. #define    SECTORLEN    (1 << LG2SECLEN)
  39. #define    SHOWNAME    0x01
  40. #define    STKLEN        256
  41. #define    TIMER        0x20
  42. #define    TRTABLEN    256
  43. #define    s_text(x)    (((char *)(x)) - ((x)->s_must))
  44.  
  45. typedef struct stringnode
  46.   {
  47.     struct stringnode    *s_alt;        /* List of alternates */
  48.     struct stringnode    *s_suf;        /* List of suffixes */
  49.     int            s_must;        /* Length of portion that must match */
  50.   }
  51.             STRINGNODE;
  52.  
  53. char            filbuf[(FILBUFLEN + 2)*2];
  54. char            *bufptr[] = { filbuf, filbuf + FILBUFLEN + 2 };
  55. char            outbuf[OUTBUFLEN*2];
  56. char            *obuf[] = { outbuf, outbuf + OUTBUFLEN };
  57. char            *optr[] = { outbuf, outbuf + OUTBUFLEN };
  58. int            ocnt[] = { OUTBUFLEN, OUTBUFLEN };
  59. int            oi = 0;
  60. char            transtab[TRTABLEN] = { 0 };
  61. STRINGNODE        *stringlist[TRTABLEN/2];
  62. int            arrc;        /* I/O return code for DOSREAD */
  63. int            awrc;        /* I/O return code for DOSWRITE */
  64. int            casesen = 1;    /* Assume case-sensitivity */
  65. int            cbread;        /* Bytes read by DOSREAD */
  66. int            cbwrite;    /* Bytes written by DOSWRITE */
  67. int            clists = 1;    /* One is first available index */
  68. int            flags;        /* Flags */
  69. int            lineno;        /* Current line number */
  70. char            pmode;        /* Protected mode flag */
  71. long            readdone;    /* Async read done semaphore */
  72. long            readpending;    /* Async read pending semaphore */
  73. int            status = 1;    /* Assume failure */
  74. char            *t2buf;        /* Async read buffer */
  75. int            t2buflen;    /* Async read buffer length */
  76. int            t2fd;        /* Async read file */
  77. char            *t3buf;        /* Async write buffer */
  78. int            t3buflen;    /* Async write buffer length */
  79. int            t3fd;        /* Async write file */
  80. long            writedone;    /* Async write done semaphore */
  81. long            writepending;    /* Async write pending semaphore */
  82. char            target[MAXSTRLEN];
  83.                     /* Last string added */
  84. int            targetlen;    /* Length of last string added */
  85.  
  86. int            countlines();    /* See CPGREPSB.ASM */
  87. int            countmatched();    /* See CPGREPSB.ASM */
  88. char            *findlist();    /* See CPGREPSB.ASM */
  89. char            *findone();    /* See CPGREPSB.ASM */
  90. void            flush1buf();    /* See below */
  91. int            grepbuffer();    /* See below */
  92. int            revfind();    /* See CPGREPSB.ASM */
  93. void            write1buf();    /* See below */
  94. char            *(*find)() = findlist;
  95. void            (*flush1)() = flush1buf;
  96. int            (*grep)() = grepbuffer;
  97. void            (*write1)() = write1buf;
  98.  
  99. void            freenode(x)
  100. register STRINGNODE    *x;        /* Pointer to node to free */
  101.   {
  102.     register STRINGNODE    *y;        /* Pointer to next node in list */
  103.  
  104.     while(x != NULL)            /* While not at end of list */
  105.       {
  106.     if(x->s_suf != NULL) freenode(x->s_suf);
  107.                     /* Free suffix list */
  108.     y = x;                /* Save pointer */
  109.     x = x->s_alt;            /* Move down the list */
  110.     free(y);            /* Free the node */
  111.       }
  112.   }
  113.  
  114.  
  115. STRINGNODE        *newnode(s,n)
  116. char            *s;        /* String */
  117. int            n;        /* Length of string */
  118.   {
  119.     register STRINGNODE    *new;        /* Pointer to new node */
  120.     char        *t;        /* String pointer */
  121.     char        *malloc();    /* Storage allocator */
  122.  
  123.     if((t = malloc(sizeof(STRINGNODE) + n + (n & 1))) == NULL)
  124.       {                    /* If allocation fails */
  125.     fprintf(stderr,"Out of memory\n");
  126.     DOSEXIT(1, 2);                  /* Print error message and die */
  127.       }
  128.     if(n & 1) ++t;            /* END of string word-aligned */
  129.     strncpy(t,s,n);            /* Copy string text */
  130.     new = (STRINGNODE *)(t + n);    /* Set pointer to node */
  131.     new->s_alt = NULL;            /* No alternates yet */
  132.     new->s_suf = NULL;            /* No suffixes yet */
  133.     new->s_must = n;            /* Set string length */
  134.     return(new);            /* Return pointer to new node */
  135.   }
  136.  
  137.  
  138. void            reallocnode(node,s,n)
  139. register STRINGNODE    *node;        /* Pointer to node */
  140. char            *s;        /* String */
  141. register int        n;        /* Length of string */
  142.   {
  143.     if(n > node->s_must)        /* If node must grow */
  144.       {
  145.     fprintf(stderr,"Internal error\n");
  146.                     /* Error message */
  147.     DOSEXIT(1, 2);                  /* Error exit */
  148.       }
  149.     node->s_must = n;            /* Set new length */
  150.     memcpy(s_text(node),s,n);        /* Copy new text */
  151.   }
  152.  
  153.  
  154. void            addstring(s,n)
  155. char            *s;        /* String to add */
  156. int            n;        /* Length of string */
  157.   {
  158.     register STRINGNODE    *cur;        /* Current string */
  159.     register STRINGNODE    **pprev;    /* Pointer to previous link */
  160.     STRINGNODE        *new;        /* New string */
  161.     int            i;        /* Index */
  162.     int            j;        /* Count */
  163.     int            k;        /* Count */
  164.  
  165.     if(n <= 0 || n > 127) return;    /* Should never happen */
  166.     i = transtab[*s];            /* Get current index */
  167.     if(i == 0)                /* If no existing list */
  168.       {
  169.     /*
  170.      *  We have to start a new list
  171.      */
  172.     if((i = clists++) >= TRTABLEN/2)
  173.       {                /* If too many string lists */
  174.         fprintf(stderr,"Too many string lists\n");
  175.                     /* Error message */
  176.         DOSEXIT(1, 2);              /* Die */
  177.       }
  178.     stringlist[i] = NULL;        /* Initialize */
  179.     transtab[*s] = i;        /* Set pointer to new list */
  180.     if(!casesen && isalpha(*s)) transtab[*s ^ '\x20'] = i;
  181.                     /* Set pointer for other case */
  182.       }
  183.     else if(stringlist[i] == NULL) return;
  184.                     /* Check for existing 1-byte string */
  185.     if(--n == 0)            /* If 1-byte string */
  186.       {
  187.     freenode(stringlist[i]);    /* Free any existing stuff */
  188.     stringlist[i] = NULL;        /* No record here */
  189.     return;                /* Done */
  190.       }
  191.     ++s;                /* Skip first char */
  192.     pprev = stringlist + i;        /* Get pointer to link */
  193.     cur = *pprev;            /* Get pointer to node */
  194.     while(cur != NULL)            /* Loop to traverse match tree */
  195.       {
  196.     i = (n > cur->s_must)? cur->s_must: n;
  197.                     /* Find minimum of string lengths */
  198.     matchstrings(s,s_text(cur),i,&j,&k);
  199.                     /* Compare the strings */
  200.     if(j == 0)            /* If complete mismatch */
  201.       {
  202.         if(k < 0) break;        /* Break if insertion point found */
  203.         pprev = &(cur->s_alt);    /* Get pointer to alternate link */
  204.         cur = *pprev;        /* Follow the link */
  205.       }
  206.     else if(i == j)            /* Else if strings matched */
  207.       {
  208.         if(i == n)            /* If new is prefix of current */
  209.           {
  210.         reallocnode(cur,s_text(cur),n);
  211.                     /* Shorten text of node */
  212.         if(cur->s_suf != NULL)    /* If there are suffixes */
  213.           {
  214.             freenode(cur->s_suf);
  215.                     /* Suffixes no longer needed */
  216.             cur->s_suf = NULL;
  217.           }
  218.         return;            /* All done */
  219.           }
  220.         pprev = &(cur->s_suf);    /* Get pointer to suffix link */
  221.         if((cur = *pprev) == NULL) return;
  222.                     /* Done if current is prefix of new */
  223.         s += i;            /* Skip matched portion */
  224.         n -= i;
  225.       }
  226.     else                /* Else partial match */
  227.       {
  228.         /*
  229.          *    We must split an existing node.
  230.          *    This is the trickiest case.
  231.          */
  232.         new = newnode(s_text(cur) + j,cur->s_must - j);
  233.                     /* Unmatched part of current string */
  234.         reallocnode(cur,s_text(cur),j);
  235.                     /* Set length to matched portion */
  236.         new->s_suf = cur->s_suf;    /* Current string's suffixes */
  237.         if(k < 0)            /* If new preceded current */
  238.           {
  239.         cur->s_suf = newnode(s + j,n - j);
  240.                     /* FIrst suffix is new string */
  241.         cur->s_suf->s_alt = new;/* Alternate is part of current */
  242.           }
  243.         else            /* Else new followed current */
  244.           {
  245.         new->s_alt = newnode(s + j,n - j);
  246.                     /* Unmatched new string is alternate */
  247.             cur->s_suf = new;    /* New suffix list */
  248.           }
  249.         return;
  250.       }
  251.       }
  252.     *pprev = newnode(s,n);        /* Set pointer to new node */
  253.     (*pprev)->s_alt = cur;        /* Attach alternates */
  254.   }
  255.  
  256.  
  257. int            addfancy(buffer,buflen,seplist)
  258. register char        *buffer;    /* Buffer */
  259. int            buflen;        /* Length of buffer */
  260. char            *seplist;    /* List of separators */
  261.   {
  262.     register char    *bufend;    /* Pointer to end of buffer */
  263.     int            strcnt = 0;    /* String count */
  264.     int            len;        /* String length */
  265.     char        c;        /* One char buffer */
  266.  
  267.     bufend = buffer + buflen;        /* Set end pointer */
  268.     while(buffer < bufend)        /* Loop through all strings */
  269.       {
  270.     len = strncspn(buffer,seplist,bufend - buffer);
  271.                     /* Length of string */
  272.     if(flags & ENDLINE)        /* If match must be at end of line */
  273.       {
  274.         c = buffer[len];        /* Save 1st character past string */
  275.         buffer[len++] = '\r';    /* Carriage return marks end of line */
  276.       }
  277.     if(findlist(buffer,buffer + len) == NULL)
  278.       {                /* If no match within string */
  279.         addstring(buffer,len);    /* Add string to list */
  280.         if(strcnt++ == 0)        /* If first string */
  281.           {
  282.         memcpy(target,buffer,len);
  283.                     /* Save first string in buffer */
  284.         targetlen = len;    /* Remember length */
  285.           }
  286.       }
  287.     buffer += len;            /* Skip over string */
  288.     if(flags & ENDLINE) (--buffer)[0] = c;
  289.                     /* Restore saved character */
  290.     buffer += strnspn(buffer,seplist,bufend - buffer);
  291.                     /* Skip over trailing separators */
  292.       }
  293.     return(strcnt);            /* Return string count */
  294.   }
  295.  
  296.  
  297. int            addplain(buffer,buflen,seplist)
  298. register char        *buffer;    /* String list buffer */
  299. int            buflen;        /* Buffer length */
  300. char            *seplist;    /* List of separators */
  301.   {
  302.     int            strcnt;        /* String count */
  303.     register int    len;        /* String length */
  304.     char        c;        /* One char buffer */
  305.  
  306.     strcnt = 0;
  307.     while((len = strncspn(buffer,seplist,buflen)) > 0)
  308.       {                    /* While not at end of input list */
  309.     if(flags & ENDLINE)        /* If match must be at end of line */
  310.       {
  311.         c = buffer[len];        /* Save 1st character past string */
  312.         buffer[len++] = '\r';    /* Carriage return marks end of line */
  313.       }
  314.     if(strcnt == 0)            /* Save first string */
  315.       {
  316.         strncpy(target,buffer,len);    /* Save string in buffer */
  317.         targetlen = len;        /* Save string length */
  318.       }
  319.     addstring(buffer,len);        /* Add the string to the table */
  320.     if(flags & ENDLINE) buffer[--len] = c;
  321.                     /* Restore saved character */
  322.     buffer += len;            /* Skip the string */
  323.     buflen -= len;
  324.     len = strnspn(buffer,seplist,buflen);
  325.                     /* Skip separators */
  326.     buffer += len;
  327.     buflen -= len;
  328.     ++strcnt;            /* Increment string count */
  329.       }
  330.     return(strcnt);            /* Return string count */
  331.   }
  332.  
  333.  
  334. void            dumplist(node,indent)
  335. register STRINGNODE    *node;        /* Pointer to list to dump */
  336. int            indent;        /* Current length of buffer */
  337.   {
  338.     int            i;        /* Counter */
  339.  
  340.     while(node != NULL)            /* While not at end of list */
  341.       {
  342.     for(i = 0; i < indent; ++i) fputc(' ',stderr);
  343.     fwrite(s_text(node),sizeof(char),node->s_must,stderr);
  344.     fprintf(stderr,"\n");
  345.     if(node->s_suf != NULL)
  346.       dumplist(node->s_suf,indent + node->s_must);
  347.                     /* Recurse to do suffixes */
  348.     node = node->s_alt;        /* Do next alternate in list */
  349.       }
  350.   }
  351.  
  352.  
  353. void            dumpstrings()
  354.   {
  355.     int            i;        /* Index */
  356.  
  357.     for(i = 0; i < TRTABLEN; ++i)    /* Loop through translation table */
  358.       {
  359.     if(transtab[i] == 0) continue;    /* Skip null entries */
  360.     fprintf(stderr,"%c\n",i);    /* Print the first byte */
  361.     dumplist(stringlist[transtab[i]],1);
  362.                     /* Dump the list */
  363.       }
  364.   }
  365.  
  366.  
  367. int            openfile(name)
  368. char            *name;        /* File name */
  369.   {
  370.     int            fd;        /* File descriptor */
  371.  
  372.     if((fd = open(name,0)) == -1)    /* If error opening file */
  373.       {
  374.     fprintf(stderr,"Cannot open %s\r\n",name);
  375.                     /* Print error message */
  376.       }
  377.     return(fd);                /* Return file descriptor */
  378.   }
  379.  
  380.  
  381. void far        thread2()    /* Read thread */
  382.   {
  383.     while(DOSSEMREQUEST((long far *) &readpending,-1L) == 0)
  384.       {                    /* While there is work to do */
  385.     arrc = DOSREAD(t2fd,(char far *) t2buf,t2buflen,(int far *) &cbread);
  386.                     /* Do the read */
  387.     DOSSEMCLEAR((long far *) &readdone);
  388.                     /* Signal read completed */
  389.       }
  390.     fprintf(stderr,"Thread 2: DOSSEMREQUEST failed\n");
  391.                     /* Print error message */
  392.     DOSEXIT(1, 2);                  /* Die */
  393.   }
  394.  
  395.  
  396. void far        thread3()    /* Write thread */
  397.   {
  398.     while(DOSSEMREQUEST((long far *) &writepending,-1L) == 0)
  399.       {                    /* While there is work to do */
  400.     awrc = DOSWRITE(t3fd,(char far *) t3buf,t3buflen,(int far *) &cbwrite);
  401.                     /* Do the write */
  402.     DOSSEMCLEAR((long far *) &writedone);
  403.                     /* Signal write completed */
  404.       }
  405.     fprintf(stderr,"Thread 3: DOSSEMREQUEST failed\n");
  406.                     /* Print error message */
  407.     DOSEXIT(1, 2);                  /* Die */
  408.   }
  409.  
  410.  
  411. void            startread(fd,buffer,buflen)
  412. int            fd;        /* File handle */
  413. char            *buffer;    /* Buffer */
  414. int            buflen;        /* Buffer length */
  415.   {
  416.     if(pmode)                /* If protected mode */
  417.       {
  418.     if(DOSSEMREQUEST((long far *) &readdone,-1L) != 0)
  419.       {                /* If we fail to get the semaphore */
  420.         fprintf(stderr,"DOSSEMREQUEST failed\n");
  421.                     /* Error message */
  422.         DOSEXIT(1, 2);              /* Die */
  423.       }
  424.     t2fd = fd;            /* Set parameters for read */
  425.     t2buf = buffer;
  426.     t2buflen = buflen;
  427.     DOSSEMCLEAR((long far *) &readpending);
  428.                     /* Wake thread 2 for read */
  429.     DOSSLEEP(0L);            /* Yield the CPU */
  430.       }
  431.     else arrc = DOSREAD(fd,(char far *) buffer,buflen,(int far *) &cbread);
  432.   }
  433.  
  434.  
  435. int            finishread()
  436.   {
  437.     if(pmode && DOSSEMWAIT((long far *) &readdone,-1L) != 0)
  438.       {                    /* If protected mode and wait fails */
  439.     fprintf(stderr,"DOSSEMWAIT failed\n");
  440.                     /* Print error message */
  441.     DOSEXIT(1, 2);                  /* Die */
  442.       }
  443.     return((arrc == 0)? cbread: -1);    /* Return number of bytes read */
  444.   }
  445.  
  446.  
  447. void            startwrite(fd,buffer,buflen)
  448. int            fd;        /* File handle */
  449. char            *buffer;    /* Buffer */
  450. int            buflen;        /* Buffer length */
  451.   {
  452.     if(pmode)                /* If protected mode */
  453.       {
  454.     if(DOSSEMREQUEST((long far *) &writedone,-1L) != 0)
  455.       {                /* If we fail to get the semaphore */
  456.         fprintf(stderr,"DOSSEMREQUEST failed\n");
  457.                     /* Error message */
  458.         DOSEXIT(1, 2);              /* Die */
  459.       }
  460.     t3fd = fd;            /* Set parameters for write */
  461.     t3buf = buffer;
  462.     t3buflen = buflen;
  463.     DOSSEMCLEAR((long far *) &writepending);
  464.                     /* Wake thread 3 for read */
  465.     DOSSLEEP(0L);            /* Yield the CPU */
  466.       }
  467.     else awrc = DOSWRITE(fd,(char far *) buffer,buflen,(int far *) &cbwrite);
  468.   }
  469.  
  470.  
  471. int            finishwrite()
  472.   {
  473.     if(pmode && DOSSEMWAIT((long far *) &writedone,-1L) != 0)
  474.       {                    /* If protected mode and wait fails */
  475.     fprintf(stderr,"DOSSEMWAIT failed\n");
  476.                     /* Print error message */
  477.     DOSEXIT(1, 2);                  /* Die */
  478.       }
  479.     return((awrc == 0)? cbwrite: -1);    /* Return number of bytes written */
  480.   }
  481.  
  482.  
  483. void            write1nobuf(buffer,buflen)
  484. char            *buffer;    /* Buffer */
  485. register int        buflen;        /* Buffer length */
  486.   {
  487.     int            cb;        /* Count of bytes written */
  488.  
  489.     if(DOSWRITE(1,(char far *) buffer,buflen,(int far *) &cb) != 0 ||
  490.       cb != buflen)            /* If write fails */
  491.       {
  492.     fprintf(stderr,"write error %d\n",awrc);
  493.                     /* Print error message */
  494.     DOSEXIT(1, 2);                  /* Die */
  495.       }
  496.   }
  497.  
  498.  
  499. void            write1buf(buffer,buflen)
  500. char            *buffer;    /* Buffer */
  501. register int        buflen;        /* Buffer length */
  502.   {
  503.     register int    cb;        /* Byte count */
  504.  
  505.     while(buflen > 0)            /* While bytes remain */
  506.       {
  507.     if(awrc != 0)            /* If previous write failed */
  508.       {
  509.         fprintf(stderr,"write error %d\n",awrc);
  510.                     /* Print error message */
  511.         DOSEXIT(1, 2);              /* Die */
  512.       }
  513.     if((cb = ocnt[oi]) == 0)    /* If buffer full */
  514.       {
  515.         startwrite(1,obuf[oi],OUTBUFLEN);
  516.                     /* Write the buffer */
  517.         ocnt[oi] = OUTBUFLEN;    /* Reset count and pointer */
  518.         optr[oi] = obuf[oi];
  519.         oi ^= 1;            /* Switch buffers */
  520.         cb = ocnt[oi];        /* Get space remaining */
  521.       }
  522.     if(cb > buflen) cb = buflen;    /* Get minimum */
  523.     memcpy(optr[oi],buffer,cb);    /* Copy bytes to buffer */
  524.     ocnt[oi] -= cb;            /* Update buffer length and pointers */
  525.     optr[oi] += cb;
  526.     buflen -= cb;
  527.     buffer += cb;
  528.       }
  529.   }
  530.  
  531.  
  532. void            flush1nobuf()
  533.   {
  534.   }
  535.  
  536.  
  537. void            flush1buf()
  538.   {
  539.     int            cb;        /* Byte count */
  540.  
  541.     if((cb = OUTBUFLEN - ocnt[oi]) > 0)    /* If buffer not empty */
  542.       {
  543.     startwrite(1,obuf[oi],cb);    /* Start write */
  544.     if(finishwrite() != cb)        /* If write failed */
  545.       {
  546.         fprintf(stderr,"write error %d\n",awrc);
  547.                     /* Print error message */
  548.         DOSEXIT(1, 2);              /* Die */
  549.       }
  550.       }
  551.   }
  552.  
  553.  
  554. int            grepnull(cp,endbuf,name)
  555. register char        *cp;        /* Buffer pointer */
  556. char            *endbuf;    /* End of buffer */
  557. char            *name;        /* File name */
  558.   {
  559.     return(0);                /* Do nothing */
  560.   }
  561.  
  562.  
  563. int            grepbuffer(startbuf,endbuf,name)
  564. char            *startbuf;    /* Start of buffer */
  565. char            *endbuf;    /* End of buffer */
  566. char            *name;        /* File name */
  567.   {
  568.     register char    *cp;        /* Buffer pointer */
  569.     char        *lastmatch;    /* Last matching line */
  570.     int            linelen;    /* Line length */
  571.     int            namlen = 0;    /* Length of name */
  572.     char        lnobuf[LNOLEN];    /* Line number buffer */
  573.     char        nambuf[LINELEN];/* Name buffer */
  574.  
  575.     cp = startbuf;            /* Initialize to start of buffer */
  576.     lastmatch = cp;            /* No previous match yet */
  577.     while((cp = (*find)(cp,endbuf)) != NULL)
  578.       {                    /* While matches are found */
  579.     if((flags & BEGLINE) && cp[-1] != '\n' && cp > startbuf)
  580.       {                /* If begin line conditions not met */
  581.         ++cp;            /* Skip first char of match */
  582.         continue;            /* Keep looking */
  583.       }
  584.     status = 0;            /* Match found */
  585.     if(flags & NAMEONLY)        /* If filename only wanted */
  586.       {
  587.         (*write1)(nambuf,sprintf(nambuf,"%s\r\n",name));
  588.                     /* Print the name */
  589.         return(1);            /* Punt remainder of buffer */
  590.       }
  591.     cp -= revfind(cp,'\n',cp - startbuf);
  592.                     /* Point at last linefeed */
  593.     if(*cp == '\n') ++cp;        /* Point at start of line */
  594.     if(flags & SHOWNAME)        /* If name wanted */
  595.       {
  596.         if(namlen == 0) namlen = sprintf(nambuf,"%s:",name);
  597.                     /* Format name if not done already */
  598.         (*write1)(nambuf,namlen);    /* Show name */
  599.       }
  600.     if(flags & LINENOS)        /* If line number wanted */
  601.       {
  602.         lineno += countlines(lastmatch,cp);
  603.                     /* Count lines since last match */
  604.         (*write1)(lnobuf,sprintf(lnobuf,"%d:",lineno));
  605.                     /* Print line number */
  606.         lastmatch = cp;        /* New last match */
  607.       }
  608.     linelen = strncspn(cp,"\n",endbuf - cp) + 1;
  609.                     /* Calculate line length */
  610.     (*write1)(cp,linelen);        /* Print the line */
  611.     cp += linelen;            /* Skip the line */
  612.       }
  613.     if(flags & LINENOS) lineno += countlines(lastmatch,endbuf);
  614.                     /* Count remaining lines in buffer */
  615.     return(0);                /* Keep searching */
  616.   }
  617.  
  618.  
  619. void            showv(name,lastmatch,thismatch)
  620. char            *name;
  621. register char        *lastmatch;
  622. char            *thismatch;
  623.   {
  624.     register int    linelen;
  625.     int            namlen = 0;    /* Length of name */
  626.     char        lnobuf[LNOLEN];    /* Line number buffer */
  627.     char        nambuf[LINELEN];/* Name buffer */
  628.  
  629.     if(flags & (SHOWNAME | LINENOS))
  630.       {
  631.     while(lastmatch < thismatch)
  632.       {
  633.         if(flags & SHOWNAME)    /* If name wanted */
  634.           {
  635.         if(namlen == 0) namlen = sprintf(nambuf,"%s:",name);
  636.                     /* Format name if not done already */
  637.         (*write1)(nambuf,namlen);
  638.                     /* Write the name */
  639.           }
  640.         if(flags & LINENOS)
  641.           {
  642.         (*write1)(lnobuf,sprintf(lnobuf,"%d:",lineno++));
  643.           }
  644.         linelen = strncspn(lastmatch,"\n",thismatch - lastmatch) + 1;
  645.         (*write1)(lastmatch,linelen);
  646.         lastmatch += linelen;
  647.       }
  648.       }
  649.     else (*write1)(lastmatch,thismatch - lastmatch);
  650.   }
  651.  
  652.  
  653. int            grepvbuffer(startbuf,endbuf,name)
  654. char            *startbuf;    /* Start of buffer */
  655. char            *endbuf;    /* End of buffer */
  656. char            *name;        /* File name */
  657.   {
  658.     register char    *cp;        /* Buffer pointer */
  659.     register char    *lastmatch;    /* Pointer to line after last match */
  660.  
  661.     cp = startbuf;            /* Initialize to start of buffer */
  662.     lastmatch = cp;
  663.     while((cp = (*find)(cp,endbuf)) != NULL)
  664.       {
  665.     if((flags & BEGLINE) && cp[-1] != '\n' && cp > startbuf)
  666.       {                /* If begin line conditions not met */
  667.         ++cp;            /* Skip first char of match */
  668.         continue;            /* Keep looking */
  669.       }
  670.     status = 1;            /* Match found */
  671.     if(flags & NAMEONLY) return(1);    /* Skip rest of file if NAMEONLY */
  672.     cp -= revfind(cp,'\n',cp - startbuf);
  673.                     /* Point at last linefeed */
  674.     if(*cp == '\n') ++cp;        /* Point at start of line */
  675.     showv(name,lastmatch,cp);    /* Show from last match to this */
  676.     cp += strncspn(cp,"\n",endbuf - cp) + 1;
  677.                     /* Skip over line with match */
  678.     lastmatch = cp;            /* New "last" match */
  679.     ++lineno;            /* Increment line count */
  680.       }
  681.     if(!(flags & NAMEONLY)) showv(name,lastmatch,endbuf);
  682.                     /* Show buffer tail if not NAMEONLY */
  683.     return(0);                /* Keep searching file */
  684.   }
  685.  
  686.  
  687. void            qgrep(name,fd)
  688. char            *name;        /* File name */
  689. int            fd;        /* File descriptor */
  690.   {
  691.     register int    cb;        /* Byte count */
  692.     register char    *cp;        /* Buffer pointer */
  693.     char        *endbuf;    /* End of buffer */
  694.     int            taillen;    /* Length of buffer tail */
  695.     int            bufi;        /* Buffer index */
  696.     char        line[LINELEN];    /* Line buffer */
  697.  
  698.     lineno = 1;                /* File starts on line 1 */
  699.     taillen = 0;            /* No buffer tail yet */
  700.     bufi = 0;                /* Initialize buffer index */
  701.     cp = bufptr[0];            /* Initialize to start of buffer */
  702.     finishread();            /* Make sure no I/O activity */
  703.     arrc = DOSREAD(fd,(char far *) cp,FILBUFLEN,(int far *) &cbread);
  704.                     /* Do first read synchronously */
  705.     while((cb = finishread()) + taillen > 0)
  706.       {                    /* While search incomplete */
  707.     if(cb == 0)            /* If buffer tail is all that's left */
  708.       {
  709.         taillen = 0;        /* Set tail length to zero */
  710.         *cp++ = '\r';        /* Add end of line sequence */
  711.         *cp++ = '\n';
  712.         endbuf = cp;        /* Note end of buffer */
  713.       }
  714.     else                /* Else start next read */
  715.       {
  716.         taillen = revfind(cp + cb - 1,'\n',cb);
  717.                     /* Find length of partial line */
  718.         endbuf = cp + cb - taillen;    /* Get pointer to end of buffer */
  719.         cp = bufptr[bufi ^ 1];    /* Pointer to other buffer */
  720.         memcpy(cp,endbuf,taillen);    /* Copy tail to head of other buffer */
  721.         cp += taillen;        /* Skip over tail */
  722.         startread(fd,cp,(FILBUFLEN - taillen) & (~0 << LG2SECLEN));
  723.                     /* Start next read */
  724.       }
  725.     if((*grep)(bufptr[bufi],endbuf,name)) return;
  726.                     /* Done if NAMEONLY and match found */
  727.     bufi ^= 1;            /* Switch buffers */
  728.       }
  729.     if((flags & (NAMEONLY | INVERT)) == (NAMEONLY | INVERT))
  730.       (*write1)(line,sprintf(line,"%s\r\n",name));
  731.                     /* Write name if -lv */
  732.   }
  733.  
  734.  
  735. void            usage(verbose)
  736. int            verbose;    /* Verbose message flag */
  737.   {
  738.     static char        *opts[] =
  739.       {
  740.     "-? - print this message",
  741.     "-B - match pattern if at beginning of line",
  742.     "-E - match pattern if at end of line",
  743.     "-l - print only file name if file contains match",
  744.     "-n - print line number before each matching line",
  745.     "-v - print only lines not containing a match",
  746.     "-x - print lines that match exactly (-BE)",
  747.     "-y - treat upper and lower case as equivalent",
  748.     "-e - treat next argument as the search string",
  749.     "-f - read search strings from file named by next argument",
  750.     "-i - read file list from file named by next argument",
  751.     0
  752.       };
  753.     register char    **opt = opts;    /* Option list */
  754.  
  755.     fprintf(stderr,"usage: CPGREP [-?BElnvxy][-e][-f <file>][-i <file>][<strings>][<files>]\n");
  756.     if(verbose)                /* If verbose message wanted */
  757.       {
  758.     while(*opt != 0) fprintf(stderr,"%s\n",*opt++);
  759.                     /* Print option list */
  760.       }
  761.     DOSEXIT(1, 2);                  /* Error exit */
  762.   }
  763.  
  764.  
  765. void            main(argc,argv)
  766. int            argc;
  767. char            **argv;
  768.   {
  769.     register char    *cp;
  770.     int            fd;
  771.     FILE        *fi;
  772.     char        filnam[FILNAMLEN];
  773.     int            i;
  774.     char        *inpfile = NULL;
  775.     int            j;
  776.     char        *seplist = " \t";
  777.     int            strcnt;
  778.     char        *strfile = NULL;
  779.     long        start;        /* Start time */
  780.     int            (*add)();
  781.     int            t2stk[STKLEN];    /* Read thread stack */
  782.     int            t3stk[STKLEN];    /* Write thread stack */
  783.     long        time();        /* Time and date in seconds */
  784.  
  785.     DOSGETMACHINEMODE((char far *) &pmode);
  786.     flags = 0;
  787.     for(i = 1; i < argc && argv[i][0] == '-'; ++i)
  788.       {
  789.     switch(argv[i][1])
  790.       {
  791.         case 'f':
  792.         case 'i':
  793.           if(i == argc - 1)
  794.         {
  795.           fprintf(stderr,"File name missing after -%c\n",argv[i][1]);
  796.           DOSEXIT(1, 2);
  797.         }
  798.           if(argv[i++][1] == 'i') inpfile = argv[i];
  799.           else strfile = argv[i];
  800.           break;
  801.  
  802.         case '?':
  803.         case 'B':
  804.         case 'E':
  805.         case 'N':
  806.         case 'S':
  807.         case 'd':
  808.         case 'l':
  809.         case 'n':
  810.         case 't':
  811.         case 'v':
  812.         case 'x':
  813.         case 'y':
  814.           for(cp = &argv[i][1]; *cp != '\0'; ++cp)
  815.         {
  816.           switch(*cp)
  817.             {
  818.               case '?':
  819.             usage(1);    /* Verbose usage message */
  820.  
  821.               case 'B':
  822.             flags |= BEGLINE;
  823.             break;
  824.  
  825.               case 'E':
  826.             flags |= ENDLINE;
  827.             break;
  828.  
  829.               case 'N':
  830.             grep = grepnull;
  831.             break;
  832.  
  833.               case 'S':
  834.             pmode = 0;    /* Force synchronous I/O */
  835.             break;
  836.  
  837.               case 'd':
  838.             flags |= DEBUG;
  839.             break;
  840.  
  841.               case 'l':
  842.             flags |= NAMEONLY;
  843.             break;
  844.  
  845.               case 'n':
  846.             flags |= LINENOS;
  847.             break;
  848.  
  849.               case 't':
  850.             flags |= TIMER;
  851.             break;
  852.  
  853.               case 'v':
  854.             status = 0;    /* Assume success */
  855.             flags |= INVERT;
  856.             grep = grepvbuffer;
  857.             break;
  858.  
  859.               case 'x':
  860.             flags |= BEGLINE | ENDLINE;
  861.             break;
  862.  
  863.               case 'y':
  864.             casesen = 0;
  865.             break;
  866.  
  867.               default:
  868.             fprintf(stderr,"-%c ignored\n",*cp);
  869.             break;
  870.             }
  871.             }
  872.           break;
  873.  
  874.         case 'e':
  875.           if(strfile == NULL)
  876.         {
  877.           ++i;
  878.           seplist = "";        /* Allow anything in string */
  879.           goto endfor0;
  880.         }
  881.           /* Drop through to "default" */
  882.  
  883.         default:
  884.           fprintf(stderr,"%s ignored\n",argv[i]);
  885.           break;
  886.       }
  887.       }
  888.     endfor0:
  889.  
  890.     if(i == argc && strfile == NULL) usage(0);
  891.                     /* Simple usage message if arg error */
  892.     if(flags & TIMER) start = time(NULL);
  893.                     /* Get start time if timer on */
  894.     if(pmode)                /* Initialize semaphores and threads */
  895.       {
  896.     DOSSEMCLEAR((long far *) &readdone);
  897.     DOSSEMCLEAR((long far *) &writedone);
  898.     DOSSEMSET((long far *) &readpending);
  899.     DOSSEMSET((long far *) &writepending);
  900.     if(DOSCREATETHREAD(thread2,(int far *) &fd,
  901.       (int far *) t2stk + STKLEN) != 0 ||
  902.       DOSCREATETHREAD(thread3,(int far *) &fd,
  903.       (int far *) t3stk + STKLEN) != 0)
  904.       {                /* If thread creation fails */
  905.         fprintf(stderr,"Failed to create child threads\n");
  906.                     /* Print error message */
  907.         DOSEXIT(1, 2);              /* Die */
  908.       }
  909.       }
  910.     setmode(fileno(stdout),O_BINARY);
  911.     add = addplain;            /* Assume plain string adds */
  912.     if(strfile != NULL)            /* If strings from file */
  913.       {
  914.     if(!(flags & BEGLINE)) add = addfancy;
  915.                     /* Try to add intelligently */
  916.     if((fd = open(strfile,0)) == -1)
  917.       {                /* If open fails */
  918.         fprintf(stderr,"Cannot read strings from %s\n",strfile);
  919.         DOSEXIT(1, 2);              /* Print message and die */
  920.       }
  921.     for(cp = filbuf, j = 0; (j = read(fd,cp,FILBUFLEN*2 - j)) > 0; cp += j);
  922.                     /* Read strings file into buffer */
  923.     j = cp - filbuf;        /* Get total length of buffer */
  924.     close(fd);            /* Close strings file */
  925.     filbuf[j] = '\0';        /* Null-terminate the buffer */
  926.     cp = filbuf;            /* Set pointer to string list */
  927.     seplist = "\r\n";        /* Only '\r' and '\n' are separators */
  928.       }
  929.     else                /* Else strings on command line */
  930.       {
  931.     cp = argv[i++];            /* Set pointer to strings */
  932.     j = strlen(cp);            /* Get length of strings */
  933.       }
  934.     if((strcnt = (*add)(cp,j,seplist)) == 0)
  935.       {                    /* If no strings */
  936.     fprintf(stderr,"No search strings\n");
  937.     DOSEXIT(1, 2);                  /* Print error message and die */
  938.       }
  939.  
  940.     /*
  941.      *  Check type of handle for std. out.
  942.      */
  943.     if(DOSQHANDTYPE(fileno(stdout),(int far *) &j,(int far *) &fd) != 0)
  944.       {                    /* If error */
  945.     fprintf(stderr,"Standard output bad handle\n");
  946.                     /* Print error message */
  947.     DOSEXIT(1, 2);                  /* Die */
  948.       }
  949.     if(j != 0 && (fd & ISCOT))        /* If handle is console output */
  950.       {
  951.     write1 = write1nobuf;        /* Use unbuffered output */
  952.     flush1 = flush1nobuf;
  953.       }
  954.  
  955.     if(strcnt > 1)            /* If more than one string */
  956.       {
  957.     if(flags & DEBUG)        /* Print debug info maybe */
  958.       {
  959.         fprintf(stderr,"Here are the strings:\n");
  960.         dumpstrings();
  961.       }
  962.       }
  963.     else if(casesen) find = findone;    /* Else use findone() */
  964.     if(inpfile != NULL)            /* If file list from file */
  965.       {
  966.     flags |= SHOWNAME;        /* Always show name of file */
  967.     if((fi = fopen(inpfile,"r")) == NULL)
  968.       {                /* If open fails */
  969.         fprintf(stderr,"Cannot read file list from %s\r\n",inpfile);
  970.                     /* Error message */
  971.         DOSEXIT(1, 2);              /* Error exit */
  972.       }
  973.     while(fgets(filnam,FILNAMLEN,fi) != NULL)
  974.       {                /* While there are names */
  975.         filnam[strcspn(filnam,"\r\n")] = '\0';
  976.                     /* Null-terminate the name */
  977.         if((fd = openfile(filnam)) == -1) continue;
  978.                     /* Skip file if it cannot be opened */
  979.         qgrep(filnam,fd);        /* Do the work */
  980.         close(fd);            /* Close the file */
  981.       }
  982.     fclose(fi);            /* Close the list file */
  983.       }
  984.     else if(i == argc)
  985.       {
  986.     flags &= ~(NAMEONLY | SHOWNAME);
  987.     setmode(fileno(stdin),O_BINARY);
  988.     qgrep(NULL,fileno(stdin));
  989.       }
  990.     if(argc > i + 1) flags |= SHOWNAME;
  991.     for(; i < argc; ++i)
  992.       {
  993.     if((fd = openfile(argv[i])) == -1) continue;
  994.     qgrep(argv[i],fd);
  995.     close(fd);
  996.       }
  997.     (*flush1)();
  998.     if(flags & TIMER) fprintf(stderr,"%ld seconds\n",time(NULL) - start);
  999.                     /* Print elapsed time if timer on */
  1000.     DOSEXIT(1, status);
  1001.   }
  1002.