[comp.sources.amiga] v02i040: unix-utils - UNIX

page@swan.ulowell.edu (Bob Page) (11/03/88)

Submitted-by: brant@uf.msc.umn.edu (Gary Brant)
Posting-number: Volume 2, Issue 40
Archive-name: unix/utils.1

Head, tail, tee and wc are similar to *NIX utilities of the same name.
detab and entab remove and instert tabs respectively in source files.
trunc removes trailing white space, inserts left margins,
deletes/converts CR's in source files, etc.

[Although the sources are copyrighted, they are freely
redistributable, as mentioned in the readme file.   ..Bob]

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:    Shell Archiver
#	Run the following text with /bin/sh to create:
#	detab.c
#	entab.c
#	head.c
#	tail.c
#	tee.c
#	trunc.c
#	wc.c
#	readme
# This archive created: Wed Nov  2 15:40:18 1988
cat << \SHAR_EOF > detab.c
/* detab.c - expand tabs to spaces in a file.  If a single tabstop	*
 *	is given, tabs are tabstop spaces apart, otherwise tabstops	*
 *	are at <tab1>, <tab2>,..., <tabn>.  If no file is specified,	*
 *	standard input is read and standard output written.		*
 *									*
 * detab [-<tab1> -<tab2>... -<tabn>] [filename... ]			*
 *									*
 * detab (C) 1988 by Gary L. Brant					*
 *									*
 * :ts=8								*/

#define MAXLINE 1000
#include <stdio.h>
char tabarray[MAXLINE];

main (argc, argv)	/* remove trailing blanks and tabs and */
			/* expand tabs in source lines */
int argc;
char *argv[];
{
   int i = 0, j, k, l, ntabs = 0, tabstop = 8;
   int argtabs[99];
   char ch, *pch;
   FILE *ifile, *fopen ();

   /* decode tabstop arguments */
   while ((++i < argc) && (argv[i][0] == '-')) {
      j = 1;
      tabstop = 0;
      while ((ch = argv[i][j++]) != '\0') {
	 if (ch >= '0' && ch <= '9') {
	    tabstop *= 10;
	    tabstop += ch - '0';
	 } else {
	    fputs ("bad args\n", stderr);
	    exit (20);
	 }
      }
      argtabs[ntabs++] = tabstop;
   }

   /* fill tabarray with \1 for each tabstop position */
   for (k = 0; k < MAXLINE; k++)
      tabarray[k] = '\0';
   if (ntabs > 1)
      for (k = 0; k < ntabs; k++)
	 if ((l = argtabs[k]-1) < MAXLINE)
	    tabarray[l] = '\001';
	 else {
	    fputs ("bad tab specification\n", stderr);
	    exit (20);
	 }
   else if ((tabstop > 0) && (tabstop < MAXLINE))
      for (k = tabstop; k < MAXLINE; k += tabstop)
	 tabarray[k] = '\001';
   else {
      fputs ("bad tab specification\n", stderr);
      exit (20);
   }

   /* remaining arguments should be file names - detab them */
   if (i < argc) {
      while (i < argc)
	 if ((ifile = fopen ((pch = argv[i++]), "r")) == NULL) {
	    fputs ("detab: cant open ", stderr);
	    fputs (pch, stderr);
	    putc ('\n', stderr);
	    exit (20);
	 } else
	    detab (ifile);
   } else
      detab (stdin);
}


/* detab - remove the tabs from one file */

detab (ifile)
FILE *ifile;
{
   int n;
   char inline[MAXLINE], outline[MAXLINE], *fgets ();

   while ((fgets (inline, MAXLINE, ifile)) != NULL) {
      n = strlen (inline);
      while (--n >= 0)			/* back over white space */
	 if (inline[n] != ' ' && inline[n] != '\t' &&
	    inline[n] != '\n') break;
      inline[n+1] = '\0';
      expand (inline, outline, MAXLINE);
      puts (outline);
   }
}


/* expand - expand a line */

expand (in, out, lim)
char in[], out[];
int  lim;
{
   register int i, j;
   register char ch;

   i = j = 0;
   while (((ch = in[i++]) != '\0') && (j < lim)) {
      if (ch == '\t') {
	 register int k;
	 register char tc;

	 k = j;
	 out[j++] = ' ';
	 while ((j < lim) && ((tc = tabarray[j]) == '\0'))
	    out[j++] = ' ';
	 if (tc == '\0') {
	    j = k;
	    out[j++] = ch;
	 }
      } else
	 out[j++] = ch;
   }
   out[j] = ch;
}


