Category : OS/2 Files
Archive   : GNUGREP.ZIP
Filename : FGREP.C

 
Output of file : FGREP.C contained in archive : GNUGREP.ZIP
/* fgrep.c - grep program built around matcher.
Copyright 1989 Free Software Foundation
Written August 1989 by Mike Haertel.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

The author may be reached (Email) at the address [email protected],
or (US mail) as Mike Haertel c/o Free Software Foundation. */

#include "std.h"
#include "unix.h"

#include
#include
#include

#include "kwset.h"

#define NCHAR (UCHAR_MAX + 1)

/* For error messages. */
static const char *prog;
static int error_seen;

/* Flags controlling the style of output. */
static int out_silent; /* Suppress all normal output. */
static int out_invert; /* Print nonmatching stuff. */
static int out_file; /* Print filenames. */
static int out_line; /* Print line numbers. */
static int out_byte; /* Print byte offsets. */
static int out_before; /* Lines of leading context. */
static int out_after; /* Lines of trailing context. */

/* Print MESG and possibly the error string for ERRNUM. Remember
that something awful happened. */
static void
DEFUN(error, (mesg, errnum), const char *mesg AND int errnum)
{
if (errnum)
fprintf(stderr, "%s: %s: %s\n", prog, mesg, strerror(errnum));
else
fprintf(stderr, "%s: %s\n", prog, mesg);
error_seen = 1;
}

/* Like error(), but die horribly after printing. */
static void
DEFUN(fatal, (mesg, errnum), const char *mesg AND int errnum)
{
error(mesg, errnum);
exit(2);
}

/* Interface to handle errors and fix library lossage. */
static PTR
DEFUN(xmalloc, (size), size_t size)
{
PTR result;

result = malloc(size);
if (size && !result)
fatal("memory exhausted", 0);
return result;
}

/* Interface to handle errors and fix some library lossage. */
static PTR
DEFUN(xrealloc, (ptr, size), PTR ptr AND size_t size)
{
PTR result;

if (ptr)
result = realloc(ptr, size);
else
result = malloc(size);
if (size && !result)
fatal("memory exhausted", 0);
return result;
}

/* Compiled search pattern. */
kwset_t kwset;

/* Flags controlling how pattern matching is performed. */
static int match_fold; /* Fold all letters to one case. */
static int match_words; /* Match only whole words. */
static int match_lines; /* Match only whole lines. */

static void
DEFUN(compile, (pattern, size), const char *pattern AND size_t size)
{
const char *beg, *lim, *err;
static char trans[NCHAR];
int i;

if (match_fold)
for (i = 0; i < NCHAR; ++i)
trans[i] = TOLOWER(i);

if (!(kwset = kwsalloc(match_fold ? trans : (const char *) NULL)))
fatal("memory exhausted", 0);

beg = pattern;
do
{
for (lim = beg; lim < pattern + size && *lim != '\n'; ++lim)
;
if (err = kwsincr(kwset, beg, lim - beg))
fatal(err, 0);
if (lim < pattern + size)
++lim;
beg = lim;
}
while (beg < pattern + size);

if (err = kwsprep(kwset))
fatal(err, 0);
}

static char *
DEFUN(execute, (buf, size), char *buf AND size_t size)
{
register char *beg, *try;
register size_t len;
struct kwsmatch kwsmatch;

beg = buf;
for (;beg <= buf + size; ++beg)
{
if (!(beg = kwsexec(kwset, beg, buf + size - beg, &kwsmatch)))
return NULL;;
len = kwsmatch.size[0];
if (match_lines)
{
if (beg > buf && beg[-1] != '\n')
continue;
if (beg + len < buf + size && *(beg + len) != '\n')
continue;
return beg;
}
else if (match_words)
for (try = beg; len && try;)
{
if (try > buf && (ISALNUM((unsigned char) try[-1])
|| !ISALNUM((unsigned char) *try)))
goto retry;
if (try + len < buf + size
&& (ISALNUM((unsigned char) *(try + len))
|| !ISALNUM((unsigned char) (try + len)[-1])))
goto retry;
return try;
retry:
if (--len)
try = kwsexec(kwset, beg, len, &kwsmatch);
else
break;
len = kwsmatch.size[0];
}
else
return beg;
}

return NULL;
}

/* Hairy buffering mechanism to efficiently support all the options. */
static char *bufbeg; /* Beginning of user-visible portion. */
static char *buflim; /* Limit of user-visible portion. */
static char *buf; /* Pointer to base of buffer. */
static size_t bufalloc; /* Allocated size of buffer. */
static size_t bufcc; /* Count of characters in buffer. */
static unsigned long int buftotalcc;
/* Total character count since reset. */
static char *buflast; /* Pointer after last character printed. */
static int bufgap; /* Weird flag indicating buflast is a lie. */
static unsigned long int buftotalnl;
/* Count of newlines before last character. */
static int bufpending; /* Lines of pending output at buflast. */
static int bufdesc; /* File descriptor to read from. */
static int bufeof; /* Flag indicating EOF reached. */
static const char *buffile; /* File name for messages. */

