This is rgrep.c in view mode; [Download] [Up]
/* * Copyright (c) 1995 John E. Davis (davis@space.mit.edu) * All Rights Reserved. */ #include <config.h> #include <stdio.h> #include <slang.h> #include <string.h> #ifdef HAVE_STDLIB_H #include <stdlib.h> #endif /* For isatty */ #ifdef HAVE_UNISTD_H # include <unistd.h> #endif #ifdef msdos #include <io.h> #endif #include "vfile.h" static int Case_Sensitive = 1; static int File_Name_Only; static int Do_Recursive = 0; static int Recursive_Match = 0; static int Highlight = 0; static int Output_Match_Only = 0; static int Count_Matches = 0; static int Line_Numbers = 0; static int Follow_Links = 0; static int Debug_Mode = 0; static char *Match_This_Extension; static int Print_Non_Matching_Lines = 0; #define HON_STR "\033[1m" #define HON_STR_LEN 4 #define HOFF_STR "\033[0m" #define HOFF_STR_LEN 4 void usage(void) { fputs("rgrep (v1.4)\nUsage: rgrep [options..] pattern [files ...]\n\ Options:\n\ -? additional help (use '-?' to avoid shell expansion on some systems)\n\ -c count matches\n\ -h highlight match (ANSI compatable terminal assumed)\n\ -H Output match instead of entire line containing match\n\ -i ignore case\n\ -l list filename only\n\ -n print line number of match\n\ -F follow links\n\ -r recursively scan through directory tree\n\ -N Do NOT perform a recursive search\n\ -R 'pat' like '-r' except that only those files matching 'pat' are checked\n\ -v print only lines that do NOT match the specified pattern\n\ -x 'ext' checks only files with extension given by 'ext'.\n\ -D Print all directories that would be searched. This option is for\n\ debugging purposes only. No file is grepped with this option.\n\ -W'len' lines are 'len' characters long (not newline terminated).\ \n\ 'pattern' is a valid 'ex' type of regular expression. See the man page for ex.\n\ It is best enclosed in single quotes to avoid shell expansion.\n", stderr); exit(1); } void additional_help (void) { char buf[3]; fputs("Supported Regular Expressions:\n\ . match any character except newline\n\ \\d match any digit\n\ \\e match ESC char\n\ * matches zero or more occurences of previous RE\n\ + matches one or more occurences of previous RE\n\ ? matches zero or one occurence of previous RE\n\ ^ matches beginning of line\n\ $ matches end of line\n\ [ ... ] matches any single character between brackets.\n\ For example, [-02468] matches `-' or any even digit.\n\ and [-0-9a-z] matches `-' and any digit between 0 and 9\n\ as well as letters a through z.\n\ \\< Match the beginning of a word.\n\ \\> Match the end of a word.\n\ \\{ ... \\}\n\ \\( ... \\)\n\ \\1, \\2, ..., \\9 matches match specified by nth \\( ... \\) expression.\n\ For example, '\\([ \\t][a-zA-Z]+\\)\\1[ \\t]' matches any\n\ word repeated consecutively.\n", stderr); if (isatty(fileno(stderr)) && isatty(fileno(stdin))) { fputs("\nPress RETURN for examples>", stderr); fgets(buf, 2, stdin); putc('\n', stderr); } fputs ("Examples:\n\ \n\ Look in all files with a 'c' extension in current directory and all its\n\ subdirectories looking for matches of 'int ' at the beginning of a line,\n\ printing the line containing the match with its line number: (two methods)\n\ rgrep -n -R '*.c' '^int ' .\n\ rgrep -n -x c '^int ' .\n\ \n\ Highlight all matches of repeated words in file 'paper.tex':\n\ rgrep -h '\\<\\(silly\\)\\>[ \\t]+\\<\\1\\>' paper.tex\n", stderr); fputs ("\n\ Search through all files EXCEPT .o and .a file below /usr/src/linux looking\n\ for the string 'mouse' without regard to case:\n\ rgrep -i -R '*.[^ao]' mouse /usr/src/linux\n\ \n\ Search a fixed record length FITS file for the keyword EXTNAME:\n\ rgrep -W80 ^EXTNAME file.fits\n\ (Note that the regular expression '^[A-Z]+' will dump all fits headers.)\n", stderr); exit (-1); } static FILE *File_Fp; static VFILE *File_Vp; SLsearch_Type Search_St; static unsigned char *Fixed_Len_Buf; static int Fixed_Len_Mode; static int Fixed_Line_Len; void msg_error(char *str) { fputs(str, stderr); putc('\n', stderr); } void exit_error(char *s) { fprintf(stderr, "rgrep: %s\n", s); exit(1); } void parse_flags(char *f) { char ch; while ((ch = *f++) != 0) { switch (ch) { case 'i': Case_Sensitive = 0; break; case 'l': File_Name_Only = 1; break; case 'r': Do_Recursive = 1; break; case 'N': Do_Recursive = -1; break; case 'v': Print_Non_Matching_Lines = 1; case 'H': Highlight = 1; /* does not cause highlight for this case */ Output_Match_Only = 1; break; case 'h': #ifndef pc_system Highlight = 1; #endif break; case 'c': Count_Matches = 1; break; case 'n': Line_Numbers = 1; break; case 'F': Follow_Links = 1; break; case 'D': Debug_Mode = 1; break; case '?': additional_help (); break; case 'W': Fixed_Line_Len = 0; while (((ch = *f) != 0) && (ch >= '0') && (ch <= '9')) { Fixed_Line_Len = Fixed_Line_Len * 10 + (unsigned char) ch - '0'; f++; } if (Fixed_Line_Len == 0) usage (); Fixed_Len_Buf = (unsigned char *) SLMALLOC (Fixed_Line_Len); if (Fixed_Len_Buf == NULL) { exit_error ("Malloc error."); } Fixed_Len_Mode = 1; break; default: usage (); } } } static SLRegexp_Type reg; static SLRegexp_Type recurse_reg; static unsigned char Recurse_Reg_Pattern_Buffer[256]; static int Must_Match; static int print_file_too; static void do_fwrite (unsigned char *s, int n, int nl) { unsigned char *smax = s + n, ch = 0; #if defined(unix) || defined(VMS) unsigned char ch1; #endif while (s < smax) { ch = *s++; #if defined(unix) || defined(VMS) ch1 = ch & 0x7F; if ((ch1 < ' ') || (ch1 == 0x7F)) { if ((ch != '\n') && (ch != '\t')) { if (ch & 0x80) putc ('~', stdout); putc ('^', stdout); if (ch1 == 0x7F) ch = '?'; else ch = ch1 + '@'; } } #endif putc (ch, stdout); } if (nl && (ch != '\n')) putc ('\n', stdout); } void output_line(unsigned char *s, unsigned int n, unsigned char *p, unsigned char *pmax) { if (Highlight == 0) { do_fwrite(s, n, 1); } else { if (Output_Match_Only == 0) { do_fwrite (s, (int) (p - s), 0); fwrite (HON_STR, 1, HON_STR_LEN, stdout); } do_fwrite (p, (int) (pmax - p), 0); if (Output_Match_Only == 0) { fwrite (HOFF_STR, 1, HOFF_STR_LEN, stdout); do_fwrite (pmax, (int) n - (int) (pmax - s), 1); } else if (*(pmax - 1) != '\n') putc ('\n', stdout); } } static unsigned char *rgrep_gets (unsigned int *n) { unsigned int nread; if (File_Vp != NULL) return (unsigned char *) vgets (File_Vp, n); nread = fread (Fixed_Len_Buf, 1, Fixed_Line_Len, File_Fp); if (nread == 0) return NULL; *n = nread; return Fixed_Len_Buf; } void grep(char *file) { unsigned char *buf, *p, *pmax; unsigned int n; int line = 0, n_matches = 0; while (NULL != (buf = (unsigned char *) rgrep_gets(&n))) { line++; if (reg.min_length > n) { if (Print_Non_Matching_Lines) { p = buf; pmax = p + n; goto match_found; } continue; } if (Must_Match) { if (Search_St.key_len > n) { if (Print_Non_Matching_Lines) { p = buf; pmax = p + n; goto match_found; } continue; } if (NULL == (p = SLsearch (buf, buf + n, &Search_St))) { if (Print_Non_Matching_Lines) { p = buf; pmax = p + n; goto match_found; } continue; } if (reg.osearch) { if (Print_Non_Matching_Lines) continue; pmax = p + Search_St.key_len; goto match_found; } } if (!SLang_regexp_match(buf, (int) n, ®)) { if (Print_Non_Matching_Lines) { p = buf; pmax = p + n; goto match_found; } continue; } p = buf + reg.beg_matches[0]; pmax = p + reg.end_matches[0]; match_found: n_matches++; if (Count_Matches) continue; if (File_Name_Only) { puts(file); return; } if (print_file_too) { fputs(file, stdout); putc(':', stdout); } if (Line_Numbers) { fprintf(stdout, "%d:", line); } output_line(buf, n, p, pmax); } if (n_matches && Count_Matches) { if (print_file_too || File_Name_Only) { fputs(file, stdout); putc(':', stdout); } fprintf(stdout, "%d\n", n_matches); } } #ifdef msdos #include <dir.h> #endif #ifdef unix #include <sys/types.h> #include <sys/stat.h> #ifdef sequent # include <sys/dir.h> # define NEED_D_NAMLEN #else # include <dirent.h> #endif #endif #ifdef msdos #define MAX_PATH_LEN 128 #else #define MAX_PATH_LEN 512 #endif #ifdef msdos typedef struct Dos_DTA_Type { unsigned char undoc[21]; unsigned char attr; unsigned int time; unsigned int date; unsigned char low_size[2]; unsigned char high_size[2]; char name[13]; } DOS_DTA_Type; #endif #ifdef unix # if HAVE_DIRENT_H # include <dirent.h> # define NAMLEN(dirent) strlen((dirent)->d_name) # else # define dirent direct # define NAMLEN(dirent) (dirent)->d_namlen # define NEED_D_NAMLEN # if HAVE_SYS_NDIR_H # include <sys/ndir.h> # endif # if HAVE_SYS_DIR_H # include <sys/dir.h> # endif # if HAVE_NDIR_H # include <ndir.h> # endif # endif #endif typedef struct { char dir[MAX_PATH_LEN]; int dir_len; char *file; /* pointer to place in dir */ int isdir; #ifdef msdos DOS_DTA_Type *dta; char pattern[16]; #endif #ifdef unix DIR *dirp; #endif } Sys_Dir_Type; #ifdef msdos void dos_set_dta (DOS_DTA_Type *dta) { asm mov ah, 0x1A asm push ds asm lds dx, dword ptr dta asm int 21h asm pop ds } int dos_is_dir (char *file) { int n = strlen (file); if (n == 0) return 0; if (file[n - 1] == '\\') return 1; asm mov ah, 0x43 asm mov al, 0 asm push ds asm lds dx, dword ptr file asm int 21h asm pop ds asm mov n, cx asm jnc L1 return 0; L1: if (n & 0x10) return 1; return 0; } #endif #ifdef unix int unix_is_dir(char *dir) { /* AIX requires this */ #ifdef _S_IFDIR #ifndef S_IFDIR #define S_IFDIR _S_IFDIR #endif #endif struct stat buf; int mode; #ifdef S_IFLNK if (Follow_Links) { #endif if (stat(dir, &buf)) return -1; #ifdef S_IFLNK } else if (lstat(dir, &buf) < 0) return -1; #endif mode = buf.st_mode & S_IFMT; #ifdef S_IFLNK if (mode == S_IFLNK) return (-1); #endif if (mode == S_IFDIR) return (1); if (mode != S_IFREG) return (-1); return(0); } #endif Sys_Dir_Type *sys_opendir(char *dir, Sys_Dir_Type *x) { #ifdef msdos char slash = '\\'; char *pat = "*.*"; dos_set_dta (x->dta); if ((dir[1] == ':') && (dir[2] == '\\')) { strcpy (x->dir, dir); } else { /* must have drive/dirpath/filename */ getcwd(x->dir, MAX_PATH_LEN); if (*dir == slash) { strcpy (x->dir + 2, dir); } else { if (x->dir[strlen (x->dir) - 1] != slash) strcat (x->dir, "\\"); strcat(x->dir, dir); } } dir = x->dir + strlen (x->dir); /* check for a pattern already as part of the dirspec */ while (dir > x->dir) { if (*dir == '\\') break; if (*dir == '*') { while (*dir != '\\') dir--; *dir = 0; pat = dir + 1; break; } dir--; } strcpy (x->pattern, pat); #else #ifdef unix char slash = '/'; DIR *dirp; if (NULL == (dirp = (DIR *) opendir(dir))) { fprintf (stderr, "rgrep: dir %s not readable.\n", dir); return NULL; } x->dirp = dirp; strcpy(x->dir, dir); #endif /* unix */ #endif /* msdos */ x->dir_len = strlen(x->dir); if (x->dir[x->dir_len - 1] != slash) { x->dir[x->dir_len++] = slash; x->dir[x->dir_len] = 0; } return (x); } void sys_closedir(Sys_Dir_Type *x) { #ifdef msdos (void) x; #else #ifdef unix DIR *dirp; dirp = x->dirp; if (dirp != NULL) closedir(dirp); x->dirp = NULL; #endif #endif } #ifdef msdos char *dos_dta_fixup_name (Sys_Dir_Type *x) { x->file = x->dir + x->dir_len; strcpy(x->file, x->dta->name); /* sub directory */ if (x->dta->attr & 0x10) x->isdir = 1; else x->isdir = 0; return x->file; } #endif char *sys_dir_findnext(Sys_Dir_Type *x) { char *file; #ifdef msdos asm mov ah, 0x4F asm int 21h asm jnc L1 return NULL; L1: file = dos_dta_fixup_name (x); #else #ifdef unix # ifdef NEED_D_NAMLEN # define dirent direct # endif struct dirent *dp; DIR *d; d = x->dirp; if (NULL == (dp = readdir(d))) return(NULL); # ifdef NEED_D_NAMLEN dp->d_name[dp->d_namlen] = 0; # endif file = dp->d_name; x->file = x->dir + x->dir_len; strcpy (x->file, dp->d_name); x->isdir = unix_is_dir(x->dir); #endif /* unix */ #endif /* msdos */ /* exclude '.' and '..' */ if (*file++ == '.') { if ((*file == 0) || ((*file == '.') && (*(file + 1) == 0))) x->isdir = -1; } return (x->dir); } char *sys_dir_findfirst(Sys_Dir_Type *x) { #ifdef msdos unsigned int attr = 0x1 | 0x10; /* read only + sub directory */ char pat[MAX_PATH_LEN], *patp, *file; attr |= 0x2 | 0x4; /* hidden and system */ strcpy (pat, x->dir); strcat (pat, x->pattern); patp = pat; asm mov ah, 0x4e asm mov cx, attr asm push ds asm lds dx, dword ptr patp asm int 21h asm pop ds asm jc L1 file = dos_dta_fixup_name (x); /* exclude '.' and '..' */ if (*file++ == '.') { if ((*file == 0) || ((*file == '.') && (*(file + 1) == 0))) x->isdir = -1; } return x->dir; L1: return NULL; #else #ifdef unix return (sys_dir_findnext(x)); #endif #endif } #define BUF_SIZE 4096 void grep_file(char *file, char *filename) { char *p; if (Debug_Mode) return; if (Recursive_Match) { if (Match_This_Extension != NULL) { p = filename + strlen(filename); while ((p >= filename) && (*p != '.')) p--; if ((*p != '.') || #ifdef msdos stricmp(Match_This_Extension, p + 1) #else strcmp(Match_This_Extension, p + 1) #endif ) return; } else if (!SLang_regexp_match((unsigned char *) filename, strlen(filename), &recurse_reg)) return; } File_Fp = NULL; File_Vp = NULL; if (Fixed_Len_Mode) { File_Fp = fopen (file, "rb"); } else File_Vp = vopen (file, BUF_SIZE, 0); if ((File_Vp == NULL) && (File_Fp == NULL)) { fprintf(stderr, "rgrep: unable to read %s\n", file); } else { grep(file); if (File_Fp == NULL) vclose(File_Vp); else fclose (File_Fp); } } #define MAX_DEPTH 25 void grep_dir(char *dir) { static int depth; Sys_Dir_Type x; char *file; #ifdef msdos DOS_DTA_Type dta; x.dta = &dta; #endif if (NULL == sys_opendir(dir, &x)) return; if (depth >= MAX_DEPTH) { fprintf(stderr, "Maximum search depth exceeded.\n"); return; } depth++; if (Debug_Mode) fprintf(stderr, "%s\n", dir); for (file = sys_dir_findfirst(&x); file != NULL; file = sys_dir_findnext(&x)) { if (x.isdir == 0) grep_file(file, x.file); else if ((Do_Recursive > 0) && (x.isdir == 1)) grep_dir(file); #ifdef msdos dos_set_dta (&dta); /* something might move it */ #endif } sys_closedir(&x); depth--; } static unsigned char *fixup_filename (unsigned char *name) { unsigned char *pat = Recurse_Reg_Pattern_Buffer; unsigned char ch; *pat++ = '^'; while ((ch = *name++) != 0) { if (ch == '*') { *pat++ = '.'; *pat++ = '*'; } else if (ch == '?') *pat++ = '.'; else if ((ch == '.') || (ch == '$')) { *pat++ = '\\'; *pat++ = ch; } else *pat++ = ch; } *pat++ = '$'; *pat = 0; return Recurse_Reg_Pattern_Buffer; } int main(int argc, char **argv) { unsigned char buf[512]; unsigned char recurse_buf[256]; argv++; argc--; SLang_init_case_tables (); while (argc && (**argv == '-') && *(*argv + 1)) { if (!strcmp(*argv, "-R")) { argc--; argv++; if (!argc) usage(); recurse_reg.pat = fixup_filename ((unsigned char *) *argv); recurse_reg.buf = recurse_buf; recurse_reg.buf_len = 256; #ifdef msdos recurse_reg.case_sensitive = 0; #else recurse_reg.case_sensitive = 1; #endif if (SLang_regexp_compile (&recurse_reg)) exit_error("Error compiling pattern."); Do_Recursive = 1; Recursive_Match = 1; } else if (!strcmp(*argv, "-x")) { argc--; argv++; if (!argc) usage(); Recursive_Match = 1; Match_This_Extension = *argv; } else { parse_flags(*argv + 1); } argv++; argc--; } if (!argc) usage(); reg.pat = (unsigned char *) *argv; reg.buf = buf; reg.buf_len = sizeof (buf); reg.case_sensitive = Case_Sensitive; if (SLang_regexp_compile (®)) exit_error("Error compiling pattern."); argc--; argv++; Must_Match = 1; if (reg.osearch) { SLsearch_init ((char *) reg.pat, 1, Case_Sensitive, &Search_St); } else if (reg.must_match) { SLsearch_init ((char *) reg.must_match_str, 1, Case_Sensitive, &Search_St); } else Must_Match = 0; if (argc == 0) { if (Fixed_Len_Mode) File_Fp = stdin; else File_Vp = vstream(fileno(stdin), BUF_SIZE, 0); if ((File_Fp == NULL) && (File_Vp == NULL)) { exit_error("Error vopening stdin."); } grep("stdin"); if (File_Vp != NULL) vclose(File_Vp); else fclose (File_Fp); } else { if ((Do_Recursive > 0) || (argc != 1)) print_file_too = 1; while (argc--) { #ifdef unix int ret; #endif #ifdef msdos { char *p = *argv; while (*p) { if (*p == '/') *p = '\\'; p++; } } #endif if ( #ifdef msdos dos_is_dir (*argv) /* * && (('\\' == (*argv)[strlen(*argv) - 1]) * || (!strcmp (*argv, ".")) * || (!strcmp (*argv, ".."))) */ #else #ifdef unix (1 == (ret = unix_is_dir (*argv))) #endif #endif ) { print_file_too = 1; if (Do_Recursive >= 0) grep_dir (*argv); } else #ifdef msdos { char *file = *argv; while (*file && (*file != '*')) file++; if (*file == '*') { print_file_too = 1; grep_dir (*argv); } else grep_file(*argv, *argv); } #else #ifdef unix if (ret == 0) #endif grep_file(*argv, *argv); #endif argv++; } } return (0); } /* ------------------------------------------------------------ */ #ifdef VMS int vms_expand_filename(char *file,char *expanded_file) { unsigned long status; static int context = 0; static char inputname[256] = ""; $DESCRIPTOR(file_desc,inputname); $DESCRIPTOR(default_dsc,"SYS$DISK:[]*.*;"); static struct dsc$descriptor_s result = {0, DSC$K_DTYPE_T, DSC$K_CLASS_D, NULL}; if (strcmp(inputname, file)) { if (context) { lib$find_file_end(&context); } context = 0; strcpy(inputname, file); file_desc.dsc$w_length = strlen(inputname); } if (RMS$_NORMAL == lib$find_file(&file_desc,&result,&context, &default_dsc,0,0,&Number_Zero)) { MEMCPY(expanded_file, result.dsc$a_pointer, result.dsc$w_length); expanded_file[result.dsc$w_length] = '\0'; return (1); } else { /* expanded_file[0] = '\0'; */ /* so file comes back as zero width */ return(0); } } static int context = 0; static char inputname[256] = ""; $DESCRIPTOR(file_desc,inputname); $DESCRIPTOR(default_dsc,"SYS$DISK:[]*.*;"); int sys_findnext(char *file) { unsigned long status; static struct dsc$descriptor_s result = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_D, NULL }; if (RMS$_NORMAL == lib$find_file(&file_desc,&result,&context, &default_dsc,0,0,&Number_Zero)) { MEMCPY(file, result.dsc$a_pointer, result.dsc$w_length); file[result.dsc$w_length] = 0; return (1); } else return(0); } int sys_findfirst(char *file) { char *file; strcpy(inputname, file); file_desc.dsc$w_length = strlen(inputname); if (context) lib$find_file_end(&context); context = 0; return sys_findnext(file); } #endif /* VMS */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.