home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / AP / JED / JED097-1.TAR / jed / src / rgrep.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-12  |  18.5 KB  |  891 lines

  1. /*
  2.  *  Copyright (c) 1994 John E. Davis  (davis@amy.tch.harvard.edu)
  3.  *  All Rights Reserved.
  4.  */
  5. #include <stdio.h>
  6. #include <string.h>
  7.  
  8. /* For isatty */
  9. #ifdef msdos
  10. #include <io.h>
  11. #endif
  12.  
  13. #include "slang.h"
  14. #include "vfile.h"
  15.  
  16. static int Case_Sensitive = 1;
  17. static int File_Name_Only;
  18. static int Do_Recursive = 0;
  19. static int Recursive_Match = 0;
  20. static int Highlight = 0;
  21. static int Output_Match_Only = 0;
  22. static int Count_Matches = 0;
  23. static int Line_Numbers = 0;
  24. static int Follow_Links = 0;
  25. static int Debug_Mode = 0;
  26. static char *Match_This_Extension;
  27.  
  28. #define HON_STR "\033[1m"
  29. #define HON_STR_LEN 4
  30. #define HOFF_STR "\033[0m"
  31. #define HOFF_STR_LEN 4
  32.  
  33. void usage(void)
  34. {
  35.    fputs("rgrep (v1.0)\nUsage: rgrep [options..] pattern [files ...]\n\
  36. Options:\n\
  37.   -?        additional help (use '-?' to avoid shell expansion on some systems)\n\
  38.   -c        count matches\n\
  39.   -h        highlight match (ANSI compatable terminal assumed)\n\
  40.   -H        Output match instead of entire line containing match\n\
  41.   -i        ignore case\n\
  42.   -l        list filename only\n\
  43.   -n        print line number of match\n\
  44.   -F        follow links\n\
  45.   -r        recursively scan through directory tree\n\
  46.   -R 'pat'  like '-r' except that only those files matching 'pat' are checked\n\
  47.   -x 'ext'  checks only files with extension given by 'ext'.\n\
  48. \n\
  49. 'pattern' is a valid 'ex' type of regular expression.  See the man page for ex.\n\
  50. It is best enclosed in single quotes to avoid shell expansion.\n", stderr);
  51.  
  52.    exit(1);
  53. }
  54.  
  55. void additional_help (void)
  56. {
  57.    char buf[3];
  58.    fputs("Supported Regular Expressions:\n\
  59.    .                  match any character except newline\n\
  60.    *                  matches zero or more occurences of previous RE\n\
  61.    +                  matches one or more occurences of previous RE\n\
  62.    ?                  matches zero or one occurence of previous RE\n\
  63.    ^                  matches beginning of line\n\
  64.    $                  matches end of line\n\
  65.    [ ... ]            matches any single character between brackets.\n\
  66.                       For example, [-02468] matches `-' or any even digit.\n\
  67.               and [-0-9a-z] matches `-' and any digit between 0 and 9\n\
  68.               as well as letters a through z.\n\
  69.    \\{ ... \\}\n\
  70.    \\( ... \\)\n\
  71.    \\1, \\2, ..., \\9    matches match specified by nth \\( ... \\) expression.\n\
  72.                       For example, '\\([ \\t][a-zA-Z]+\\)\\1[ \\t]' matches any\n\
  73.               word repeated consecutively.\n", stderr);
  74.    if (isatty(fileno(stderr)) && isatty(fileno(stdin)))
  75.      {
  76.     fputs("\nPress RETURN for examples>", stderr);
  77.     fgets(buf, 2, stdin);
  78.     putc('\n', stderr);
  79.      }
  80.    fputs("Examples:\n\
  81. \n\
  82.  Look in all files with a 'c' extension in current directory and all its\n\
  83.  subdirectories looking for matches of 'int ' at the beginning of a line,\n\
  84.  printing the line containing the match with its line number: (two methods)\n\
  85.     rgrep -n -R '*.c' '^int ' .\n\
  86.     rgrep -n -x c '^int ' .\n\
  87. \n\
  88.  Highlight all matches of repeated words in file 'paper.tex':\n\
  89.     rgrep -h '[ \\t]\\([a-zA-Z]+\\)[ \\t]+\\1[ \\t\\n]' paper.tex\n\
  90.     rgrep -h '^\\([a-zA-Z]+\\)[ \\t]+\\1[ \\t\\n]' paper.tex\n\
  91.    (Note that this version of rgrep requires two passes for this example)\n", stderr);
  92.    exit (-1);
  93. }
  94.  
  95.    
  96. void parse_flags(char *f)
  97. {
  98.    char ch;
  99.    while ((ch = *f++) != 0)
  100.      {
  101.     switch (ch)
  102.       {
  103.        case 'i': Case_Sensitive = 0; break;
  104.        case 'l': File_Name_Only = 1; break;
  105.        case 'r': Do_Recursive = 1; break;
  106.        case 'H':
  107.          Highlight = 1;           /* does not cause highlight for this case */
  108.          Output_Match_Only = 1;
  109.          break;
  110.        case 'h':
  111. #ifndef pc_system
  112.          Highlight = 1;
  113. #endif
  114.          break;
  115.        case 'c': Count_Matches = 1; break;
  116.        case 'n': Line_Numbers = 1; break;
  117.        case 'F': Follow_Links = 1; break;
  118.        case 'D': Debug_Mode = 1; break;
  119.        case '?': additional_help (); break;
  120.        default: usage ();
  121.       }
  122.      }
  123. }
  124.  
  125. /* 8bit clean upper and lowercase macros */
  126. unsigned char Chg_LCase_Lut[256];
  127. unsigned char Chg_UCase_Lut[256];
  128.  
  129. void SLang_define_case(int *u, int *l)
  130. {
  131.    unsigned char up = (unsigned char) *u, dn = (unsigned char) *l;
  132.    
  133.    Chg_LCase_Lut[up] = dn;
  134.    Chg_UCase_Lut[dn] = up;
  135. }
  136.  
  137. void init_lut(void)
  138. {
  139.    int i,j;
  140.    
  141.    for (i = 0; i < 256; i++) 
  142.      {
  143.     Chg_UCase_Lut[i] = i;
  144.     Chg_LCase_Lut[i] = i;
  145.      }
  146.    
  147.    for (i = 'A'; i <= 'Z'; i++) 
  148.      {
  149.     j = i + 32;
  150.     Chg_UCase_Lut[j] = i;
  151.     Chg_LCase_Lut[i] = j;
  152.      }
  153. #ifdef msdos
  154.    /* Initialize for DOS code page 437. */
  155.    Chg_UCase_Lut[135] = 128; Chg_LCase_Lut[128] = 135;
  156.    Chg_UCase_Lut[132] = 142; Chg_LCase_Lut[142] = 132;
  157.    Chg_UCase_Lut[134] = 143; Chg_LCase_Lut[143] = 134;
  158.    Chg_UCase_Lut[130] = 144; Chg_LCase_Lut[144] = 130;
  159.    Chg_UCase_Lut[145] = 146; Chg_LCase_Lut[146] = 145;
  160.    Chg_UCase_Lut[148] = 153; Chg_LCase_Lut[153] = 148;
  161.    Chg_UCase_Lut[129] = 154; Chg_LCase_Lut[154] = 129;
  162.    Chg_UCase_Lut[164] = 165; Chg_LCase_Lut[165] = 164;
  163. #else
  164.    /* ISO Latin */
  165.    for (i = 192; i <= 221; i++) 
  166.      {
  167.     j = i + 32;
  168.     Chg_UCase_Lut[j] = i;
  169.     Chg_LCase_Lut[i] = j;
  170.      }
  171.    Chg_UCase_Lut[215] = 215; Chg_LCase_Lut[215] = 215;
  172.    Chg_UCase_Lut[223] = 223; Chg_LCase_Lut[223] = 223;
  173.    Chg_UCase_Lut[247] = 247; Chg_LCase_Lut[247] = 247;
  174.    Chg_UCase_Lut[255] = 255; Chg_LCase_Lut[255] = 255;
  175. #endif
  176.  
  177. }
  178.  
  179.  
  180. #define UPPER_CASE(x) (Chg_UCase_Lut[(unsigned char) (x)])
  181. #define upcase(ch) (cs ? ch : UPPER_CASE(ch))
  182.  
  183. static int ind[256];
  184.  
  185. unsigned char *forw_search_region
  186.     (register unsigned char *beg, unsigned char *end, unsigned char *key, register int key_len)
  187. {
  188.    register unsigned char char1;
  189.    unsigned char *pos;
  190.    int j, str_len;
  191.    register unsigned char ch;
  192.    register int db;
  193.    int cs = Case_Sensitive;
  194.    
  195.  
  196.    str_len = (int) (end - beg);
  197.    if (str_len < key_len) return (NULL);
  198.  
  199.    char1 = key[key_len - 1];
  200.    beg += (key_len - 1);
  201.  
  202.    while(1)
  203.      {
  204.     if (cs) while (beg < end)
  205.       {
  206.          ch = *beg;
  207.          db = ind[(unsigned char) ch];
  208.          if ((db < key_len) && (ch == char1)) break;
  209.          beg += db; /* ind[(unsigned char) ch]; */
  210.       }
  211.     else while (beg < end)
  212.       {
  213.          ch = *beg;
  214.          db = ind[(unsigned char) ch];
  215.          if ((db < key_len) && 
  216.          (UPPER_CASE(ch) == char1)) break;
  217.          beg += db; /* ind[(unsigned char) ch]; */
  218.       }
  219.     
  220.     if (beg >= end) return(NULL);
  221.     
  222.     pos = beg - (key_len - 1);
  223.     for (j = 0; j < key_len; j++)
  224.       {
  225.          ch = upcase(pos[j]);
  226.          if (ch != (unsigned char) key[j]) break;
  227.       }
  228.     
  229.     if (j == key_len) return(pos);
  230.     beg += 1;
  231.      }
  232. }
  233.  
  234. static int key_len;
  235. static unsigned char search_buf[256];
  236.  
  237.  
  238. static void upcase_search_word(unsigned char *str)
  239. {
  240.    int i, maxi;
  241.    int cs = Case_Sensitive;
  242.    register int max = strlen((char *) str);
  243.    char *w;
  244.    register int *indp, *indpm;
  245.    
  246.    w = (char *) search_buf;
  247.    indp = ind; indpm = ind + 256; while (indp < indpm) *indp++ = max;
  248.    
  249.    i = 0;
  250.    while (i++ < max)
  251.      {
  252.     maxi = max - i;
  253.     if (cs)
  254.       {
  255.          *w = *str;
  256.          ind[(unsigned char) *str] = maxi;
  257.       }
  258.     else
  259.       {
  260.          *w = UPPER_CASE(*str);
  261.          ind[(unsigned char) *w] = maxi;
  262.          ind[(unsigned char) LOWER_CASE(*str)] = maxi;
  263.       }
  264.     str++; w++;
  265.      }
  266.    search_buf[max] = 0;
  267.    key_len = max;
  268. }
  269.  
  270.  
  271.  
  272. void msg_error(char *str)
  273. {
  274.    fputs(str, stderr);
  275.    putc('\n', stderr);
  276. }
  277.  
  278. void exit_error(char *s)
  279. {
  280.    fprintf(stderr, "rgrep: %s\n", s);
  281.    exit(1);
  282. }
  283.  
  284. static SLRegexp_Type reg;
  285. static SLRegexp_Type recurse_reg;
  286. static int Must_Match;
  287. static int print_file_too;
  288.  
  289. void output_line(unsigned char *s, unsigned int n, unsigned char *p, unsigned char *pmax)
  290. {
  291.    if (Highlight == 0)
  292.      {
  293.     fwrite((char *) s, 1, n, stdout);
  294.      }
  295.    else
  296.      {
  297.     if (Output_Match_Only == 0)
  298.       {
  299.          fwrite ((char *) s, 1, (int) (p - s), stdout);
  300.          fwrite (HON_STR, 1, HON_STR_LEN, stdout);
  301.       }
  302.     
  303.     fwrite (p, 1, (int) (pmax - p), stdout);
  304.     if (Output_Match_Only == 0)
  305.       {
  306.          fwrite (HOFF_STR, 1, HOFF_STR_LEN, stdout);
  307.          fwrite (pmax, 1, (int) n - (int) (pmax - s), stdout);
  308.       }
  309.     else if (*(pmax - 1) != '\n') fwrite("\n", 1, 1, stdout);
  310.      }
  311. }
  312.  
  313.  
  314. static VFILE *vfile_vp;
  315.  
  316. void grep(char *file)
  317. {
  318.    unsigned char *buf, *p, *pmax;
  319.    unsigned int n;
  320.    int line = 0, n_matches = 0;
  321.    
  322.    while (NULL != (buf = (unsigned char *) vgets(vfile_vp, &n)))
  323.      {
  324.     line++;
  325.     if (Must_Match)
  326.       {
  327.          if (key_len > n) continue;
  328.          if (NULL == (p = forw_search_region(buf, buf + n, search_buf, key_len)))
  329.            {
  330.           continue;
  331.            }
  332.          if (reg.osearch) 
  333.            {
  334.           pmax = p + key_len;
  335.           goto match_found;
  336.            }
  337.       }
  338.     
  339.     if (!SLang_regexp_match(buf, (int) n, ®)) continue;
  340.     p = buf + reg.beg_matches[0];
  341.     pmax = p + reg.end_matches[0];
  342.     
  343.     match_found:
  344.     n_matches++;
  345.     
  346.     if (Count_Matches) continue;
  347.     if (File_Name_Only)
  348.       {
  349.          puts(file);
  350.          return;
  351.       }
  352.     if (print_file_too)
  353.       {
  354.          fputs(file, stdout);
  355.          putc(':', stdout);
  356.       }
  357.     if (Line_Numbers)
  358.       {
  359.          fprintf(stdout, "%d:", line);
  360.       }
  361.          
  362.     output_line(buf, n, p, pmax);
  363.      }
  364.    if (n_matches && Count_Matches)
  365.      {
  366.     if (print_file_too || File_Name_Only)
  367.       {
  368.          fputs(file, stdout);
  369.          putc(':', stdout);
  370.       }
  371.     fprintf(stdout, "%d\n", n_matches);
  372.      }
  373. }
  374.  
  375. #ifdef msdos
  376. #include <dir.h>
  377. #endif
  378.  
  379. #ifdef unix
  380. #include <sys/types.h>
  381. #include <sys/stat.h>
  382. #ifdef sequent
  383. # include <sys/dir.h>
  384. # define NEED_D_NAMLEN
  385. #else
  386. # include <dirent.h>
  387. #endif
  388. #endif
  389.  
  390.  
  391. #ifdef msdos
  392. #define MAX_PATH_LEN 128
  393. #else
  394. #define MAX_PATH_LEN 512
  395. #endif
  396.  
  397. #ifdef msdos
  398. typedef struct Dos_DTA_Type
  399. {
  400.    unsigned char undoc[21];
  401.    unsigned char attr;
  402.    unsigned int time;
  403.    unsigned int date;
  404.    unsigned char low_size[2];
  405.    unsigned char high_size[2];
  406.    char name[13];
  407. } DOS_DTA_Type;
  408. #endif
  409.  
  410. typedef struct
  411. {
  412.    char dir[MAX_PATH_LEN];
  413.    int dir_len;
  414.    char *file;                   /* pointer to place in dir */
  415.    int isdir;
  416. #ifdef msdos
  417.    DOS_DTA_Type *dta;
  418.    char pattern[16];
  419. #endif
  420. #ifdef unix
  421.    DIR *dirp;
  422. #endif
  423. } Sys_Dir_Type;
  424.    
  425.  
  426. #ifdef msdos 
  427. void dos_set_dta (DOS_DTA_Type *dta)
  428. {
  429.    asm mov ah, 0x1A
  430.    asm push ds
  431.    asm lds dx, dword ptr dta
  432.    asm int 21h
  433.    asm pop ds
  434. }
  435. #endif
  436.  
  437. #ifdef unix
  438. int unix_is_dir(char *dir)
  439. {
  440. /* AIX requires this */
  441. #ifdef _S_IFDIR
  442. #ifndef S_IFDIR
  443. #define S_IFDIR _S_IFDIR
  444. #endif
  445. #endif
  446.    struct stat buf;
  447.    int mode;
  448.  
  449. #ifdef S_IFLNK
  450.    if (Follow_Links)
  451.      {
  452. #endif
  453.     if (stat(dir, &buf)) return -1;
  454. #ifdef S_IFLNK
  455.      }
  456.    else if (lstat(dir, &buf) < 0) return -1;
  457. #endif
  458.    
  459.    mode = buf.st_mode & S_IFMT;
  460.    
  461. #ifdef S_IFLNK
  462.    if (mode == S_IFLNK) return (-1);
  463. #endif
  464.    if (mode == S_IFDIR) return (1);
  465.    if (mode != S_IFREG) return (-1);
  466.    
  467.    return(0);
  468. }
  469. #endif  /* unix */
  470.  
  471. Sys_Dir_Type *sys_opendir(char *dir, Sys_Dir_Type *x)
  472. {
  473. #ifdef msdos
  474.    char slash = '\\';
  475.    char *pat = "*.*";
  476.    dos_set_dta (x->dta);
  477.    
  478.    if ((dir[1] == ':') && (dir[2] == '\\'))
  479.      {
  480.     strcpy (x->dir, dir);
  481.      }
  482.    else
  483.      {
  484.     /* must have drive/dirpath/filename */
  485.     getcwd(x->dir, MAX_PATH_LEN);
  486.     if (*dir == slash) 
  487.       {
  488.          strcpy (x->dir + 2, dir);
  489.       }
  490.     else
  491.       {
  492.          if (x->dir[strlen (x->dir) - 1] != slash) strcat (x->dir, "\\");
  493.          strcat(x->dir, dir);
  494.       }
  495.      }
  496.    
  497.    dir = x->dir + strlen (x->dir);
  498.    /* check for a pattern already as part of the dirspec */
  499.    while (dir > x->dir)
  500.      {
  501.     if (*dir == '\\') break;
  502.     if (*dir == '*')
  503.       {
  504.          while (*dir != '\\') dir--;
  505.          *dir = 0;
  506.          pat = dir + 1;
  507.          break;
  508.       }
  509.     dir--;
  510.      }
  511.    strcpy (x->pattern, pat);
  512.    
  513. #else
  514. #ifdef unix
  515.    char slash = '/';
  516.    DIR *dirp;
  517.    if (NULL == (dirp = (DIR *) opendir(dir)))
  518.      {
  519.     fprintf (stderr, "rgrep: dir %s not readable.\n", dir);
  520.     return NULL;
  521.      }
  522.    x->dirp = dirp;
  523.    strcpy(x->dir, dir);   
  524. #endif /* unix */
  525. #endif /* msdos */
  526.    x->dir_len = strlen(x->dir);
  527.    if (x->dir[x->dir_len - 1] != slash) 
  528.      {
  529.     x->dir[x->dir_len++] = slash;
  530.     x->dir[x->dir_len] = 0;
  531.      }
  532.    return (x);
  533. }
  534.  
  535.  
  536.  
  537. void sys_closedir(Sys_Dir_Type *x)
  538. {
  539. #ifdef msdos
  540.    (void) x;
  541. #else
  542. #ifdef unix
  543.    DIR *dirp;
  544.    dirp = x->dirp;
  545.    if (dirp != NULL) closedir(dirp);
  546.    x->dirp = NULL;
  547. #endif
  548. #endif
  549. }
  550.  
  551. #ifdef msdos
  552. char *dos_dta_fixup_name (Sys_Dir_Type *x)
  553. {
  554.    x->file = x->dir + x->dir_len;
  555.    strcpy(x->file, x->dta->name);
  556.    /* sub directory */
  557.    if (x->dta->attr & 0x10) x->isdir = 1; else x->isdir = 0;
  558.    return x->file;
  559. }
  560. #endif
  561.  
  562. char *sys_dir_findnext(Sys_Dir_Type *x)
  563. {
  564.    char *file;
  565. #ifdef msdos
  566.    asm mov ah, 0x4F
  567.    asm int 21h
  568.    asm jnc L1
  569.    return NULL;
  570.    
  571.    L1:
  572.    file = dos_dta_fixup_name (x);
  573. #else
  574.    
  575. #ifdef unix
  576. #  ifdef NEED_D_NAMLEN
  577. #    define dirent direct
  578. #  endif
  579.    struct dirent *dp;
  580.    DIR *d;
  581.    d = x->dirp;
  582.    
  583.    if (NULL == (dp = readdir(d))) return(NULL);
  584. #  ifdef NEED_D_NAMLEN
  585.      dp->d_name[dp->d_namlen] = 0;
  586. #  endif
  587.    file = dp->d_name;
  588.    x->file = x->dir + x->dir_len;
  589.    strcpy (x->file, dp->d_name);
  590.    x->isdir = unix_is_dir(x->dir);
  591. #endif /* unix */
  592. #endif /* msdos */
  593.    /* exclude '.' and '..' */
  594.    if (*file++ == '.')
  595.      {
  596.     if ((*file == 0) || 
  597.         ((*file == '.') && (*(file + 1) == 0))) x->isdir = -1;
  598.      }
  599.    return (x->dir);
  600. }
  601.  
  602. char *sys_dir_findfirst(Sys_Dir_Type *x)
  603. {
  604. #ifdef msdos
  605.    unsigned int attr = 0x1 | 0x10;     /* read only + sub directory */
  606.    char pat[MAX_PATH_LEN], *patp, *file;
  607.    
  608.    attr |= 0x2 | 0x4;               /* hidden and system */
  609.    
  610.    strcpy (pat, x->dir);
  611.    strcat (pat, x->pattern);
  612.    patp = pat;
  613.    
  614.    asm mov ah, 0x4e
  615.    asm mov cx, attr
  616.    asm push ds
  617.    asm lds dx, dword ptr patp
  618.    asm int 21h
  619.    asm pop ds
  620.    asm jc L1
  621.    
  622.    file = dos_dta_fixup_name (x);
  623.    /* exclude '.' and '..' */
  624.    if (*file++ == '.')
  625.      {
  626.     if ((*file == 0) || 
  627.         ((*file == '.') && (*(file + 1) == 0))) x->isdir = -1;
  628.      }
  629.    return x->dir;
  630.    
  631.    L1:  return NULL;
  632. #else
  633. #ifdef unix
  634.    return (sys_dir_findnext(x));
  635. #endif
  636. #endif
  637. }
  638.  
  639. #define BUF_SIZE 4096
  640.  
  641. void grep_file(char *file, char *filename)
  642. {
  643.    char *p;
  644.    if (Debug_Mode) return;
  645.    if (Recursive_Match)
  646.      {
  647.     if (Match_This_Extension != NULL)
  648.       {
  649.          p = filename + strlen(filename);
  650.          while ((p >= filename) && (*p != '.')) p--;
  651.          if ((*p != '.') ||
  652. #ifdef msdos
  653.          stricmp(Match_This_Extension, p + 1)
  654. #else
  655.          strcmp(Match_This_Extension, p + 1)
  656. #endif
  657.          )
  658.            return;
  659.       }
  660.     else
  661.       if (!SLang_regexp_match((unsigned char *) filename, strlen(filename), &recurse_reg)) return;
  662.      }
  663.    
  664.    vfile_vp = vopen (file, BUF_SIZE, 0);
  665.    if (vfile_vp != NULL)
  666.      {
  667.     grep(file);
  668.     vclose(vfile_vp);
  669.      }
  670.    else fprintf(stderr, "rgrep: unable to read %s\n", file);
  671. }
  672.  
  673. #define MAX_DEPTH 25
  674. void grep_dir(char *dir)
  675. {
  676.    static int depth;
  677.    Sys_Dir_Type x;
  678.    char *file;
  679. #ifdef msdos
  680.    DOS_DTA_Type dta;
  681.    x.dta = &dta;
  682. #endif
  683.    
  684.    if (NULL == sys_opendir(dir, &x)) return;
  685.    if (depth >= MAX_DEPTH)
  686.      {
  687.     fprintf(stderr, "Maximum search depth exceeded.\n");
  688.     return;
  689.      }
  690.    
  691.    depth++;
  692.    if (Debug_Mode) fprintf(stderr, "%s\n", dir);
  693.    
  694.    for (file = sys_dir_findfirst(&x); 
  695.     file != NULL; file = sys_dir_findnext(&x))
  696.      {
  697.     if (x.isdir == 0) grep_file(file, x.file);
  698.     else if (x.isdir == 1) grep_dir(file);
  699. #ifdef msdos
  700.     dos_set_dta (&dta);           /* something might move it */
  701. #endif
  702.      }
  703.    
  704.    sys_closedir(&x);
  705.    depth--;
  706. }
  707.  
  708.    
  709.  
  710.  
  711. int main(int argc, char **argv)
  712. {
  713.    unsigned char buf[256];
  714.    unsigned char recurse_buf[256];
  715.    
  716.    argv++;
  717.    argc--;
  718.    
  719.    while (argc && (**argv == '-') && *(*argv + 1))
  720.      {
  721.     if (!strcmp(*argv, "-R"))
  722.       {
  723.          argc--;
  724.          argv++;
  725.          if (!argc) usage();
  726.          recurse_reg.pat = (unsigned char *) *argv;
  727.          recurse_reg.buf = recurse_buf;
  728.          recurse_reg.buf_len = 256;
  729.          recurse_reg.case_sensitive = 1;
  730.    
  731.          if (SLang_regexp_compile (&recurse_reg)) exit_error("Error compiling pattern.");
  732.          Do_Recursive = 1;
  733.          Recursive_Match = 1;
  734.       }
  735.     else if (!strcmp(*argv, "-x"))
  736.       {
  737.          argc--;
  738.          argv++;
  739.          if (!argc) usage();
  740.          Recursive_Match = 1;
  741.          Match_This_Extension = *argv;
  742.       }
  743.     else
  744.       {
  745.          parse_flags(*argv + 1);
  746.       }
  747.     argv++; argc--;
  748.      }
  749.    
  750.    if (!argc) usage();
  751.    init_lut();
  752.    
  753.    reg.pat = (unsigned char *) *argv;
  754.    reg.buf = buf;
  755.    reg.buf_len = 256;
  756.    reg.case_sensitive = Case_Sensitive;
  757.    
  758.    if (SLang_regexp_compile (®)) exit_error("Error compiling pattern.");
  759.    argc--; argv++;
  760.  
  761.    Must_Match = 1;
  762.    
  763.    if (reg.osearch)
  764.      {
  765.         upcase_search_word(reg.pat);
  766.      }
  767.    else if (reg.must_match)
  768.      {
  769.     upcase_search_word(reg.must_match_str);
  770.      }
  771.    else Must_Match = 0;
  772.    
  773.     
  774.    if (argc == 0)
  775.      {
  776.     vfile_vp = vstream(fileno(stdin), BUF_SIZE, 0);
  777.     if (vfile_vp == NULL)
  778.       {
  779.          exit_error("Error vopening stdin.");
  780.       }
  781.     grep("stdin");
  782.     vclose(vfile_vp);
  783.      }
  784.    else
  785.      {
  786.     if (Do_Recursive || (argc != 1)) print_file_too = 1;
  787.     while (argc--)
  788.       {
  789.          if (Do_Recursive
  790. #ifdef msdos
  791.          && ('\\' == (*argv)[strlen(*argv) - 1])
  792. #else
  793. #ifdef unix
  794.          && (1 == unix_is_dir (*argv))
  795. #endif
  796. #endif
  797.          ) grep_dir (*argv);
  798.          else
  799. #ifdef msdos
  800.            {
  801.           char *file = *argv;
  802.           while (*file && (*file != '*')) file++;
  803.           if (*file == '*') 
  804.             {
  805.                print_file_too = 1;
  806.                grep_dir (*argv); 
  807.             }
  808.           else grep_file(*argv, *argv);
  809.            }
  810. #else
  811.          grep_file(*argv, *argv);
  812. #endif
  813.          argv++;
  814.       }
  815.      }
  816.    return (0);
  817. }
  818.  
  819.  
  820. /* ------------------------------------------------------------ */
  821.  
  822. #ifdef VMS
  823.  
  824. int vms_expand_filename(char *file,char *expanded_file)
  825. {
  826.     unsigned long status;
  827.     static int context = 0;
  828.     static char inputname[256] = "";
  829.     $DESCRIPTOR(file_desc,inputname);
  830.     $DESCRIPTOR(default_dsc,"SYS$DISK:[]*.*;");
  831.     static struct dsc$descriptor_s  result =
  832.         {0, DSC$K_DTYPE_T, DSC$K_CLASS_D, NULL};
  833.  
  834.     if (strcmp(inputname, file))
  835.       {
  836.       if (context)
  837.         {
  838.         lib$find_file_end(&context);
  839.         }
  840.       context = 0;
  841.       strcpy(inputname, file);
  842.       file_desc.dsc$w_length = strlen(inputname);
  843.       }
  844.  
  845.     if (RMS$_NORMAL == lib$find_file(&file_desc,&result,&context,
  846.                             &default_dsc,0,0,&Number_Zero))
  847.       {
  848.       MEMCPY(expanded_file, result.dsc$a_pointer, result.dsc$w_length);
  849.       expanded_file[result.dsc$w_length] = '\0';
  850.           return (1);
  851.       }
  852.     else
  853.       {
  854.           /* expanded_file[0] = '\0'; */      /* so file comes back as zero width */
  855.           return(0);
  856.       }
  857. }
  858.  
  859. static int context = 0;
  860.  
  861. static char inputname[256] = "";
  862. $DESCRIPTOR(file_desc,inputname);
  863. $DESCRIPTOR(default_dsc,"SYS$DISK:[]*.*;");
  864.  
  865. int sys_findnext(char *file)
  866. {
  867.    unsigned long status;
  868.    static struct dsc$descriptor_s  result = {0, DSC$K_DTYPE_T, DSC$K_CLASS_D, NULL};
  869.  
  870.    if (RMS$_NORMAL == lib$find_file(&file_desc,&result,&context,
  871.                     &default_dsc,0,0,&Number_Zero))
  872.      {
  873.     MEMCPY(file, result.dsc$a_pointer, result.dsc$w_length);
  874.     file[result.dsc$w_length] = 0;
  875.     return (1);
  876.      }
  877.    else return(0);
  878. }
  879.  
  880. int sys_findfirst(char *file)
  881. {
  882.    char *file;
  883.    strcpy(inputname, file);
  884.    file_desc.dsc$w_length = strlen(inputname);
  885.    if (context) lib$find_file_end(&context);
  886.    context = 0;
  887.    return sys_findnext(file);
  888. }
  889. #endif
  890. /* VMS */
  891.