/* wb_parse is included here only to reduce the size of the executable */

void
_wb_parse ()
{
}
SHAR_EOF
cat << \SHAR_EOF > entab.c
/* entab.c - compress spaces to tabs in a file.  If a single tabstop	*
 *	is given, tabs are tabstop spaces apart, otherwise tabstops	*
 *	are at <tab1>, <tab2>,..., <tabn>.  If no file is specified,	*
 *	standard input is read and standard output written.		*
 *									*
 * entab [-<tab1> -<tab2> -<tabn>] [filename... ]			*
 *									*
 * entab (C) 1988 by Gary L. Brant					*
 *									*
 * :ts=8								*/

#define MAXLINE 1000
#include <stdio.h>
char tabarray[MAXLINE];

main (argc, argv)	/* remove trailing blanks and tabs and */
			/* compress blanks in source lines */
int argc;
char *argv[];
{
   int i = 0, j, k, l, ntabs = 0, tabstop = 8;
   int argtabs[99];
   char ch, *pch;
   FILE *ifile, *fopen ();

   /* decode tabstop arguments */
   while ((++i < argc) && (argv[i][0] == '-')) {
      j = 1;
      tabstop = 0;
      while ((ch = argv[i][j++]) != '\0') {
	 if (ch >= '0' && ch <= '9') {
	    tabstop *= 10;
	    tabstop += ch - '0';
	 } else {
	    fputs ("bad args\n", stderr);
	    exit (20);
	 }
      }
      argtabs[ntabs++] = tabstop;
   }

   /* fill tabarray with \1 at each tabstop position */
   for (k = 0; k < MAXLINE; k++)
      tabarray[k] = '\0';
   if (ntabs > 1)
      for (k = 0; k < ntabs; k++)
	 if ((l = argtabs[k]-1) < MAXLINE)
	    tabarray[l] = '\001';
	 else {
	    fputs ("bad tab specification\n", stderr);
	    exit (20);
	 }
   else if ((tabstop > 0) && (tabstop < MAXLINE))
      for (k = tabstop; k < MAXLINE; k += tabstop)
	 tabarray[k] = '\001';
   else {
      fputs ("bad tab specification\n", stderr);
      exit (20);
   }

   /* remaining arguments should be file names - entab them */
   if (i < argc)
      while (i < argc)
	 if ((ifile = fopen ((pch = argv[i++]), "r")) == NULL) {
	    fputs ("entab: cant open ", stderr);
	    fputs (pch, stderr);
	    putc ('\n', stderr);
	    exit (20);
	 } else
	    entab (ifile);
   else
      entab (stdin);
}


/* entab - insert tabs into one file */

entab (ifile)
FILE *ifile;
{
   int n;
   char inline[MAXLINE], outline[MAXLINE], *fgets ();

   while ((fgets (inline, MAXLINE, ifile)) != NULL) {
      n = strlen (inline);
      while (--n >= 0)			/* back over white space */
	 if (inline[n] != ' ' && inline[n] != '\t' && inline[n] != '\n')
	    break;
      inline[n+1] = '\0';
      compress (inline, outline, MAXLINE);
      puts (outline);
   }
}


/* compress - compress one line, replacing strings of blanks with tabs	*
 * to tab stops specified on command line or default			*/

compress (in, out, lim)
char in[], out[];
int  lim;
{
   register int i = 0, j = 0;
   register char ch;

   while (((ch = in[i++]) != '\0') && (i < lim)) {
      if (ch == ' ') {
	 register int k = i, tc;
	 while (((tc = tabarray[k]) == '\0') && (in[k] == ' ') && (k < lim))
	    k++;
	 if ((tc == '\001') && (k > i))
	    out[j++] = '\t';
	 else			/* avoid running through this again next trip */
	    while (i++ <= k)
	       out[j++] = ch;
	 i = k;
      } else if (ch == '\042' || ch == '\047') {
	 register int tc;		/* avoid tabbing quoted strings */
	 out[j++] = ch;
	 while (((tc = in[i++]) != ch) && (i < lim)) {
	    if (tc == '\134') { 	/* possible protected quote */
	       out[j++] = tc;
	       tc = in[i++];
	       if (i == lim) break;
	    }
	    out[j++] = tc;
	 }
	 out[j++] = ch;
      } else
	 out[j++] = ch;
   }
   out[j] = ch;
}


