home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / MISC / GNU / FGRE11AS.ZIP / FGREP.C next >
Encoding:
C/C++ Source or Header  |  1992-02-22  |  15.3 KB  |  696 lines

  1. /* fgrep.c - grep program built around matcher.
  2.    Copyright 1989 Free Software Foundation
  3.           Written August 1989 by Mike Haertel.
  4.  
  5.    This program is free software; you can redistribute it and/or modify
  6.    it under the terms of the GNU General Public License as published by
  7.    the Free Software Foundation; either version 1, or (at your option)
  8.    any later version.
  9.  
  10.    This program is distributed in the hope that it will be useful,
  11.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.    GNU General Public License for more details.
  14.  
  15.    You should have received a copy of the GNU General Public License
  16.    along with this program; if not, write to the Free Software
  17.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  
  19.    The author may be reached (Email) at the address mike@ai.mit.edu,
  20.    or (US mail) as Mike Haertel c/o Free Software Foundation. */
  21.  
  22. /* MS-DOS port (c) 1990 by Thorsten Ohl, ohl@gnu.ai.mit.edu
  23.    This port is also distributed under the terms of the
  24.    GNU General Public License as published by the
  25.    Free Software Foundation.
  26.  
  27.    Please note that this file is not identical to the
  28.    original GNU release, you should have received this
  29.    code as patch to the official release.
  30.  
  31.    $Header: e:/gnu/fgrep/RCS/fgrep.c 1.1.0.4 90/09/24 00:37:48 tho Exp $
  32.  */
  33.  
  34. #include "std.h"
  35. #ifdef MSDOS
  36. char *optarg;                /* interface to getopt() */
  37. int  optind;
  38. extern  int getopt (int argc, char **argv, char *optstr);
  39.  
  40. static  void error(char const *mesg,int errnum);
  41. static  void fatal(char const *mesg,int errnum);
  42. static  void compile(char const *pattern,unsigned int size);
  43. static  char *execute (char *buf, unsigned int size);
  44. static  void nlscan (char *lim);
  45. static  unsigned int prline (char *beg, char sep);
  46. static  void prpending (char *lim);
  47. static  int prtext (char *beg, char *lim);
  48. static  int fillbuf (void);
  49. static  void initbuf (void);
  50. static  void resetbuf(int desc,char const *file);
  51. static  int grepbuf (void);
  52. static  int grep(int desc,char const *file);
  53. static  void usage (void);
  54. extern  void main (int argc, char **argv);
  55.  
  56. #include <io.h>
  57. #else /* not MSDOS */
  58. #include "unix.h"
  59. #endif /* not MSDOS */
  60.  
  61. #include <errno.h>
  62. #include <stdio.h>
  63. #include <string.h>
  64.  
  65. #include "kwset.h"
  66.  
  67. #define NCHAR (UCHAR_MAX + 1)
  68.  
  69. /* For error messages. */
  70. static const char *prog;
  71. static int error_seen;
  72.  
  73. /* Flags controlling the style of output. */
  74. static int out_silent;        /* Suppress all normal output. */
  75. static int out_invert;        /* Print nonmatching stuff. */
  76. static int out_file;        /* Print filenames. */
  77. static int out_line;        /* Print line numbers. */
  78. static int out_byte;        /* Print byte offsets. */
  79. static int out_before;        /* Lines of leading context. */
  80. static int out_after;        /* Lines of trailing context. */
  81.  
  82. /* Print MESG and possibly the error string for ERRNUM.  Remember
  83.    that something awful happened. */
  84. static void
  85. DEFUN(error, (mesg, errnum), const char *mesg AND int errnum)
  86. {
  87.   if (errnum)
  88.     fprintf(stderr, "%s: %s: %s\n", prog, mesg, strerror(errnum));
  89.   else
  90.     fprintf(stderr, "%s: %s\n", prog, mesg);
  91.   error_seen = 1;
  92. }
  93.  
  94. /* Like error(), but die horribly after printing. */
  95. static void
  96. DEFUN(fatal, (mesg, errnum), const char *mesg AND int errnum)
  97. {
  98.   error(mesg, errnum);
  99.   exit(2);
  100. }
  101.  
  102. /* Interface to handle errors and fix library lossage. */
  103. #ifndef MSDOS
  104. static
  105. #endif
  106. PTR
  107. DEFUN(xmalloc, (size), size_t size)
  108. {
  109.   PTR result;
  110.  
  111.   result = malloc(size);
  112.   if (size && !result)
  113.     fatal("memory exhausted", 0);
  114.   return result;
  115. }
  116.  
  117. /* Interface to handle errors and fix some library lossage. */
  118. #ifndef MSDOS
  119. static
  120. #endif
  121. PTR
  122. DEFUN(xrealloc, (ptr, size), PTR ptr AND size_t size)
  123. {
  124.   PTR result;
  125.  
  126.   if (ptr)
  127.     result = realloc(ptr, size);
  128.   else
  129.     result = malloc(size);
  130.   if (size && !result)
  131.     fatal("memory exhausted", 0);
  132.   return result;
  133. }
  134.  
  135. /* Compiled search pattern. */
  136. kwset_t kwset;
  137.  
  138. /* Flags controlling how pattern matching is performed. */
  139. static int match_fold;        /* Fold all letters to one case. */
  140. static int match_words;        /* Match only whole words. */
  141. static int match_lines;        /* Match only whole lines. */
  142.  
  143. static void
  144. DEFUN(compile, (pattern, size), const char *pattern AND size_t size)
  145. {
  146.   const char *beg, *lim, *err;
  147.   static char trans[NCHAR];
  148.   int i;
  149.  
  150.   if (match_fold)
  151.     for (i = 0; i < NCHAR; ++i)
  152. #ifdef MSDOS
  153.       trans[i] = (char) TOLOWER(i);
  154. #else
  155.       trans[i] = TOLOWER(i);
  156. #endif
  157.  
  158.   if (!(kwset = kwsalloc(match_fold ? trans : (const char *) NULL)))
  159.     fatal("memory exhausted", 0);
  160.  
  161.   beg = pattern;
  162.   do
  163.     {
  164.       for (lim = beg; lim < pattern + size && *lim != '\n'; ++lim)
  165.     ;
  166.       if (err = kwsincr(kwset, beg, lim - beg))
  167.     fatal(err, 0);
  168.       if (lim < pattern + size)
  169.     ++lim;
  170.       beg = lim;
  171.     }
  172.   while (beg < pattern + size);
  173.  
  174.   if (err = kwsprep(kwset))
  175.     fatal(err, 0);
  176. }
  177.  
  178. static char *
  179. DEFUN(execute, (buf, size), char *buf AND size_t size)
  180. {
  181.   register char *beg, *try;
  182.   register size_t len;
  183.   struct kwsmatch kwsmatch;
  184.  
  185.   beg = buf;
  186.   for (;beg <= buf + size; ++beg)
  187.     {
  188.       if (!(beg = kwsexec(kwset, beg, buf + size - beg, &kwsmatch)))
  189.     return NULL;;
  190.       len = kwsmatch.size[0];
  191.       if (match_lines)
  192.     {
  193.       if (beg > buf && beg[-1] != '\n')
  194.         continue;
  195.       if (beg + len < buf + size && *(beg + len) != '\n')
  196.         continue;
  197.       return beg;
  198.     }
  199.       else if (match_words)
  200.     for (try = beg; len && try;)
  201.       {
  202.         if (try > buf && (ISALNUM((unsigned char) try[-1])
  203.                   || !ISALNUM((unsigned char) *try)))
  204.           goto retry;
  205.         if (try + len < buf + size
  206.         && (ISALNUM((unsigned char) *(try + len))
  207.             || !ISALNUM((unsigned char) (try + len)[-1])))
  208.           goto retry;
  209.         return try;
  210.       retry:
  211.         if (--len)
  212.           try = kwsexec(kwset, beg, len, &kwsmatch);
  213.         else
  214.           break;
  215.         len = kwsmatch.size[0];
  216.       }
  217.       else
  218.     return beg;
  219.     }
  220.  
  221.   return NULL;
  222. }
  223.  
  224. /* Hairy buffering mechanism to efficiently support all the options. */
  225. static char *bufbeg;        /* Beginning of user-visible portion. */
  226. static char *buflim;        /* Limit of user-visible portion. */
  227. static char *buf;        /* Pointer to base of buffer. */
  228. static size_t bufalloc;        /* Allocated size of buffer. */
  229. static size_t bufcc;        /* Count of characters in buffer. */
  230. static unsigned long int buftotalcc;
  231.                 /* Total character count since reset. */
  232. static char *buflast;        /* Pointer after last character printed. */
  233. static int bufgap;        /* Weird flag indicating buflast is a lie. */
  234. static unsigned long int buftotalnl;
  235.                 /* Count of newlines before last character. */
  236. static int bufpending;        /* Lines of pending output at buflast. */
  237. static int bufdesc;        /* File descriptor to read from. */
  238. static int bufeof;        /* Flag indicating EOF reached. */
  239. static const char *buffile;    /* File name for messages. */
  240.  
  241. /* Scan and count the newlines prior to LIM in the buffer. */
  242. static void
  243. DEFUN(nlscan, (lim), register char *lim)
  244. {
  245.   register char *p;
  246.  
  247.   for (p = buflast; p < lim; ++p)
  248.     if (*p == '\n')
  249.       ++buftotalnl;
  250.   buflast = lim;
  251. }
  252.  
  253. /* Print the line beginning at BEG, using SEP to separate optional label
  254.    fields from the text of the line.  Return the size of the line. */
  255. static size_t
  256. DEFUN(prline, (beg, sep), register char *beg AND register char sep)
  257. {
  258.   register size_t cc;
  259.   register char c;
  260.   static int err;
  261.   
  262.   cc = 0;
  263.  
  264.   if (out_silent || err)
  265.     while (beg < buflim)
  266.       {
  267.     ++cc;
  268.     if (*beg++ == '\n')
  269.       break;
  270.       }
  271.   else
  272.     {
  273.       if (out_file)
  274.     printf("%s%c", buffile, sep);
  275.       if (out_line)
  276.     {
  277.       nlscan(beg);
  278.       printf("%d%c", buftotalnl + 1, sep);
  279.     }
  280.       if (out_byte)
  281. #ifdef MSDOS                /* MSC 5.1 needs this cast! */
  282.     printf("%lu%c", buftotalcc + (unsigned long) (beg - buf), sep);
  283. #else
  284.     printf("%lu%c", buftotalcc + (beg - buf), sep);
  285. #endif
  286.       while (beg < buflim)
  287.     {
  288.       ++cc;
  289.       c = *beg++;
  290.       putchar(c);
  291.       if (c == '\n')
  292.         break;
  293.     }
  294.       if (ferror(stdout))
  295.     {
  296.       error("output error", errno);
  297.       err = 1;
  298.     }
  299.     }
  300.  
  301.   if (out_line)
  302.     nlscan(beg);
  303.   else
  304.     buflast = beg;
  305.   bufgap = 0;
  306.  
  307.   return cc;
  308. }
  309.  
  310. /* Print pending bytes of last trailing context prior to LIM. */
  311. static void
  312. DEFUN(prpending, (lim), register char *lim)
  313. {
  314.   while (buflast < lim && bufpending)
  315.     {
  316.       --bufpending;
  317.       prline(buflast, '-');
  318.     }
  319. }
  320.  
  321. /* Print the lines between BEG and LIM.  Deal with context crap.
  322.    Return the count of lines between BEG and LIM. */
  323. static int
  324. DEFUN(prtext, (beg, lim), char *beg AND char *lim)
  325. {
  326.   static int used;
  327.   register char *p;
  328.   int i, n;
  329.  
  330.   prpending(beg);
  331.  
  332.   p = beg;
  333.   for (i = 0; i < out_before; ++i)
  334.     if (p > buflast)
  335.       do
  336.     --p;
  337.       while (p > buflast && p[-1] != '\n');
  338.  
  339.   if ((out_before || out_after) && used && (p > buflast || bufgap))
  340.     puts("--");
  341.  
  342.   while (p < beg)
  343.     p += prline(p, '-');
  344.  
  345.   n = 0;
  346.   while (p < lim)
  347.     {
  348.       ++n;
  349.       p += prline(p, ':');
  350.     }
  351.  
  352.   bufpending = out_after;
  353.   used = 1;
  354.  
  355.   return n;
  356. }
  357.  
  358. /* Fill the user-visible portion of the buffer, returning a byte count. */
  359. static int
  360. fillbuf()
  361. {
  362.   register char *b, *d, *l;
  363.   int i, cc;
  364.   size_t discard, save;
  365.  
  366.   prpending(buflim);
  367.  
  368.   b = buflim;
  369.   for (i = 0; i < out_before; ++i)
  370.     if (b > buflast)
  371.       do
  372.     --b;
  373.       while (b > buflast && b[-1] != '\n');
  374.  
  375.   if (buflast < b)
  376.     bufgap = 1;
  377.   if (out_line)
  378.     nlscan(b);
  379.  
  380.   discard = b - buf;
  381.   save = buflim - b;
  382.  
  383.   if (b > buf)
  384.     {
  385.       d = buf;
  386.       l = buf + bufcc;
  387.       while (b < l)
  388.     *d++ = *b++;
  389.     }
  390.  
  391.   bufcc -= discard;
  392.   buftotalcc += discard;
  393.  
  394.   do
  395.     {
  396.       if (!bufeof)
  397.     {
  398.       if (bufcc > bufalloc / 2)
  399.         buf = xrealloc(buf, bufalloc *= 2);
  400.       cc = read(bufdesc, buf + bufcc, bufalloc - bufcc);
  401.       if (cc < 0)
  402.         {
  403.           error(buffile, errno);
  404.           bufeof = 1;
  405.         }
  406.       else
  407.         {
  408.           bufeof = !cc;
  409.           bufcc += cc;
  410.         }
  411.     }
  412.       bufbeg = buf + save;
  413.       for (l = buf + bufcc; l > bufbeg && l[-1] != '\n'; --l)
  414.     ;
  415.       buflim = l;
  416.       buflast = buf;
  417.     }
  418.   while (!bufeof && bufbeg == buflim);
  419.  
  420.   if (bufeof)
  421.     buflim = buf + bufcc;
  422.  
  423.   return buflim - bufbeg;
  424. }
  425.  
  426. /* One-time initialization. */
  427. static void
  428. initbuf()
  429. {
  430.   bufalloc = 8192;
  431.   buf = xmalloc(bufalloc);
  432. }
  433.  
  434. /* Reset the buffer for a new file. */
  435. static void
  436. DEFUN(resetbuf, (desc, file), int desc AND const char *file)
  437. {
  438.   bufbeg = buf;
  439.   buflim = buf;
  440.   bufcc = 0;
  441.   buftotalcc = 0;
  442.   buflast = buf;
  443.   bufgap = 0;
  444.   buftotalnl = 0;
  445.   bufpending = 0;
  446.   bufdesc = desc;
  447.   bufeof = 0;
  448.   buffile = file;
  449. }
  450.  
  451. /* Scan the user-visible portion of the buffer, calling prtext() for
  452.    matching lines (or between matching lines if OUT_INVERT is true).
  453.    Return a count of lines printed. */
  454. static int
  455. grepbuf()
  456. {
  457.   int total;
  458.   register char *p, *b, *l;
  459.  
  460.   total = 0;
  461.   p = bufbeg;
  462.   while (b = execute(p, buflim - p))
  463.     {
  464.       if (b == buflim && (b > bufbeg && b[-1] == '\n' || b == bufbeg))
  465.     break;
  466.       while (b > bufbeg && b[-1] != '\n')
  467.     --b;
  468.       l = b + 1;
  469.       while (l < buflim && l[-1] != '\n')
  470.     ++l;
  471.       if (!out_invert)
  472.     total += prtext(b, l);
  473.       else if (p < b)
  474.     total += prtext(p, b);
  475.       p = l;
  476.     }
  477.   if (out_invert && p < buflim)
  478.     total += prtext(p, buflim);
  479.   return total;
  480. }
  481.  
  482. /* Scan the given file, returning a count of lines printed. */
  483. static int
  484. DEFUN(grep, (desc, file), int desc AND const char *file)
  485. {
  486.   int total;
  487.  
  488.   total = 0;
  489.   resetbuf(desc, file);
  490.   while (fillbuf())
  491.     total += grepbuf();
  492.   return total;
  493. }
  494.  
  495.  
  496. #ifdef MSDOS
  497. static char Program_Id[] = "fgrep";
  498. static char RCS_Revision[] = "$Revision: 1.1.0.4 $";
  499. #define VERSION \
  500.   "GNU %s, Version %.*s (compiled %s %s for MS-DOS)\n", Program_Id, \
  501.   (sizeof RCS_Revision - 14), (RCS_Revision + 11), __DATE__, __TIME__
  502. #else /* not MSDOS */
  503. static const char version[] = "GNU fgrep, version 1.1";
  504. #endif /* not MSDOS */
  505.  
  506. #define USAGE \
  507.   "usage: %s [-[[AB] ]<num>] [-[CVchilnsvwx]] [-[ef]] <expr> [<files...>]\n"
  508.  
  509. static void
  510. usage()
  511. {
  512.   fprintf(stderr, USAGE, prog);
  513.   exit(2);
  514. }
  515.  
  516.  
  517. #ifdef MSDOS
  518. void
  519. #else
  520. int
  521. #endif
  522. DEFUN(main, (argc, argv), int argc AND char *argv[])
  523. {
  524.   char *keys;
  525.   size_t keycc, keyalloc;
  526.   int count_matches, no_filenames, list_files;
  527.   int opt, cc, desc, count, status;
  528.   FILE *fp;
  529.  
  530.   prog = argv[0];
  531.   if (prog && strrchr(prog, '/'))
  532.     prog = strrchr(prog, '/') + 1;
  533.  
  534.   keys = NULL;
  535.   count_matches = 0;
  536.   no_filenames = 0;
  537.   list_files = 0;
  538.  
  539.   while ((opt = getopt(argc, argv, "0123456789A:B:CVbce:f:hilnsvwxy")) != EOF)
  540.     switch (opt)
  541.       {
  542.       case '0':
  543.       case '1':
  544.       case '2':
  545.       case '3':
  546.       case '4':
  547.       case '5':
  548.       case '6':
  549.       case '7':
  550.       case '8':
  551.       case '9':
  552.     out_before = 10 * out_before + opt - '0';
  553.     out_after = 10 * out_after + opt - '0';
  554.     break;
  555.       case 'A':
  556.     out_after = atoi(optarg);
  557.     if (out_after < 0)
  558.       usage();
  559.     break;
  560.       case 'B':
  561.     out_before = atoi(optarg);
  562.     if (out_before < 0)
  563.       usage();
  564.     break;
  565.       case 'C':
  566.     out_before = out_after = 2;
  567.     break;
  568.       case 'V':
  569. #ifdef MSDOS
  570.     fprintf(stderr, VERSION);
  571. #else
  572.     fprintf(stderr, "%s\n", version);
  573. #endif
  574.     break;
  575.       case 'b':
  576.     out_byte = 1;
  577.     break;
  578.       case 'c':
  579.     out_silent = 1;
  580.     count_matches = 1;
  581.     break;
  582.       case 'e':
  583.     if (keys)
  584.       usage();
  585.     keys = optarg;
  586.     keycc = strlen(keys);
  587.     break;
  588.       case 'f':
  589.     if (keys)
  590.       usage();
  591.     fp = strcmp(optarg, "-") ? fopen(optarg, "r") : stdin;
  592.     if (!fp)
  593.       fatal(optarg, errno);
  594.     keyalloc = 1024;
  595.     keys = xmalloc(keyalloc);
  596.     keycc = 0;
  597.     while (!feof(fp)
  598.            && (cc = fread(keys + keycc, 1, keyalloc - keycc, fp)) > 0)
  599.       {
  600.         keycc += cc;
  601.         if (keycc == keyalloc)
  602.           keys = xrealloc(keys, keyalloc *= 2);
  603.       }
  604.     if (fp != stdin)
  605.       fclose(fp);
  606.     break;
  607.       case 'h':
  608.     no_filenames = 1;
  609.     break;
  610.       case 'i':
  611.       case 'y':            /* For old-timers . . . */
  612.     match_fold = 1;
  613.     break;
  614.       case 'l':
  615.     out_silent = 1;
  616.     list_files = 1;
  617.     break;
  618.       case 'n':
  619.     out_line = 1;
  620.     break;
  621.       case 's':
  622.     out_silent = 1;
  623.     break;
  624.       case 'v':
  625.     out_invert = 1;
  626.     break;
  627.       case 'w':
  628.     match_words = 1;
  629.     break;
  630.       case 'x':
  631.     match_lines = 1;
  632.     break;
  633.       default:
  634.     usage();
  635.     break;
  636.       }
  637.  
  638.   if (!keys)
  639.     if (optind < argc)
  640.       {
  641.     keys = argv[optind++];
  642.     keycc = strlen(keys);
  643.       }
  644.     else
  645.       usage();
  646.  
  647.   compile(keys, keycc);
  648.  
  649.   if (argc - optind > 1 && !no_filenames)
  650.     out_file = 1;
  651.  
  652.   status = 1;
  653.   initbuf();
  654.  
  655.   if (optind < argc)
  656.     while (optind < argc)
  657.       {
  658.     desc = strcmp(argv[optind], "-") ? open(argv[optind], 0) : 0;
  659.     if (desc < 0)
  660.       error(argv[optind], errno);
  661.     else
  662.       {
  663.         count = grep(desc, argv[optind]);
  664.         if (count_matches)
  665.           {
  666.         if (out_file)
  667.           printf("%s:", argv[optind]);
  668.         printf("%d\n", count);
  669.           }
  670.         if (count)
  671.           {
  672.         status = 0;
  673.         if (list_files)
  674.           printf("%s\n", argv[optind]);
  675.           }
  676.       }
  677.     if (desc)
  678.       close(desc);
  679.     ++optind;
  680.       }
  681.   else
  682.     {
  683.       count = grep(0, "<stdin>");
  684.       if (count_matches)
  685.     printf("%d\n", count);
  686.       if (count)
  687.     {
  688.       status = 0;
  689.       if (list_files)
  690.         printf("%s\n", argv[optind]);
  691.     }
  692.     }
  693.  
  694.   exit(error_seen ? 2 : status);
  695. }
  696.