/* Scan and count the newlines prior to LIM in the buffer. */
static void
DEFUN(nlscan, (lim), register char *lim)
{
register char *p;

for (p = buflast; p < lim; ++p)
if (*p == '\n')
++buftotalnl;
buflast = lim;
}

/* Print the line beginning at BEG, using SEP to separate optional label
fields from the text of the line. Return the size of the line. */
static size_t
DEFUN(prline, (beg, sep), register char *beg AND register char sep)
{
register size_t cc;
register char c;
static int err;

cc = 0;

if (out_silent || err)
while (beg < buflim)
{
++cc;
if (*beg++ == '\n')
break;
}
else
{
if (out_file)
printf("%s%c", buffile, sep);
if (out_line)
{
nlscan(beg);
printf("%d%c", buftotalnl + 1, sep);
}
if (out_byte)
printf("%lu%c", buftotalcc + (beg - buf), sep);
while (beg < buflim)
{
++cc;
c = *beg++;
putchar(c);
if (c == '\n')
break;
}
if (ferror(stdout))
{
error("output error", errno);
err = 1;
}
}

if (out_line)
nlscan(beg);
else
buflast = beg;
bufgap = 0;

return cc;
}

/* Print pending bytes of last trailing context prior to LIM. */
static void
DEFUN(prpending, (lim), register char *lim)
{
while (buflast < lim && bufpending)
{
--bufpending;
prline(buflast, '-');
}
}

/* Print the lines between BEG and LIM. Deal with context crap.
Return the count of lines between BEG and LIM. */
static int
DEFUN(prtext, (beg, lim), char *beg AND char *lim)
{
static int used;
register char *p;
int i, n;

prpending(beg);

p = beg;
for (i = 0; i < out_before; ++i)
if (p > buflast)
do
--p;
while (p > buflast && p[-1] != '\n');

if ((out_before || out_after) && used && (p > buflast || bufgap))
puts("--");

while (p < beg)
p += prline(p, '-');

n = 0;
while (p < lim)
{
++n;
p += prline(p, ':');
}

bufpending = out_after;
used = 1;

return n;
}

/* Fill the user-visible portion of the buffer, returning a byte count. */
static int
fillbuf()
{
register char *b, *d, *l;
int i, cc;
size_t discard, save;

prpending(buflim);

b = buflim;
for (i = 0; i < out_before; ++i)
if (b > buflast)
do
--b;
while (b > buflast && b[-1] != '\n');

if (buflast < b)
bufgap = 1;
if (out_line)
nlscan(b);

discard = b - buf;
save = buflim - b;

if (b > buf)
{
d = buf;
l = buf + bufcc;
while (b < l)
*d++ = *b++;
}

bufcc -= discard;
buftotalcc += discard;

do
{
if (!bufeof)
{
if (bufcc > bufalloc / 2)
buf = xrealloc(buf, bufalloc *= 2);
cc = read(bufdesc, buf + bufcc, bufalloc - bufcc);
if (cc < 0)
{
error(buffile, errno);
bufeof = 1;
}
else
{
bufeof = !cc;
bufcc += cc;
}
}
bufbeg = buf + save;
for (l = buf + bufcc; l > bufbeg && l[-1] != '\n'; --l)
;
buflim = l;
buflast = buf;
}
while (!bufeof && bufbeg == buflim);

if (bufeof)
buflim = buf + bufcc;

return buflim - bufbeg;
}

/* One-time initialization. */
static void
initbuf()
{
bufalloc = 8192;
buf = xmalloc(bufalloc);
}

/* Reset the buffer for a new file. */
static void
DEFUN(resetbuf, (desc, file), int desc AND const char *file)
{
bufbeg = buf;
buflim = buf;
bufcc = 0;
buftotalcc = 0;
buflast = buf;
bufgap = 0;
buftotalnl = 0;
bufpending = 0;
bufdesc = desc;
bufeof = 0;
buffile = file;
}

/* Scan the user-visible portion of the buffer, calling prtext() for
matching lines (or between matching lines if OUT_INVERT is true).
Return a count of lines printed. */
static int
grepbuf()
{
int total;
register char *p, *b, *l;

total = 0;
p = bufbeg;
while (b = execute(p, buflim - p))
{
if (b == buflim && (b > bufbeg && b[-1] == '\n' || b == bufbeg))
break;
while (b > bufbeg && b[-1] != '\n')
--b;
l = b + 1;
while (l < buflim && l[-1] != '\n')
++l;
if (!out_invert)
total += prtext(b, l);
else if (p < b)
total += prtext(p, b);
p = l;
}
if (out_invert && p < buflim)
total += prtext(p, buflim);
return total;
}