void
_wb_parse ()
{
}
SHAR_EOF
cat << \SHAR_EOF > head.c
/* head.c - print the first few lines in a file.  If count is specified,*
 *	that many lines are printed instead of the default value of	*
 *	ten lines.  If no files are specified, head reads standard	*
 *	input.								*
 *									*
 * head [-<count>] [<file> ...] 					*
 *									*
 * head (C) 1988 by Gary L. Brant					*
 *									*
 * :ts=8								*/

#include <stdio.h>
#define   MAXLINE   1000

void fputs ();
int head = 0;

main (argc, argv)	/* list 1st n lines of a file */
int  argc;
char *argv[];
{
   FILE *input, *fopen ();
   void fclose ();
   int default_lines = 10;	/* default number of lines to list */
   int i = 0, j, maxlines;
   char ch;

   maxlines = default_lines;
   while (++i < argc) {
      if (argv [i][0] == '-') { 	/* remember to bump i in loop */
	 maxlines = 0;	/* remember to set maxlines to 0 1st */
	 for (j = 1; (ch = argv[i][j]) != '\0'; j++)
	    if (ch >= '0' && ch <= '9') {
	       maxlines *= 10;
	       maxlines += ch - '0';
	    } else {
	       maxlines = default_lines;
	       break;
	    }
	 default_lines = maxlines;
      } else {
	 ++head;
	 if ((input = fopen (argv[i], "r")) == NULL) {
	    fputs ("head: can't open ", stderr);
	    fputs (argv[i], stderr);
	    putc ('\n', stderr);
	    break;
	 } else {
	    list (input, argv[i], maxlines);
	    fclose (input);
	 }
      }
   }
   if (!head)
      list (stdin, "", maxlines);
}


/* list head of a file */

list (fp, fn, maxlines)
FILE *fp;
char *fn;
int maxlines;
{
   int n;
   int i = 0;
   char line[MAXLINE];
   char *fgets ();

   while ((i < maxlines) && (fgets (line, MAXLINE, fp)) != NULL) {
      if (i++ == 0)
	 heading (fn);
      fputs (line, stdout);
   }
}


/* heading - print a short heading identifying file */

heading (filename)
char *filename;
{
   if (head) {
      fputs ("==> ", stdout);
      fputs (filename, stdout);
      fputs (" <==\n", stdout);
   }
}


_wb_parse ()
{
}
SHAR_EOF
cat << \SHAR_EOF > tail.c
/* tail.c - print the last few lines in a file.  If count is specified, *
 *	that many lines are printed instead of the default value of	*
 *	ten lines.  If no files are specified, head reads standard	*
 *	input.								*
 *									*
 * tail [-<count>] [<file> ...] 					*
 *									*
 * tail (C) 1988 by Gary L. Brant					*
 *									*
 * :ts=8								*/

#include <stdio.h>
#define   MAXLINE   1000
void fputs ();
int default_lines = 10; /* default number of lines to list */
int head = 0;

main (argc, argv)	/* list 1st n lines of a file */
int  argc;
char *argv[];
{
   FILE *input, *fopen ();
   void fclose ();
   int i = 0, j, maxlines;
   char ch;

   maxlines = default_lines;
   while (++i < argc) {
      if (argv [i][0] == '-') { 	/* process line count argument */
	 maxlines = convert (argv[i]);
	 default_lines = maxlines;
	 if (maxlines > 4096) {
	    fputs ("give me a break!!  n <= 4096!\n", stderr);
	    exit (20);
	 }
      } else if (argv [i][0] == '+') {
	 maxlines = -convert (argv[i]);
	 default_lines = maxlines;
      } else {
	 ++head;
	 if ((input = fopen (argv[i], "r")) == NULL) {
	    fputs ("tail: can't open ", stderr);
	    fputs (argv[i], stderr);
	    putc ('\n', stderr);
	    break;
	 } else {
	    list (input, argv[i], maxlines);
	    fclose (input);
	 }
      }
   }
   if (!head)
      list (stdin, "", maxlines);
}


