/*************************************************************************\ ** 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 #include #include #include #include #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 */ main(argc,argv) int argc; /* argument count */ char **argv; /* argument vector */ { ddb inddb; /* input ddb */ /*********** 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. ** \**************************************************************/ char *swtxt[NSW]; /* -- names */ int swval[NSW]; /* -- values */ char *defcmd; /* default specification */ long flags; /* flags passed to/from CMDLIN.SYS */ /************* 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 */ clear(inddb); /* clear input ddb */ cmloc(&inddb); /* locate CMDLIN.SYS */ strpack(snames,swtxt,NSW); /* pack names into 1 string */ /* init switch table */ sw_tbl.swcount = NSW; /* 1 switch defined */ cmdef(&sw_tbl,swtyp,swoff,swon,snames); flags = (_op_prt|_op_err); /* print & abort on error */ /* 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; next[0] = -1; for(i = 0, j = -1; i < len_p; i++, j++, next[i] = (p[i] == p[j]) ? next[j] : j) while((j >= 0) && (p[i] != p[j])) j = next[j]; } .