/* Scan the given file, returning a count of lines printed. */
static int
DEFUN(grep, (desc, file), int desc AND const char *file)
{
int total;

total = 0;
resetbuf(desc, file);
while (fillbuf())
total += grepbuf();
return total;
}

static const char version[] = "GNU fgrep, version 1.1";

static void
usage()
{
printf("\n%s\n", version);
printf("\nUsage: %s [-[[AB]]] [-[CVchilnsvwx]] [-[ef]] []\n", prog);

printf("\n -A print lines of context after every matching line"
"\n -B print lines of context before every matching line"
"\n -C print 2 lines of context on each side of every match"
"\n - print lines of context on each side"
"\n -V print the version number on stderr");
printf("\n -b print every match preceded by its byte offset"
"\n -c print a total count of matching lines only"
"\n -e search for ; useful if begins with -"
"\n -f take from the given "
"\n -h don't display filenames on matches");
printf("\n -i ignore case difference when comparing strings"
"\n -l list files containing matches only"
"\n -n print each match preceded by its line number"
"\n -s run silently producing no output except error messages"
"\n -v print only lines that contain no matches for the "
"\n -w print only lines where the match is a complete word"
"\n -x print only lines where the match is a whole line\n");

exit(2);
}

int
DEFUN(main, (argc, argv), int argc AND char *argv[])
{
char *keys;
size_t keycc, keyalloc;
int count_matches, no_filenames, list_files;
int opt, cc, desc, count, status;
FILE *fp;

#ifdef __EMX__
_wildcard(&argc, &argv);
setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
#endif

prog = argv[0];
if (prog && strrchr(prog, '/'))
prog = strrchr(prog, '/') + 1;

keys = NULL;
count_matches = 0;
no_filenames = 0;
list_files = 0;

while ((opt = getopt(argc, argv, "0123456789A:B:CVbce:f:hilnsvwxy")) != EOF)
switch (opt)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
out_before = 10 * out_before + opt - '0';
out_after = 10 * out_after + opt - '0';
break;
case 'A':
out_after = atoi(optarg);
if (out_after < 0)
usage();
break;
case 'B':
out_before = atoi(optarg);
if (out_before < 0)
usage();
break;
case 'C':
out_before = out_after = 2;
break;
case 'V':
fprintf(stderr, "%s\n", version);
break;
case 'b':
out_byte = 1;
break;
case 'c':
out_silent = 1;
count_matches = 1;
break;
case 'e':
if (keys)
usage();
keys = optarg;
keycc = strlen(keys);
break;
case 'f':
if (keys)
usage();
fp = strcmp(optarg, "-") ? fopen(optarg, "r") : stdin;
if (!fp)
fatal(optarg, errno);
keyalloc = 1024;
keys = xmalloc(keyalloc);
keycc = 0;
while (!feof(fp)
&& (cc = fread(keys + keycc, 1, keyalloc - keycc, fp)) > 0)
{
keycc += cc;
if (keycc == keyalloc)
keys = xrealloc(keys, keyalloc *= 2);
}
if (fp != stdin)
fclose(fp);
break;
case 'h':
no_filenames = 1;
break;
case 'i':
case 'y': /* For old-timers . . . */
match_fold = 1;
break;
case 'l':
out_silent = 1;
list_files = 1;
break;
case 'n':
out_line = 1;
break;
case 's':
out_silent = 1;
break;
case 'v':
out_invert = 1;
break;
case 'w':
match_words = 1;
break;
case 'x':
match_lines = 1;
break;
default:
usage();
break;
}

if (!keys)
if (optind < argc)
{
keys = argv[optind++];
keycc = strlen(keys);
}
else
usage();

compile(keys, keycc);

if (argc - optind > 1 && !no_filenames)
out_file = 1;

status = 1;
initbuf();

if (optind < argc)
while (optind < argc)
{
desc = strcmp(argv[optind], "-") ? open(argv[optind], 0) : 0;
if (desc < 0)
error(argv[optind], errno);
else
{
count = grep(desc, argv[optind]);
if (count_matches)
{
if (out_file)
printf("%s:", argv[optind]);
printf("%d\n", count);
}
if (count)
{
status = 0;
if (list_files)
printf("%s\n", argv[optind]);
}
}
if (desc)
close(desc);
++optind;
}
else
{
count = grep(0, "");
if (count_matches)
printf("%d\n", count);
if (count)
{
status = 0;
if (list_files)
printf("%s\n", argv[optind]);
}
}

exit(error_seen ? 2 : status);
}


  3 Responses to “Category : OS/2 Files
Archive   : GNUGREP.ZIP
Filename : FGREP.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/