list (fp, fn, maxlines) 	/* list tail of a file */
FILE *fp;
char *fn;
int maxlines;
{
   int	i = 0, n, fseek ();
   char line[MAXLINE];
   long cur_pos = 0L, line_pos[4096];
   char *c, *fgets ();

   if (maxlines < 0) {		/* +n, head relative list */
      while (maxlines++ < 0 && (c = fgets (line, MAXLINE, fp)) != NULL);
      if (c != NULL) {
	 heading (fn);
	 while ((fgets (line, MAXLINE, fp)) != NULL)
	    fputs (line, stdout);
      }
   } else {			/* -n, tail relative list */
      for (n = 0; n < maxlines; n++)
	 line_pos[n] = 0L;
      while ((fgets (line, MAXLINE, fp)) != NULL) {
	 n = strlen (line);
	 line_pos[i++] = cur_pos;
	 cur_pos += n;
	 if (i == maxlines)
	    i = 0;
      }
      if (cur_pos == 0L)
	 return;
      fseek (fp, line_pos[i], 0);
      heading (fn);
      while ((fgets (line, MAXLINE, fp)) != NULL)
	 fputs (line, stdout);
   }
}


heading (filename)
char *filename;
{
   if (head) {
      fputs ("==> ", stdout);
      fputs (filename, stdout);
      fputs (" <==\n", stdout);
   }
}


convert (string)
char string[];
{
   register int maxlines = 0, j;
   register char ch;

   for (j = 1; (ch = string[j]) != '\0'; j++)
   if (ch >= '0' && ch <= '9') {
      maxlines *= 10;
      maxlines += ch - '0';
   } else {
      maxlines = default_lines;
      break;
   }
   return (maxlines);
}


void _wb_parse ()
{
}
SHAR_EOF
cat << \SHAR_EOF > tee.c
/* tee.c - copy standard input to standard output and one other file.	*
 *	This is useful for splitting (tapping) the pipe.  Presumes you	*
 *	are using a shell program which can pipe the output from one	*
 *	program into the input of another or some other pipe device,	*
 *	but also can be used to make 2 copies of a file.		*
 *									*
 * tee <file1 >file2 file3						*
 * prog1 file1 | tee file3 | prog2 ...					*
 *									*
 * tee (C) 1988 by Gary L. Brant					*
 *									*
 * :ts=8								*/

#include <stdio.h>
#include <fcntl.h>
#define MAXLINE 256
#define ERROR	-1

void copy ();
int close (), open (), read (), write ();
int err, out2;			/* file handles */

main (argc, argv)
int  argc;
char *argv[];
{

   err = fileno (stderr);
   if (argc != 2) {
      write (err, "usage: tee <file1 >file2 file3\n", 31);
      exit (20);
   }

   /* Manx documentation (lib.35) claims that if O_TRUNC is used, */
   /* then O_CREAT is not needed; HOG_WASH; open() first deletes */
   /* the file & then complains ENOENT (File does not exist!!! */

   if ((out2 = open (argv[1], O_WRONLY | O_TRUNC | O_CREAT)) == ERROR) {
      write (err, "tee: cant open ", 15);
      write (err, argv[1], strlen (argv[1]));
      write (err, "\n", 1);
      exit (20);
   }

   copy (out2);
   close (out2);
}


/* copy stdin to stdout and one other file */

void copy (out2)
int out2;
{
   int p, in, out1;
   char line[MAXLINE];

   in = fileno (stdin);
   out1 = fileno (stdout);
   while ((p = read (in, line, MAXLINE)) > 0) {
      write (out1, line, p);
      write (out2, line, p);
   }
}


_wb_parse ()
{
}
SHAR_EOF
cat << \SHAR_EOF > trunc.c
/* trunc.c - Remove trailing white space from a file.  In addition	*
 *	perform some simple formatting.  Options include lm (left	*
 *	margin), lc (leftmost column to copy), rc (rightmost column	*
 *	to copy), mc (convert CR's to LF's), and md (delete CR's).      *
 *									*
 * trunc [-<mc>|<md>][-lm n][-lc n][-rc n] [<file> ...] 		*
 *									*
 * trunc (C) 1988 by Gary L. Brant					*
 *									*
 * :ts=8								*/

#define MAXLINE 1000
#include <stdio.h>
int lc = 0,		/* leftmost column to copy */
    lm = 0,		/* left margin to insert */
    rc = 0;		/* rightmost column to copy */
