/*************************************************************************\
** GREP - Limited implementation of the unix grep utility. **
** Uses CMDLIN.SYS for wildcard specification. [msm] 1/2/91 **
** **
** Copyright (c) 1991 - Morton & Pitalo, Inc. **
** All Rights Reserved. **
** **
** This program was written to try a simplistic implementation of **
** the unix grep utility and to play with CMDLIN.SYS and **
** redirection on the command line. There are some obvious **
** limitations due to the fact that it is running under AMOS and **
** not UNIX but that's life. The search routine currently uses a **
** variation of the Knuth, Morris, Pratt algorithm to help speed **
** up search times. Although this speeds things up a bit there are **
** variations that would vastly increase search speed. Among the **
** most obvious would be to read the file to be searched into a **
** "large" memory buffer and then do the search within the buffer. **
** This would take advantage of the smart controllers and DMA **
** control to load the file faster rather than grabing one block **
** at a time. Allocate as large a buffer as is available from the **
** heap and then do an fread() to load the buffer as needed. In **
** addition there are faster searching algorithms. For reference **
** of this algorithm as well as some faster ones check out **
** Sedgewicks book "Algorithms" which is an excellent source for **
** good algorithms to speed up life in general. As for the code it's a **
** mess, but thats due alot to the cumbersome things you have to go **
** through for the CMDLIN.SYS interface. **
** **
** Written By: Michael Mc Murdie, Jan. 4, 1990 **
** Any questions send e-mail to weng/am **
** **
** Also Note: A lot of the cmdlin interface stuff was lifted from the **
** Alpha-Micro Technical Journal: Vol. 12, No. 3, So if it looks funny **
** it's their fault. **
** **
** **
\*************************************************************************/
version "1.0(100),-1,0,PH$REE!PH$REU";
#include <stdio.h>
#include <cmdlin.h>
#include <string.h>
#include <cdefs.c>
#include <ctype.h>
#include "defs.h" /* my standard definitions */
#define NSW 2 /* number of switches */
/**************** GLOBAL VARIABLES **********************/
char line_buf[256]; /* input line buffer */
char pattern[81]; /* pattern to search for */
int next[81]; /* next array for searching algorithm */
/*********** switch data ************/
short swtyp[NSW]; /* -- types */
int swoff[NSW]; /* -- off values */
int swon[NSW]; /* -- on values */
char snames[50]; /* concatenated names of cmdef */
swdef sw_tbl; /* switch table */
/**************************************************************\
** NOTE: in order for the switches to work, the sw_tbl MUST **
** follow the switch types, off settings, on settings and the **
** name string. **
\**************************************************************/
/************* general variables ****************/
char file_name[30]; /* current file being searched */
char *ch_pos; /* character pointer for ofile */
short new_file; /* true if nothing output from this file */
FILE *fp_in; /* input file pointer */
int ptrn_len; /* pattern length */
int chk_pos; /* position returned */
int line_cnt; /* line count value */
/* initialize the switch types */
swtyp[0] = 0; /* switch type */
swoff[0] = 0; /* Off values */
swon[0] = 1; /* Switch is simply On/Off */
swtxt[0] = "LINE"; /* include line numbering */
swtyp[1] = 0; /* switch type */
swoff[1] = 0; /* Off values */
swon[1] = 1; /* Switch is simply On/Off */
swtxt[1] = "NAME"; /* only output file name with matches */
defcmd = "=*.*"; /* default spec. Note "=" sign in front */
/* of spec to show it is input */
/* check command line */
if (argc != 3){ /* give usage info. */
BRIGHT;
typecr("Usage: Grep pattern filespec/switches");
DIM;
typecr("\nThe pattern can only be a single word and the");
typecr("filespec can contain any of the standard CMDLIN");
typecr("wildcard or @file parameters. In addition, output");
typecr("can be redirected via the '>' notation after the");
typecr("filespec/switches. Available switches are as follows:");
BRIGHT;
typecr(" /LINE to include line number on matched lines.");
typecr(" /NAME to only output the filename of those files that");
typecr(" have matches.");
typecr("\nExample: grep find_proc() *.c/n > proc.lst");
DIM;
typecr("will search all files that have the extension .C for the");
typecr("text \"find_proc()\". All matching files will be listed in");
typecr("the file PROC.LST");
BRIGHT;
exit(1);
}
DIM;
type("String to search for:");
BRIGHT;
typecr(strcpy(pattern,argv[1]));
DIM;
type(" Files to search:");
BRIGHT;
typecr(cmdlin = argv[2]); /* reference the filespec and print */
ptrn_len = strlen(pattern); /* find the pattern length */
init_next(pattern,ptrn_len); /* initialize the next array */
/* initialize CMDLIN.SYS */
if (cmini(&sw_tbl,swval,defcmd,&flags)) exit(1);
/* check for output file spec'd */
if (flags & _in_ofp){
typecr("Error: Do NOT use an output specification.");
typecr(" Use the redirection operator '>' instead.");
exit(1);
}
/* get files specified */
CUROFF;
while(!cmnxt(&inddb,nil,&flags) && !(flags & _nx_end)){
if (ctrlc()) break; /* check for ^C */
/**********************************************\
** NOTE: the cmqry() call has been commented **
** out because it outputs a CR/LF after every **
** call, whether query was requested or not. **
** Since this messes up the screen display it **
** is NOT used. **
\**********************************************/
/* if (!cmqry()) continue; /* check for /Q */
/* skip random files */
if (inddb.altwrk.strwrk.lsz == 65535) continue;
/* get this file name */
ch_pos = file_name;
ofile(&inddb,_ot_mem,&ch_pos);
*ch_pos = NULL;
DIM; /* print the file name on screen */
type("Searching File:");
BRIGHT;
type(file_name);
CLR_EOL;
COL_1;
new_file = TRUE;
/* open the file for input */
if ((fp_in = fopen(file_name,"r")) == nil){
DIM;
type("Unable to open file:");
BRIGHT;
typecr(file_name);
continue;
}
for(line_cnt = 1; TRUE; line_cnt++){
if (ctrlc()){
jobidx()->jobsts |= _j_ccc;
break;
}
fgets(line_buf,255,fp_in);
if (feof(fp_in)) break;
if ((chk_pos = search(line_buf,ptrn_len)) != -1){
if (new_file){
printf("\n%s\n",file_name);
new_file = FALSE;
if (swval[1]) break;
}
if (swval[0]) printf("%d:",line_cnt);
printf("%s",line_buf);
}
}
fclose(fp_in); /* close file */
} /* end of while loop */
crlf();
CURON;
} /* end of main */
/********************************************************************\
** search the string pointed to by a and return the position of the **
** pattern within the string. If the pattern is not found return -1 **
\********************************************************************/
int search(a,len_p)
char *a; /* pointers to strings to check */
int len_p; /* pattern length */
{
int i, j, N;
N = strlen(a); /* length of string */
for(i = 0, j = 0; j < len_p && i < N; i++, j++)
while ((j >= 0) && (toupper(a[i]) != pattern[j])) j = next[j];
if (j == len_p) return(i - len_p); else return(-1);
}
/* initialize the "next" array for pattern searching */
int init_next(p,len_p)
char *p; /* pointer to pattern */
int len_p; /* length of pattern */
{
int i, j;