From:	MERC::"uunet!WKUVX1.BITNET!FILESERV-Mgr" 12-JUN-1992 15:52:55.07
To:	galaxy::gleeve
CC:	
Subj:	FGREP.01_OF_06

$! ------------------ CUT HERE -----------------------
$ v='f$verify(f$trnlnm("SHARE_VERIFY"))'
$!
$! This archive created by VMS_SHARE Version 7.2-007  22-FEB-1990
$!   On 11-JUN-1992 20:55:33.00   By user GOATHUNTER (@WKUVX1.BITNET)
$!
$! This VMS_SHARE Written by:
$!    Andy Harper, Kings College London UK
$!
$! Acknowledgements to:
$!    James Gray       - Original VMS_SHARE
$!    Michael Bednarek - Original Concept and implementation
$!
$!+ THIS PACKAGE DISTRIBUTED IN 6 PARTS, TO KEEP EACH PART
$!  BELOW 60 BLOCKS
$!
$! TO UNPACK THIS SHARE FILE, CONCATENATE ALL PARTS IN ORDER
$! AND EXECUTE AS A COMMAND PROCEDURE  (  @name  )
$!
$! THE FOLLOWING FILE(S) WILL BE CREATED AFTER UNPACKING:
$!       1. [.FGREP011]AAAREADME.TXT;1
$!       2. [.FGREP011]ALLOCA.C;1
$!       3. [.FGREP011]DESCRIP.MMS;1
$!       4. [.FGREP011]DIR.H;1
$!       5. [.FGREP011]FGREP.C;1
$!       6. [.FGREP011]FGREP.CLD;1
$!       7. [.FGREP011]GETOPT.C;1
$!       8. [.FGREP011]GREP.RNH;1
$!       9. [.FGREP011]KWSET.C;1
$!      10. [.FGREP011]KWSET.H;1
$!      11. [.FGREP011]MAKEFILE.;1
$!      12. [.FGREP011]OBSTACK.C;1
$!      13. [.FGREP011]OBSTACK.H;1
$!      14. [.FGREP011]README.;1
$!      15. [.FGREP011]SHELL_MUNG.C;1
$!      16. [.FGREP011]STD.C;1
$!      17. [.FGREP011]STD.H;1
$!      18. [.FGREP011]UNIX.H;1
$!      19. [.FGREP011]VMSMAKE.COM;1
$!      20. [.FGREP011]XALLOC.C;1
$!
$set="set"
$set symbol/scope=(nolocal,noglobal)
$f=f$parse("SHARE_TEMP","SYS$SCRATCH:.TMP_"+f$getjpi("","PID"))
$e="write sys$error  ""%UNPACK"", "
$w="write sys$output ""%UNPACK"", "
$ if f$trnlnm("SHARE_LOG") then $ w = "!"
$ ve=f$getsyi("version")
$ if ve-f$extract(0,1,ve) .ges. "4.4" then $ goto START
$ e "-E-OLDVER, Must run at least VMS 4.4"
$ v=f$verify(v)
$ exit 44
$UNPACK: SUBROUTINE ! P1=filename, P2=checksum
$ if f$search(P1) .eqs. "" then $ goto file_absent
$ e "-W-EXISTS, File ''P1' exists. Skipped."
$ delete 'f'*
$ exit
$file_absent:
$ if f$parse(P1) .nes. "" then $ goto dirok
$ dn=f$parse(P1,,,"DIRECTORY")
$ w "-I-CREDIR, Creating directory ''dn'."
$ create/dir 'dn'
$ if $status then $ goto dirok
$ e "-E-CREDIRFAIL, Unable to create ''dn'. File skipped."
$ delete 'f'*
$ exit
$dirok:
$ w "-I-PROCESS, Processing file ''P1'."
$ if .not. f$verify() then $ define/user sys$output nl:
$ EDIT/TPU/NOSEC/NODIS/COM=SYS$INPUT 'f'/OUT='P1'
PROCEDURE Unpacker ON_ERROR ENDON_ERROR;SET(FACILITY_NAME,"UNPACK");SET(
SUCCESS,OFF);SET(INFORMATIONAL,OFF);f:=GET_INFO(COMMAND_LINE,"file_name");b:=
CREATE_BUFFER(f,f);p:=SPAN(" ")@r&LINE_END;POSITION(BEGINNING_OF(b));
LOOP EXITIF SEARCH(p,FORWARD)=0;POSITION(r);ERASE(r);ENDLOOP;POSITION(
BEGINNING_OF(b));g:=0;LOOP EXITIF MARK(NONE)=END_OF(b);x:=ERASE_CHARACTER(1);
IF g=0 THEN IF x="X" THEN MOVE_VERTICAL(1);ENDIF;IF x="V" THEN APPEND_LINE;
MOVE_HORIZONTAL(-CURRENT_OFFSET);MOVE_VERTICAL(1);ENDIF;IF x="+" THEN g:=1;
ERASE_LINE;ENDIF;ELSE IF x="-" THEN IF INDEX(CURRENT_LINE,"+-+-+-+-+-+-+-+")=
1 THEN g:=0;ENDIF;ENDIF;ERASE_LINE;ENDIF;ENDLOOP;t:="0123456789ABCDEF";
POSITION(BEGINNING_OF(b));LOOP r:=SEARCH("`",FORWARD);EXITIF r=0;POSITION(r);
ERASE(r);x1:=INDEX(t,ERASE_CHARACTER(1))-1;x2:=INDEX(t,ERASE_CHARACTER(1))-1;
COPY_TEXT(ASCII(16*x1+x2));ENDLOOP;WRITE_FILE(b,GET_INFO(COMMAND_LINE,
"output_file"));ENDPROCEDURE;Unpacker;QUIT;
$ delete/nolog 'f'*
$ CHECKSUM 'P1'
$ IF CHECKSUM$CHECKSUM .eqs. P2 THEN $ EXIT
$ e "-E-CHKSMFAIL, Checksum of ''P1' failed."
$ ENDSUBROUTINE
$START:
$ create 'f'
XGNU fgrep v1.1  -  Search a file for a pattern
X
XThis version of GNU fgrep v1.1 was taken via anonymous ftp from
Xprep.ai.mit.edu and modified to run under VMS.  It compiles under
XVMS using GNU C or VAX C and was tested with GNU C v1.39.1 and
XVAX C v3.1 under VMS v5.4-2.
X
XAs supplied, VMSMAKE.COM also compiles SHELL_MUNG.C, which will allow
Xfgrep to handle wildcarded file specs and some redirection.
X
XTo install:
X
X`09$ @VMSMAKE.COM
X`09$ FGREP :== $dev:`5Bdir`5DFGREP.EXE
X`09$ LIBRARY/HELP/INSERT library GREP
X
XNew to this distribution:
X
X`09GETOPT.C`09`09Taken from GNU grep distribution because
X`09`09`09`09it wasn't in the GNU fgrep distribution
X`09GREP.RNH`09`09RUNOFF source for on-line VMS help
X`09SHELL_MUNG.C`09`09Jym Dyer's routine to emulate UNIX shell
X`09FGREP.C`09`09`09Modified for VMS
X`09UNIX.H`09`09`09Modified for VMS
X`09STD.H`09`09`09Modified for VMS
X`09VMSMAKE.COM`09`09DCL command procedure to build fgrep
X`09DESCRIP.MMS`09`09MMS procedure to build fgrep
X
XThis version of grep also includes a few VMS-specific (bracketed by #ifdef V
VMS)
Xchanges.  Specifically:
X
X    1.  Added call to shell_mung
X    2.  Modified error() so that strerror accepted two arguments
X    3.  The exit statuses were changed to better fit VMS:
X            Meaning                  UNIX       VMS
X            -------                  ----       ---
X            matches found               0         1
X            no matches found            1         3
X            error                       2        44 (SS$_ABORT)
X    4.  Modified print_line to use printf when printing lines instead of
X        putchar.  Much faster output on VMS.
X
XI also modified SHELL_MUNG.C to allow it to be compiled by GNU C.
X
XAny suggestions/comments/etc. can be sent to the address below.
X
XHunter Goatley, VAX Systems Programmer      E-mail: goathunter@WKUVX1.BITNET
XAcademic Computing, STH 226                 Voice:  (502) 745-5251
XWestern Kentucky University
XBowling Green, KY 42101
$ CALL UNPACK [.FGREP011]AAAREADME.TXT;1 2083090673
$ create 'f'
X/*
X`09alloca -- (mostly) portable public-domain implementation -- D A Gwyn
X
X`09This implementation of the PWB library alloca() function,
X`09which is used to allocate space off the run-time stack so
X`09that it is automatically reclaimed upon procedure exit,`20
X`09was inspired by discussions with J. Q. Johnson of Cornell.
X
X`09It should work under any C implementation that uses an
X`09actual procedure stack (as opposed to a linked list of
X`09frames).  There are some preprocessor constants that can
X`09be defined when compiling for your specific system, for
X`09improved efficiency; however, the defaults should be okay.
X
X`09The general concept of this implementation is to keep
X`09track of all alloca()-allocated blocks, and reclaim any
X`09that are found to be deeper in the stack than the current
X`09invocation.  This heuristic does not reclaim storage as
X`09soon as it becomes invalid, but it will do so eventually.
X
X`09As a special case, alloca(0) reclaims storage without
X`09allocating any.  It is a good idea to use alloca(0) in
X`09your main control loop, etc. to force garbage collection.
X*/
X#ifndef lint
Xstatic char`09SCCSid`5B`5D = "@(#)alloca.c`091.1";`09/* for the "what" utili
Vty */
X#endif
X
X#ifdef emacs
X#include "config.h"
X#ifdef static
X/* actually, only want this if static is defined as ""
X   -- this is for usg, in which emacs must undefine static
X   in order to make unexec workable
X   */
X#ifndef STACK_DIRECTION
Xyou
Xlose
X-- must know STACK_DIRECTION at compile-time
X#endif /* STACK_DIRECTION undefined */
X#endif static
X#endif emacs
X
X#ifdef X3J11
Xtypedef void`09*pointer;`09`09/* generic pointer type */
X#else
Xtypedef char`09*pointer;`09`09/* generic pointer type */
X#endif
X
X#define`09NULL`090`09`09`09/* null pointer constant */
X
Xextern void`09free();
Xextern pointer`09malloc();
X
X/*
X`09Define STACK_DIRECTION if you know the direction of stack
X`09growth for your system; otherwise it will be automatically
X`09deduced at run-time.
X
X`09STACK_DIRECTION > 0 => grows toward higher addresses
X`09STACK_DIRECTION < 0 => grows toward lower addresses
X`09STACK_DIRECTION = 0 => direction of growth unknown
X*/
X
X#ifndef STACK_DIRECTION
X#define`09STACK_DIRECTION`090`09`09/* direction unknown */
X#endif
X
X#if STACK_DIRECTION != 0
X
X#define`09STACK_DIR`09STACK_DIRECTION`09/* known at compile-time */
X
X#else`09/* STACK_DIRECTION == 0; need run-time code */
X
Xstatic int`09stack_dir;`09`09/* 1 or -1 once known */
X#define`09STACK_DIR`09stack_dir
X
Xstatic void
Xfind_stack_direction (/* void */)
X`7B
X  static char`09*addr = NULL;`09/* address of first
X`09`09`09`09   `60dummy', once known */
X  auto char`09dummy;`09`09/* to get stack address */
X
X  if (addr == NULL)
X    `7B`09`09`09`09/* initial entry */
X      addr = &dummy;
X
X      find_stack_direction ();`09/* recurse once */
X    `7D
X  else`09`09`09`09/* second entry */
X    if (&dummy > addr)
X      stack_dir = 1;`09`09/* stack grew upward */
X    else
X      stack_dir = -1;`09`09/* stack grew downward */
X`7D
X
X#endif`09/* STACK_DIRECTION == 0 */
X
X/*
X`09An "alloca header" is used to:
X`09(a) chain together all alloca()ed blocks;
X`09(b) keep track of stack depth.
X
X`09It is very important that sizeof(header) agree with malloc()
X`09alignment chunk size.  The following default should work okay.
X*/
X
X#ifndef`09ALIGN_SIZE
X#define`09ALIGN_SIZE`09sizeof(double)
X#endif
X
Xtypedef union hdr
X`7B
X  char`09align`5BALIGN_SIZE`5D;`09/* to force sizeof(header) */
X  struct
X    `7B
X      union hdr *next;`09`09/* for chaining headers */
X      char *deep;`09`09/* for stack depth measure */
X    `7D h;
X`7D header;
X
X/*
X`09alloca( size ) returns a pointer to at least `60size' bytes of
X`09storage which will be automatically reclaimed upon exit from
X`09the procedure that called alloca().  Originally, this space
X`09was supposed to be taken from the current stack frame of the
X`09caller, but that method cannot be made to work for some
X`09implementations of C, for example under Gould's UTX/32.
X*/
X
Xstatic header *last_alloca_header = NULL; /* -> last alloca header */
X
Xpointer
Xalloca (size)`09`09`09/* returns pointer to storage */
X     unsigned`09size;`09`09/* # bytes to allocate */
X`7B
X  auto char`09probe;`09`09/* probes stack depth: */
X  register char`09*depth = &probe;
X
X#if STACK_DIRECTION == 0
X  if (STACK_DIR == 0)`09`09/* unknown growth direction */
X    find_stack_direction ();
X#endif
X
X`09`09`09`09/* Reclaim garbage, defined as all alloca()ed storage that
X`09`09`09`09   was allocated from deeper in the stack than currently. */
X
X  `7B
X    register header`09*hp;`09/* traverses linked list */
X
X    for (hp = last_alloca_header; hp != NULL;)
X      if (STACK_DIR > 0 && hp->h.deep > depth
X`09  `7C`7C STACK_DIR < 0 && hp->h.deep < depth)
X`09`7B
X`09  register header`09*np = hp->h.next;
X
X`09  free ((pointer) hp);`09/* collect garbage */
X
X`09  hp = np;`09`09/* -> next header */
X`09`7D
X      else
X`09break;`09`09`09/* rest are not deeper */
X
X    last_alloca_header = hp;`09/* -> last valid storage */
X  `7D
X
X  if (size == 0)
X    return NULL;`09`09/* no allocation required */
X
X  /* Allocate combined header + user data storage. */
X
X  `7B
X    register pointer`09new = malloc (sizeof (header) + size);
X    /* address of header */
X
X    ((header *)new)->h.next = last_alloca_header;
X    ((header *)new)->h.deep = depth;
X
X    last_alloca_header = (header *)new;
X
X    /* User storage begins just after header. */
X
X    return (pointer)((char *)new + sizeof(header));
X  `7D
X`7D
$ CALL UNPACK [.FGREP011]ALLOCA.C;1 306858353
$ create 'f'
X!
X! VMS MMS to build GNU fgrep
X!
X!  Uncomment the following line to compile with GNU C
X!
X!CC = GCC
X
X.IFDEF GNU_C
XCC = GCC
XOPTIONS = GNU_CC:`5B000000`5DOPTIONS.OPT/OPT
X.ELSE
XOPTIONS = fgrep.opt/options
X.ENDIF
X
XMAKEFILE = DESCRIP.MMS
XLIBS = SYS$SHARE:VAXCRTL.EXE/SHARE
X
X!CFLAGS = /NOOPT/DEBUG/ANA
XCFLAGS = /NODEBUG
XLINKFLAGS = /NOTRACE/NODEBUG/NOMAP
X
XOBJS = getopt.obj, kwset.obj, obstack.obj, shell_mung.obj, std.obj, -
X`09xalloc.obj, alloca.obj
XFOBJ = fgrep.obj
X
Xfgrep : fgrep.exe, grep.hlp
X`09!fgrep build complete
X
Xfgrep.exe : $(OBJS), $(FOBJ), fgrep.opt
X`09$(LINK) $(LINKFLAGS) $(FOBJ), $(OBJS), $(OPTIONS)
X
Xfgrep.opt : $(MAKEFILE)
X`09open/write opt fgrep.opt
X`09write opt "! GNU fgrep linker options file"
X      @ write opt "$(LIBS)"
X`09close opt
X
Xgrep.hlp : grep.rnh
X`09runoff grep.rnh
X
Xclean :
X`09delete/noconfirm fgrep.exe;*, *.obj;*, grep.hlp;, fgrep.opt;*
X
Xfgrep.obj kwset.obj std.obj`09: std.h
Xfgrep.obj std.obj`09`09: unix.h
Xfgrep.obj kwset.obj`09`09: kwset.h
Xkwset.obj obstack.obj`09`09: obstack.h
$ CALL UNPACK [.FGREP011]DESCRIP.MMS;1 408047484
$ create 'f'
X/* GNU Emacs VMS directory definition file.
X   Copyright (C) 1986 Free Software Foundation, Inc.
X
XThis file is part of GNU Emacs.
X
XGNU Emacs is free software; you can redistribute it and/or modify
Xit under the terms of the GNU General Public License as published by
Xthe Free Software Foundation; either version 1, or (at your option)
Xany later version.
X
XGNU Emacs is distributed in the hope that it will be useful,
Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
XGNU General Public License for more details.
X
XYou should have received a copy of the GNU General Public License
Xalong with GNU Emacs; see the file COPYING.  If not, write to
Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
X
X/*
X * Files-11 Ver. 2 directory structure (VMS V4.x - long names)
X */
X#ifndef DIR$K_LENGTH
X
X#define`09DIR$C_FID`090
X#define`09DIR$C_LINKNAME`091
X#define`09DIR$K_LENGTH`096
X#define`09DIR$C_LENGTH`096
X#define`09DIR$S_DIRDEF`096
X#define`09DIR$W_SIZE`090
X#define`09DIR$W_VERLIMIT`092
X#define`09DIR$B_FLAGS`094
X#define`09DIR$S_TYPE`093
X#define`09DIR$V_TYPE`090
X#define`09DIR$V_NEXTREC`096
X#define`09DIR$V_PREVREC`097
X#define`09DIR$B_NAMECOUNT`095
X#define`09DIR$S_NAME`0980
X#define`09DIR$T_NAME`096
X
X#define`09DIR$K_VERSION`098
X#define`09DIR$C_VERSION`098
X#define`09DIR$S_DIRDEF1`098
X#define`09DIR$W_VERSION`090
X#define`09DIR$S_FID`096
X#define`09DIR$W_FID`092
X#define`09DIR$W_FID_NUM`092
X#define`09DIR$W_FID_SEQ`094
X#define`09DIR$W_FID_RVN`096
X#define`09DIR$B_FID_RVN`096
X#define`09DIR$B_FID_NMX`097
X
X#define`09DIR$S_DIRDEF2`091
X#define`09DIR$T_LINKNAME`090
X
Xtypedef struct dir$_name `7B
X/*  short dir$w_size;`09`09/* if you read with RMS, it eats this... */
X  short dir$w_verlimit;`09`09`09/* maximum number of versions */
X  union `7B
X    unsigned char dir_b_flags;
X#define dir$b_flags dir__b_flags.dir_b_flags
X    struct `7B
X      unsigned char dir_v_type: DIR$S_TYPE;
X#define dir$v_type dir__b_flags.dir___b_flags.dir_v_type
X      unsigned char: 3;
X      unsigned char dir_v_nextrec: 1;
X#define dir$v_nextrec dir__b_flags.dir___b_flags.dir_v_nextrec
X      unsigned char dir_v_prevrec: 1;
X#define dir$v_prevrec dir__b_flags.dir___b_flags.dir_v_prevrec
X    `7D dir___b_flags;
X  `7D dir__b_flags;
X  unsigned char dir$b_namecount;
X  char dir$t_name`5B255`5D;
X`7D dir$_dirdef;`09`09/* only the fixed first part */
X
Xtypedef struct dir$_version `7B
X  short dir$w_version;
X  short dir$w_fid_num;
X  short dir$w_fid_seq;
X  union `7B
X    short dir_w_fid_rvn;
X#define dir$w_fid_rvn dir__w_fid_rvn.dir_w_fid_rvn
X    struct `7B
X      char dir_b_fid_rvn;
X#define dir$b_fid_rvn dir__w_fid_rvn.dir___w_fid_rvn.dir_b_fid_rvn
X      char dir_b_fid_nmx;
X#define dir$b_fid_nmx dir__w_fid_rvn.dir___w_fid_rvn.dir_b_fid_nmx
X    `7D dir___w_fid_rvn;
X  `7D dir__w_fid_rvn;
X`7D dir$_dirdef1;`09`09/* one for each version of the file */
X
Xtypedef
Xstruct dir$_linkname `7B
X  char    dir$t_linkname`5B255`5D;
X`7D dir$_dirdef2;
X
X#endif
$ CALL UNPACK [.FGREP011]DIR.H;1 1463240667
$ create 'f'
X/* fgrep.c - grep program built around matcher.
X   Copyright 1989 Free Software Foundation
X`09`09  Written August 1989 by Mike Haertel.
X
X   This program is free software; you can redistribute it and/or modify
X   it under the terms of the GNU General Public License as published by
X   the Free Software Foundation; either version 1, or (at your option)
X   any later version.
X
X   This program is distributed in the hope that it will be useful,
X   but WITHOUT ANY WARRANTY; without even the implied warranty of
X   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X   GNU General Public License for more details.
X
X   You should have received a copy of the GNU General Public License
X   along with this program; if not, write to the Free Software
X   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X
X   The author may be reached (Email) at the address mike@ai.mit.edu,
X   or (US mail) as Mike Haertel c/o Free Software Foundation. */
X
X/*
X
X  VMS-specific (#ifdef VMS) modifications added by:
X
X`09Hunter Goatley, VAX Systems Programmer, Western Kentucky University
X`09goathunter@WKUVX1.BITNET
X`0917-SEP-1991 07:56
X
X*/
X
X#ifdef VMS
X#include <ssdef.h>
X#endif
X
X#include "std.h"
X#include "unix.h"
X
X#include <errno.h>
X#include <stdio.h>
X#include <string.h>
X
X#include "kwset.h"
X
X#define NCHAR (UCHAR_MAX + 1)
X
X/* For error messages. */
Xstatic const char *prog;
Xstatic int error_seen;
X
X/* Flags controlling the style of output. */
Xstatic int out_silent;`09`09/* Suppress all normal output. */
Xstatic int out_invert;`09`09/* Print nonmatching stuff. */
Xstatic int out_file;`09`09/* Print filenames. */
Xstatic int out_line;`09`09/* Print line numbers. */
Xstatic int out_byte;`09`09/* Print byte offsets. */
Xstatic int out_before;`09`09/* Lines of leading context. */
Xstatic int out_after;`09`09/* Lines of trailing context. */
X
X/* Print MESG and possibly the error string for ERRNUM.  Remember
X   that something awful happened. */
Xstatic void
XDEFUN(error, (mesg, errnum), const char *mesg AND int errnum)
X`7B
X  if (errnum)
X#ifdef VMS
X    fprintf(stderr, "%s: %s: %s\n", prog, mesg, strerror(errnum, vaxc$errno)
V);
X#else
X    fprintf(stderr, "%s: %s: %s\n", prog, mesg, strerror(errnum));
X#endif
X  else
X    fprintf(stderr, "%s: %s\n", prog, mesg);
X  error_seen = 1;
X`7D
X
X/* Like error(), but die horribly after printing. */
Xstatic void
XDEFUN(fatal, (mesg, errnum), const char *mesg AND int errnum)
X`7B
X  error(mesg, errnum);
X#ifdef VMS
X  exit(SS$_ABORT);
X#else
X  exit(2);
X#endif
X`7D
X
X/* Interface to handle errors and fix library lossage. */
Xstatic PTR
XDEFUN(xmalloc, (size), size_t size)
X`7B
X  PTR result;
X
X  result = malloc(size);
X  if (size && !result)
X    fatal("memory exhausted", 0);
X  return result;
X`7D
X
X/* Interface to handle errors and fix some library lossage. */
Xstatic PTR
XDEFUN(xrealloc, (ptr, size), PTR ptr AND size_t size)
X`7B
X  PTR result;
X
X  if (ptr)
X    result = realloc(ptr, size);
X  else
X    result = malloc(size);
X  if (size && !result)
X    fatal("memory exhausted", 0);
X  return result;
X`7D
X
X/* Compiled search pattern. */
Xkwset_t kwset;
X
X/* Flags controlling how pattern matching is performed. */
Xstatic int match_fold;`09`09/* Fold all letters to one case. */
Xstatic int match_words;`09`09/* Match only whole words. */
Xstatic int match_lines;`09`09/* Match only whole lines. */
X
Xstatic void
XDEFUN(compile, (pattern, size), const char *pattern AND size_t size)
X`7B
X  const char *beg, *lim, *err;
X  static char trans`5BNCHAR`5D;
X  int i;
X
X  if (match_fold)
X    for (i = 0; i < NCHAR; ++i)
X      trans`5Bi`5D = TOLOWER(i);
X
X  if (!(kwset = kwsalloc(match_fold ? trans : (const char *) NULL)))
X    fatal("memory exhausted", 0);
X
X  beg = pattern;
X  do
X    `7B
X      for (lim = beg; lim < pattern + size && *lim != '\n'; ++lim)
X`09;
X      if (err = kwsincr(kwset, beg, lim - beg))
X`09fatal(err, 0);
X      if (lim < pattern + size)
X`09++lim;
X      beg = lim;
X    `7D
X  while (beg < pattern + size);
X
X  if (err = kwsprep(kwset))
X    fatal(err, 0);
X`7D
X
Xstatic char *
XDEFUN(execute, (buf, size), char *buf AND size_t size)
X`7B
X  register char *beg, *try;
X  register size_t len;
X  struct kwsmatch kwsmatch;
X
X  beg = buf;
X  for (;beg <= buf + size; ++beg)
X    `7B
X      if (!(beg = kwsexec(kwset, beg, buf + size - beg, &kwsmatch)))
X`09return NULL;;
X      len = kwsmatch.size`5B0`5D;
X      if (match_lines)
X`09`7B
X`09  if (beg > buf && beg`5B-1`5D != '\n')
X`09    continue;
X`09  if (beg + len < buf + size && *(beg + len) != '\n')
X`09    continue;
X`09  return beg;
X`09`7D
X      else if (match_words)
X`09for (try = beg; len && try;)
X`09  `7B
X`09    if (try > buf && (ISALNUM((unsigned char) try`5B-1`5D)
X`09`09`09      `7C`7C !ISALNUM((unsigned char) *try)))
X`09      goto retry;
X`09    if (try + len < buf + size
X`09`09&& (ISALNUM((unsigned char) *(try + len))
X`09`09    `7C`7C !ISALNUM((unsigned char) (try + len)`5B-1`5D)))
X`09      goto retry;
X`09    return try;
X`09  retry:
X`09    if (--len)
X`09      try = kwsexec(kwset, beg, len, &kwsmatch);
X`09    else
X`09      break;
X`09    len = kwsmatch.size`5B0`5D;
X`09  `7D
X      else
X`09return beg;
X    `7D
X
X  return NULL;
X`7D
X
X/* Hairy buffering mechanism to efficiently support all the options. */
Xstatic char *bufbeg;`09`09/* Beginning of user-visible portion. */
Xstatic char *buflim;`09`09/* Limit of user-visible portion. */
Xstatic char *buf;`09`09/* Pointer to base of buffer. */
Xstatic size_t bufalloc;`09`09/* Allocated size of buffer. */
Xstatic size_t bufcc;`09`09/* Count of characters in buffer. */
Xstatic unsigned long int buftotalcc;
X`09`09`09`09/* Total character count since reset. */
Xstatic char *buflast;`09`09/* Pointer after last character printed. */
Xstatic int bufgap;`09`09/* Weird flag indicating buflast is a lie. */
Xstatic unsigned long int buftotalnl;
X`09`09`09`09/* Count of newlines before last character. */
Xstatic int bufpending;`09`09/* Lines of pending output at buflast. */
Xstatic int bufdesc;`09`09/* File descriptor to read from. */
Xstatic int bufeof;`09`09/* Flag indicating EOF reached. */
Xstatic const char *buffile;`09/* File name for messages. */
X
X/* Scan and count the newlines prior to LIM in the buffer. */
Xstatic void
XDEFUN(nlscan, (lim), register char *lim)
X`7B
X  register char *p;
X
X  for (p = buflast; p < lim; ++p)
X    if (*p == '\n')
X      ++buftotalnl;
X  buflast = lim;
X`7D
X
X/* Print the line beginning at BEG, using SEP to separate optional label
X   fields from the text of the line.  Return the size of the line. */
Xstatic size_t
XDEFUN(prline, (beg, sep), register char *beg AND register char sep)
X`7B
X  register size_t cc;
X  register char c;
X  static int err;
X#ifdef VMS
X  register char *b;
X#endif
X `20
X  cc = 0;
X
X  if (out_silent `7C`7C err)
X    while (beg < buflim)
X      `7B
X`09++cc;
X`09if (*beg++ == '\n')
X`09  break;
X      `7D
X  else
X    `7B
X      if (out_file)
X`09printf("%s%c", buffile, sep);
X      if (out_line)
X`09`7B
X`09  nlscan(beg);
X`09  printf("%d%c", buftotalnl + 1, sep);
X`09`7D
X      if (out_byte)
X`09printf("%lu%c", buftotalcc + (beg - buf), sep);
X#ifdef VMS
X    /*  Use printf instead of putchar - much faster on VMS */
X    b = beg;
X    while (beg < buflim)
X      `7B
X`09++cc;
X`09if (*beg++ == '\n')
X`09  break;
X      `7D
X      b`5Bcc-1`5D = '\0';
X      printf("%s\n",b);
X      b`5Bcc-1`5D = '\n';
X#else
X      while (beg < buflim)
X`09`7B
X`09  ++cc;
X`09  c = *beg++;
X`09  putchar(c);
X`09  if (c == '\n')
X`09    break;
X`09`7D
X#endif
X      if (ferror(stdout))
X`09`7B
X`09  error("output error", errno);
X`09  err = 1;
X`09`7D
X    `7D
X
X  if (out_line)
X    nlscan(beg);
X  else
X    buflast = beg;
X  bufgap = 0;
X
X  return cc;
X`7D
X
X/* Print pending bytes of last trailing context prior to LIM. */
Xstatic void
XDEFUN(prpending, (lim), register char *lim)
X`7B
X  while (buflast < lim && bufpending)
X    `7B
X      --bufpending;
X      prline(buflast, '-');
X    `7D
X`7D
X
X/* Print the lines between BEG and LIM.  Deal with context crap.
X   Return the count of lines between BEG and LIM. */
Xstatic int
XDEFUN(prtext, (beg, lim), char *beg AND char *lim)
X`7B
X  static int used;
X  register char *p;
X  int i, n;
X
X  prpending(beg);
X
X  p = beg;
X  for (i = 0; i < out_before; ++i)
X    if (p > buflast)
X      do
X`09--p;
X      while (p > buflast && p`5B-1`5D != '\n');
X
X  if ((out_before `7C`7C out_after) && used && (p > buflast `7C`7C bufgap))
X    puts("--");
X
X  while (p < beg)
X    p += prline(p, '-');
X
X  n = 0;
X  while (p < lim)
X    `7B
X      ++n;
X      p += prline(p, ':');
X    `7D
X
X  bufpending = out_after;
X  used = 1;
X
X  return n;
X`7D
X
X/* Fill the user-visible portion of the buffer, returning a byte count. */
Xstatic int
Xfillbuf()
X`7B
X  register char *b, *d, *l;
X  int i, cc;
X  size_t discard, save;
X
X  prpending(buflim);
X
X  b = buflim;
X  for (i = 0; i < out_before; ++i)
X    if (b > buflast)
X      do
X`09--b;
X      while (b > buflast && b`5B-1`5D != '\n');
X
X  if (buflast < b)
X    bufgap = 1;
X  if (out_line)
X    nlscan(b);
X
X  discard = b - buf;
X  save = buflim - b;
X
X  if (b > buf)
X    `7B
X      d = buf;
X      l = buf + bufcc;
X      while (b < l)
X`09*d++ = *b++;
X    `7D
X
X  bufcc -= discard;
X  buftotalcc += discard;
X
X  do
X    `7B
X      if (!bufeof)
X`09`7B
X`09  if (bufcc > bufalloc / 2)
X`09    buf = xrealloc(buf, bufalloc *= 2);
X`09  cc = read(bufdesc, buf + bufcc, bufalloc - bufcc);
X`09  if (cc < 0)
X`09    `7B
X`09      error(buffile, errno);
X`09      bufeof = 1;
X`09    `7D
X`09  else
X`09    `7B
X`09      bufeof = !cc;
X`09      bufcc += cc;
X`09    `7D
X`09`7D
X      bufbeg = buf + save;
X      for (l = buf + bufcc; l > bufbeg && l`5B-1`5D != '\n'; --l)
X`09;
X      buflim = l;
X      buflast = buf;
X    `7D
X  while (!bufeof && bufbeg == buflim);
X
X  if (bufeof)
X    buflim = buf + bufcc;
X
X  return buflim - bufbeg;
X`7D
X
X/* One-time initialization. */
Xstatic void
Xinitbuf()
X`7B
X  bufalloc = 8192;
X  buf = xmalloc(bufalloc);
X`7D
X
X/* Reset the buffer for a new file. */
Xstatic void
XDEFUN(resetbuf, (desc, file), int desc AND const char *file)
X`7B
X  bufbeg = buf;
X  buflim = buf;
X  bufcc = 0;
X  buftotalcc = 0;
X  buflast = buf;
X  bufgap = 0;
X  buftotalnl = 0;
X  bufpending = 0;
X  bufdesc = desc;
X  bufeof = 0;
X  buffile = file;
X`7D
X
X/* Scan the user-visible portion of the buffer, calling prtext() for
X   matching lines (or between matching lines if OUT_INVERT is true).
X   Return a count of lines printed. */
Xstatic int
Xgrepbuf()
X`7B
X  int total;
X  register char *p, *b, *l;
X
X  total = 0;
X  p = bufbeg;
X  while (b = execute(p, buflim - p))
X    `7B
X      if (b == buflim && (b > bufbeg && b`5B-1`5D == '\n' `7C`7C b == bufbeg
V))
X`09break;
X      while (b > bufbeg && b`5B-1`5D != '\n')
X`09--b;
X      l = b + 1;
X      while (l < buflim && l`5B-1`5D != '\n')
X`09++l;
X      if (!out_invert)
X`09total += prtext(b, l);
X      else if (p < b)
X`09total += prtext(p, b);
X      p = l;
X    `7D
X  if (out_invert && p < buflim)
X    total += prtext(p, buflim);
X  return total;
X`7D
X
X/* Scan the given file, returning a count of lines printed. */
Xstatic int
XDEFUN(grep, (desc, file), int desc AND const char *file)
X`7B
X  int total;
X
X  total = 0;
X  resetbuf(desc, file);
X  while (fillbuf())
X    total += grepbuf();
X  return total;
X`7D
X
Xstatic const char version`5B`5D = "GNU fgrep, version 1.1";
X
X#define USAGE \
X  "usage: %s `5B-`5B`5BAB`5D `5D<num>`5D `5B-`5BCVchilnsvwx`5D`5D `5B-`5Bef`
V5D`5D <expr> `5B<files...>`5D\n"
X
Xstatic void
Xusage()
X`7B
X  fprintf(stderr, USAGE, prog);
X#ifdef VMS
X  exit(SS$_ABORT);
X#else
X  exit(2);
X#endif
X`7D
X
Xint
XDEFUN(main, (argc, argv), int argc AND char *argv`5B`5D)
X`7B
X  char *keys;
X  size_t keycc, keyalloc;
X  int count_matches, no_filenames, list_files;
X  int opt, cc, desc, count, status;
X  FILE *fp;
X
X#ifdef VMS
X  if (!shell$is_shell())
X      shell_mung(&argc,&argv,2,"A-B-e+-f+");
X#endif
X
X  prog = argv`5B0`5D;
X  if (prog && strrchr(prog, '/'))
X#ifdef VMS
X   (char *) prog = strrchr(prog, '/') + 1;
X#else
X    prog = strrchr(prog, '/') + 1;
X#endif
X
X  keys = NULL;
X  count_matches = 0;
X  no_filenames = 0;
X  list_files = 0;
X
X  while ((opt = getopt(argc, argv, "0123456789A:B:CVbce:f:hilnsvwxy")) != EO
VF)
X    switch (opt)
X      `7B
X      case '0':
X      case '1':
X      case '2':
X      case '3':
X      case '4':
X      case '5':
X      case '6':
X      case '7':
X      case '8':
X      case '9':
X`09out_before = 10 * out_before + opt - '0';
X`09out_after = 10 * out_after + opt - '0';
X`09break;
X      case 'A':
X`09out_after = atoi(optarg);
X`09if (out_after < 0)
X`09  usage();
X`09break;
X      case 'B':
X`09out_before = atoi(optarg);
X`09if (out_before < 0)
X`09  usage();
X`09break;
X      case 'C':
X`09out_before = out_after = 2;
X`09break;
X      case 'V':
X`09fprintf(stderr, "%s\n", version);
+-+-+-+-+-+-+-+-  END  OF PART 1 +-+-+-+-+-+-+-+-