int m  = 0;		/* conversion flag for ^M's */
int flag = 0;		/* indicates CR seen and conversion mode on */
int head = 0;
void fputs (), putc ();

main (argc, argv)	/*remove trailing blanks and tabs from source lines */
int argc;
char *argv[];

{
   int i = 0, j;
   char ch, *pch;
   FILE *ifile, *fopen ();

   while ((++i < argc) && (argv[i][0] == '-')) {
      j = 1;
      switch (ch = argv[i][j++]) {
      case 'l': if ((ch = argv[i][j]) == 'c' && i < argc - 1) {
		   lc = convert (argv[++i]);
		   if (lc > 0)
		      lc--;
		} else if (ch = 'm' && i < argc - 1)
		   lm = convert (argv[++i]);
		else
		   badarg ();
		break;
      case 'm': if ((ch = argv[i][j]) == 'd')
		   m = 1;
		else if (ch == 'c')
		   m = 2;
		break;
      case 'r': if ((ch = argv[i][j]) == 'c' && i < argc - 1)
		   rc = convert (argv[++i]);
		else
		   badarg ();
		break;
      default:	badarg ();
		break;
      }
   }
   if (rc == 0) 				rc = MAXLINE - 1 - lm;
   if (lc > rc || rc - lc + lm >= MAXLINE)	badarg ();

   while (i < argc) {
      ++head;
      if ((ifile = fopen ((pch = argv[i++]), "r")) == NULL) {
	 fputs ("trunc: cant open ", stderr);
	 fputs (pch, stderr);
	 putc ('\n', stderr);
	 exit (20);
      } else
	 copy (ifile);
   }
   if (head == 0)
      copy (stdin);
}


/* copy - copy file, remove trailing white space and format as we go	*/
/* inspired by example in: K & R, P. 61 				*/

copy (ifile)
FILE *ifile;
{
   int irc, n = 0;
   char line[MAXLINE];

   irc = rc + lm - lc;
   while (n < lm)
      line[n++] = ' ';
   while ((n = getline (ifile, &line[lm], MAXLINE-1-lm)) > 0) {
      register int in = (lm + n < irc) ? lm + n : irc;
      while (in-- >= lm)
	 if (line[in] != ' ' && line[in] != '\t' && line[in] != '\n')
	    break;
      if (in < lm) {
	 putc ('\n', stdout);
	 if (flag) {
	    flag = 0;
	    putc ('\n', stdout);
	 }
      } else {
	 if (flag != 0) {
	    line[++in] = '\n';
	    flag = 0;
	 }
	 line[++in] = '\n';
	 line[++in] = '\0';
	 fputs (line, stdout);
      }
   }
}


/* get line into s, return length
 * inspired by example in: K & R, P. 67 	*/

getline (ifile, s, lim)
FILE *ifile;
char s[];
int  lim;
{
   register int c, i, j;

   i = 0;	j = lc; 	/* leftmost columns to ignore */
   while (i < lim && (c = getc (ifile)) != EOF && c != '\n') {
      if (c == '\r') {
	 if (m == 1)
	    continue;
	 else if (m == 2) {
	    flag = 1;
	    continue;
	 }
      }
      if (j-- <= 0)
	 s[i++] = c;
   }
   if (c  == '\n')
      s[i++] = c;
   s[i] = '\0';
   return (i);
}


/* convert - convert numeric command-line arguments to binary	*
 * returns -1 if non-numeric data encountered			*/

convert (argv)
char *argv;
{
   register long i = 0;
   register char ch;
   register int j=0;

   while ((ch = argv[j++]) != '\0')
      if (ch >= '0' && ch <= '9') {
	 i *= 10;
	 i += ch - '0';
      } else
	 return (-1);
   return (i);
}


/* badarg - complain about bad argument */

badarg ()
{
	 fputs ("bad args\n", stderr);
	 exit (20);
}


_wb_parse ()
{
}
SHAR_EOF
cat << \SHAR_EOF > wc.c
/* wc.c - count the number of lines, words, and characters in a file.	*
 *									*
 * wc [<file> ...]							*
 *									*
 * wc (C) 1988 by Gary L. Brant 					*
 *									*
 * :ts=8								*/

#include <stdio.h>
#define 	FALSE		0
#define 	TRUE		1
#define 	COUNT_LINES	4
#define 	COUNT_WORDS	2
#define 	COUNT_CHARS	1
int cur_flag, def_flag = COUNT_LINES | COUNT_WORDS | COUNT_CHARS;
int head;
long  lines, words, chars;
long  tlines=0, twords=0, tchars=0;
char string[] = "         ";

main (argc, argv)	/* count lines, words, chars in input */
int  argc;
char *argv[];
{
   register int i = 0, j;
   register char ch;
   FILE *input, *fopen ();
   void fclose ();

   cur_flag = def_flag;
   while (++i < argc) {
      if (argv [i][0] == '-') { 	/* remember to bump i in loop */
	 def_flag = cur_flag;
	 cur_flag = 0;
	 for (j = 1; (ch = argv[i][j]) != '\0'; j++)
	    switch (ch) {
	    case 'l':
		cur_flag |= COUNT_LINES;
		break;
	    case 'w':
		cur_flag |= COUNT_WORDS;
		break;
	    case 'c':
		cur_flag |= COUNT_CHARS;
		break;
	    default:
		cur_flag = def_flag;
	    }
      } else {
	 ++head;
	 if ((input = fopen (argv[i], "r")) == NULL) {
	    fputs ("wc: can't open ", stderr);
	    fputs (argv[i], stderr);
	    putc ('\n', stderr);
	    continue;
	 } else {
	    wc (input, argv[i]);
	    fclose (input);
	 }
      }
   }
   if (!head)
      wc (stdin, "");
   else if ( head > 1)
      print (tlines, twords, tchars, "total");
}


/* count words, etc. in 1 file
 * inspired by example from: K.&R. P. 18	*/

wc (fp, fn)
FILE *fp;
char *fn;
{
   register int in, c;

   in = FALSE;
   lines = words = chars = 0;
   while ((c = getc (fp)) != EOF) {
      ++chars;
      if (c == '\n') {
	 ++lines;
	 in = FALSE;
      } else if (c == ' ' || c == '\t')
	 in = FALSE;
      else if (!in) {
	 in = TRUE;
	 ++words;
      }
   }
   print (lines, words, chars, fn);
   tlines += lines;
   twords += words;
   tchars += chars;
}


/* print - print counts for a file */

print (lines, words, chars, fn)
long lines, words, chars;
char *fn;
{
   if (cur_flag & COUNT_LINES) {
      convert (lines, string);
      fputs (string, stdout);
   }
   if (cur_flag & COUNT_WORDS) {
      convert (words, string);
      fputs (string, stdout);
   }
   if (cur_flag & COUNT_CHARS) {
      convert (chars, string);
      fputs (string, stdout);
   }
   if (head)
      fputs (fn, stdout);
   putc ('\n', stdout);
}


convert (val, string)
register long val;
register char *string;
{
   register int i = 7;

   if (val == 0)
      string[i--] = '0';
   while (val != 0) {
      register long j, k;
      j = val / 10;
      k = val - 10 * j;
      val = j;
      string[i--] = '0' + k;
      if (i < 0)
	 break;
   }
   while (i >= 0)
      string[i--] = ' ';
}


_wb_parse ()
{
}
SHAR_EOF
cat << \SHAR_EOF > readme
Here are some utilities that I have found useful.  head, tail, tee 
and wc are similar to *NIX utilities of the same name.  detab and
entab remove and instert tabs respectively in source files.  trunc
removes trailing white space, inserts left margins, deletes/converts
CR's in source files, etc.  

All of these utilities write to standard output and read from 
standard input if a file name is not provided on the command line.
This is so that each may 'pipe' its output to the input of another.
Note that if someday *real* pipes become available (:-)), tail will 
break due to seeks.

These programs were compiled using the Manx C compiler (v3.6a), but 
conversion to Lattice should be easy; I have tried to keep all of 
the code as straight-forward as possible.

The sources & binaries are freely distributable;  you may do anything
you like with them except sell them for profit as long as you leave
my name in the source and include this notice with the source files.

Have fun.


		 Gary Brant

	US mail: 1355 Eustis St. #1
	         St. Paul, MN 55108

	ARPA:	 brant@uc.msc.umn.edu
SHAR_EOF
#	End of shell archive
exit 0
-- 
Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
Have five nice days.