home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_100 / 192_01 / sgrep.c < prev    next >
Text File  |  1979-12-31  |  21KB  |  787 lines

  1. /*
  2.  *
  3.  * The  information  in  this  document  is  subject  to  change
  4.  * without  notice  and  should not be construed as a commitment
  5.  * by Digital Equipment Corporation or by DECUS.
  6.  *
  7.  * Neither Digital Equipment Corporation, DECUS, nor the authors
  8.  * assume any responsibility for the use or reliability of  this
  9.  * document or the described software.
  10.  *
  11.  *      Copyright (C) 1980, DECUS
  12.  *
  13.  * General permission to copy or modify, but not for profit,  is
  14.  * hereby  granted,  provided that the above copyright notice is
  15.  * included and reference made to  the  fact  that  reproduction
  16.  * privileges were granted by DECUS.
  17.  *
  18.  */
  19.  
  20. #include "stdio.h"
  21.  
  22. /*
  23.  * grep.
  24.  *
  25.  * Runs on the Decus compiler or on vms.
  26.  * Converted for BDS compiler (under CP/M-80), 20-Jan-83, by Chris Kern.
  27.  * Converted to IBM PC with CI-C86 C Compiler June 1983 by David N. Smith
  28.  * On vms, define as:
  29.  *      grep :== "$disk:[account]grep"     (native)
  30.  *      grep :== "$disk:[account]grep grep"     (Decus)
  31.  *
  32.  * sgrep.
  33.  *
  34.  * Addition of string substitution capability,
  35.  * multiple pattern search, upper-lower case option, scanning options,
  36.  * and name changed to sgrep, April 1986 by James J. McKeon.
  37.  * Runs on IBM PC or compatibles using ECO C88 compiler.
  38.  *
  39.  * For help type "sgrep ?".  See below for more information.
  40.  *
  41.  */
  42.  
  43.  
  44. char    *documentation[] = {
  45. "Sgrep searches a file for a given pattern and substitutes a pattern.",
  46. "If no substitution is required, the command sgrep -myn corresponds",
  47. "to grep -n and will match only. Output is to the screen and may be",
  48. "re-directed using \">\" at the DOS level. Execute by",
  49. "  sgrep [flags] pattern-file input-file",
  50. "",
  51. "Flags are single characters preceeded by '-':",
  52. "   -c      Only a count of matching lines is printed",
  53. "   -m      Match patterns only, no substitutions.",
  54. "   -n      Each line is preceeded by its line number",
  55. "   -v      Only print non-matching lines",
  56. "   -y      Upper and lower case match.",
  57. "",
  58. 0 };
  59.  
  60. char    *patdoc[] = {
  61. "Each match pattern is on a separate line followed by its substitute",
  62. "pattern, if any, also on a separate line.",
  63.  
  64. " MATCH PATTERNS",
  65. "The regular_expression defines the pattern to search for.  Upper and",
  66. "lower-case are regarded as different unless -y option is used.",
  67. "x      An ordinary character (not mentioned below) matches that character.",
  68. "'\\'    The backslash quotes any character.  \"\\$\" matches a dollar-sign.",
  69. "'$'    Matches beginning or end of line.",
  70. "'.'    A period matches any character except \"new-line\".",
  71. "':a'   A colon matches a class of characters described by the following",
  72. "':d'     character.  \":a\" matches any alphabetic, \":d\" matches digits,",
  73. "':n'     \":n\" matches alphanumerics, \": \" matches spaces, tabs, and",
  74. "': '     other control characters except new-line.",
  75. "'*'    An expression followed by an asterisk matches zero or more",
  76. "       occurrances of that expression: \"fo*\" matches \"f\", \"fo\"",
  77. "       \"foo\", etc.",
  78. "'+'    An expression followed by a plus sign matches one or more",
  79. "       occurrances of that expression: \"fo+\" matches \"fo\", etc.",
  80. "'-'    An expression followed by a minus sign optionally matches",
  81. "       the expression.",
  82. "'[]'   A string enclosed in square brackets matches any character in",
  83. "       that string, but no others.  If the first character in the",
  84. "       string is a circumflex, the expression matches any character",
  85. "       except \"new-line\" and the characters in the string.  For",
  86. "       example, \"[xyz]\" matches \"xx\" and \"zyx\", while \"[^xyz]\"",
  87. "       matches \"abc\" but not \"axb\".  A range of characters may be",
  88. "       specified by two characters separated by \"-\".  Note that,",
  89. "       [a-z] matches alphabetics, while [z-a] never matches.",
  90. "The concatenation of regular expressions is a regular expression.",
  91.  
  92. " Scanning options:",
  93. "The default scanning option is match all occurences of the pattern.",
  94. "'@'    at the beginning of the pattern, is equivalent to",
  95. "       \"$: *\", meaning match first non-whitespace pattern.",
  96. "'@e'   at the end of a pattern means that if a match is",
  97. "       found (and a substitution made), end all pattern search",
  98. "       on current line.",
  99. "'@r'   at the end of a pattern means that after a match",
  100. "       (and substitution), rescan line until no match occurs.",
  101.  
  102. " SUBSTITUTE PATTERNS ",
  103. "The only control character for substitute patterns is \"?\".",
  104. "Any other character represents itself. Only the characters ? and",
  105. " \\ itself need to be quoted.",
  106.  
  107. "'?n'   where n is a non-zero digit, indicates the position where",
  108. "       the nth wildcard string is to be placed.",
  109. "A wildcard string is any string which is not completely fixed,",
  110. "both as to the characters and number of characters in the string.",
  111. 0};
  112.  
  113. #define LMAX    100
  114. #define PMAX    2000
  115. #define NPATMAX 100
  116.  
  117. #define CHR     1
  118. #define SCOP    2
  119. #define BEOL    3
  120. #define ANY     4
  121. #define CLASS   5
  122. #define NCLASS  6
  123. #define STAR    7
  124. #define PLUS    8
  125. #define MINUS   9
  126. #define ALPHA   10
  127. #define DIGIT   11
  128. #define NALPHA  12
  129. #define PUNCT   13
  130. #define RANGE   14
  131. #define ENDPAT  15
  132. #define lowopt(x) yflag?tolower(x):x
  133.  
  134. int     cflag;
  135. int     mflag;
  136. int     nflag;
  137. int     vflag;
  138. int     yflag;
  139.  
  140. int     debug   =       0;         /* Set for debug code      */
  141.  
  142. char    *pp, *psp;
  143.  
  144. #ifndef vms
  145. char    file_name[81];
  146. #endif
  147.  
  148. char    lbuf[LMAX], slbuf[LMAX];
  149. char    pbuf[PMAX], spbuf[PMAX];
  150. char    * wldstr[19][2];  /* Location of wildcard strings */
  151. int     nws, npat, rescan, nxtln;
  152. char   *mpp[NPATMAX], *mpsp[NPATMAX];  /* Location of patterns */
  153. /*******************************************************/
  154.  
  155. main(argc, argv)
  156. char *argv[];
  157. {
  158.    register char   *p;
  159.    register int    c, i;
  160.  
  161.    FILE            *f;
  162.  
  163.    if (argc <= 1)
  164.       usage("No arguments");
  165.    if (argc == 2 && argv[1][0] == '?' && argv[1][1] == 0) {
  166.       help(documentation);
  167.       help(patdoc);
  168.       return;
  169.       }
  170.       p=argv[argc-1];
  171.       if ((f=fopen(p, "r")) == NULL) cant(p);
  172.       p = argv[1];
  173.       if (*p == '-') {
  174.          ++p;
  175.          while (c = *p++) {
  176.             switch(tolower(c)) {
  177.  
  178.             case 'c':
  179.                ++cflag;
  180.                break;
  181.  
  182.             case 'd':
  183.                ++debug;
  184.                break;
  185.  
  186.             case 'm':
  187.                ++mflag;
  188.                break;
  189.  
  190.             case 'n':
  191.                ++nflag;
  192.                break;
  193.  
  194.             case 'v':
  195.                ++vflag;
  196.                break;
  197.  
  198.             case 'y':
  199.                ++yflag;
  200.                break;
  201.  
  202.             default:
  203.                usage("Unknown flag");
  204.             }
  205.          }
  206.         p=argv[2];
  207.       }
  208.       compat(p);
  209.       grep(f, p);
  210.       fclose(f);
  211. }
  212.  
  213. /*******************************************************/
  214.  
  215. cant(s)
  216. char *s;
  217. {
  218.    fprintf(stderr, "%s: cannot open\n", s);
  219. }
  220.  
  221.  
  222. /*******************************************************/
  223.  
  224. help(hp)
  225. char **hp;  /* dns added extra '*'  */
  226. /*
  227.  * Give good help
  228.  */
  229. {
  230.    register char   **dp;
  231.  
  232.    for (dp = hp; *dp; dp++)
  233.       printf("%s\n", *dp);
  234. }
  235.  
  236.  
  237. /*******************************************************/
  238.  
  239. usage(s)
  240. char    *s;
  241. {
  242.    fprintf(stderr, "?SGREP-%s\n", s);
  243.    fprintf(stderr,
  244.   "Usage: sgrep [-mycnv] pattern-file input-file. sgrep ? for help\n");
  245.    exit(1);
  246. }
  247.  
  248.  
  249.  
  250. /*******************************************************/
  251.  
  252.  
  253. compile(source)
  254. char       *source;   /* Pattern to compile         */
  255. /*
  256.  * Compile the pattern into global pbuf[]
  257.  */
  258. {
  259.    register char  *s;         /* Source string pointer     */
  260.    register char  *lp;        /* Last pattern pointer      */
  261.    register int   c;          /* Current character         */
  262.    int            o;          /* Temp                      */
  263.    char           *spp;       /* Save beginning of pattern */
  264.    char           *cclass();  /* Compile class routine     */
  265.  
  266.    s = source;
  267.    if (debug)
  268.       printf("Pattern = %s\n", s);
  269.    while (c = *s++) {
  270.       /*
  271.        * STAR, PLUS and MINUS are special.
  272.        */
  273.       if (c == '*' || c == '+' || c == '-') {
  274.          if (pp == pbuf ||
  275.               (o=pp[-1]) == SCOP || o == '\0' ||
  276.               o == BEOL ||
  277.               o == STAR ||
  278.               o == PLUS ||
  279.               o == MINUS)
  280.             badpat("Illegal occurrance op.", source, s);
  281.          store(ENDPAT);
  282.          store(ENDPAT);
  283.          spp = pp;               /* Save pattern end     */
  284.          while (--pp > lp)       /* Move pattern down    */
  285.             *pp = pp[-1];        /* one byte             */
  286.          *pp =   (c == '*') ? STAR :
  287.             (c == '-') ? MINUS : PLUS;
  288.          pp = spp;               /* Restore pattern end  */
  289.          continue;
  290.       }
  291.       /*
  292.        * All the rest.
  293.        */
  294.       lp = pp;         /* Remember start       */
  295.       switch(c) {
  296.  
  297.       case '@':
  298.          if(s-1 == source) {
  299.            store(BEOL);
  300.            store(STAR);
  301.            store(PUNCT);
  302.            store(ENDPAT);
  303.            break;
  304.          } else {
  305.          store(SCOP);
  306.          store(*s++);
  307.          break;
  308.          }
  309.       case '$':
  310.          store(BEOL);
  311.          break;
  312.  
  313.       case '.':
  314.          store(ANY);
  315.          break;
  316.  
  317.       case '[':
  318.          s = cclass(source, s);
  319.          break;
  320.  
  321.       case ':':
  322.          if (*s) {
  323.             c = *s++;
  324.             switch(tolower(c)) {
  325.  
  326.             case 'a':
  327.             case 'A':
  328.                store(ALPHA);
  329.                break;
  330.  
  331.             case 'd':
  332.             case 'D':
  333.                store(DIGIT);
  334.                break;
  335.  
  336.             case 'n':
  337.             case 'N':
  338.                store(NALPHA);
  339.                break;
  340.  
  341.             case ' ':
  342.                store(PUNCT);
  343.                break;
  344.  
  345.             default:
  346.                badpat("Unknown : type", source, s);
  347.  
  348.             }
  349.             break;
  350.          }
  351.          else    badpat("No : type", source, s);
  352.  
  353.       case '\\':
  354.          if (*s)
  355.             c = *s++;
  356.  
  357.       default:
  358.          store(CHR);
  359.          store(lowopt(c));
  360.       }
  361.    }
  362.    pp -= 2;                /* delete linefeed */
  363.    store(ENDPAT);
  364.    store(0);                /* Terminate string     */
  365.    mpp[npat+1] = pp;
  366.    if (debug) {
  367.       for (lp = mpp[npat]; lp < pp;) {
  368.          if ((c = (*lp++ & 0377)) < ' ')
  369.             printf("\\%x ", c);
  370.          else    printf("%c ", c);
  371.         }
  372.         printf("\n");
  373.    }
  374. }
  375.  
  376. /*******************************************************/
  377.  
  378. char *
  379. cclass(source, src)
  380. char       *source;   /* Pattern start -- for error msg.      */
  381. char       *src;      /* Class start           */
  382. /*
  383.  * Compile a class (within [])
  384.  */
  385. {
  386.    register char   *s;        /* Source pointer    */
  387.    register char   *cp;       /* Pattern start     */
  388.    register int    c;         /* Current character */
  389.    int             o;         /* Temp              */
  390.  
  391.    s = src;
  392.    o = CLASS;
  393.    if (*s == '^') {
  394.       ++s;
  395.       o = NCLASS;
  396.    }
  397.    store(o);
  398.    cp = pp;
  399.    store(0);                          /* Byte count      */
  400.    while ((c = *s++) && c!=']') {
  401.       if (c == '\\') {                /* Store quoted char    */
  402.          if ((c = *s++) == '\0')      /* Gotta get something  */
  403.             badpat("Class terminates badly", source, s);
  404.          else    store(lowopt(c));
  405.       }
  406.       else if (c == '-' &&
  407.             (pp - cp) > 1 && *s != ']' && *s != '\0') {
  408.          c = pp[-1];             /* Range start     */
  409.          pp[-1] = RANGE;         /* Range signal    */
  410.          store(c);               /* Re-store start  */
  411.          c = *s++;               /* Get end char and*/
  412.          store(lowopt(c));      /* Store it        */
  413.       }
  414.       else {
  415.          store(lowopt(c));      /* Store normal char */
  416.       }
  417.    }
  418.    if (c != ']')
  419.       badpat("Unterminated class", source, s);
  420.    if ((c = (pp - cp)) >= 256)
  421.       badpat("Class too large", source, s);
  422.    if (c == 0)
  423.       badpat("Empty class", source, s);
  424.    *cp = c;
  425.    return(s);
  426. }
  427.  
  428. /*******************************************************/
  429.  
  430. store(op)
  431. {
  432.    if (pp >= &pbuf[PMAX])
  433.       error("Pattern too complex\n");
  434.    *pp++ = op;
  435. }
  436.  
  437. /*******************************************************/
  438.  
  439. badpat(message, source, stop)
  440. char  *message;       /* Error message */
  441. char  *source;        /* Pattern start */
  442. char  *stop;          /* Pattern end   */
  443. {
  444.    register int    c;
  445.  
  446.    fprintf(stderr, "-GREP-E-%s, pattern is\"%s\"\n", message, source);
  447.    fprintf(stderr, "-GREP-E-Stopped at byte %d, '%c'\n",
  448.          stop-source, stop[-1]);
  449.    error("?GREP-E-Bad pattern\n");
  450. }
  451.  
  452. /*******************************************************/
  453.  
  454. grep(fp, fn)
  455. FILE       *fp;       /* File to process            */
  456. char       *fn;       /* File name (for -f option)  */
  457. /*
  458.  * Scan the file for the pattern in pbuf[]
  459.  */
  460. {
  461.    register int lno, count, m;
  462.    int  jpat, mm;
  463.    char  *l;
  464.  
  465.    lno = 0;
  466.    count = 0;
  467.    while (fgets(lbuf, LMAX, fp)) {
  468.     ++lno;
  469.     mm = 0;
  470.     for(jpat=1;jpat<=npat;jpat++){
  471.      m = nxtln = 0;
  472.      do {
  473.        rescan = 0;
  474.        if(match(jpat)) m = 1;
  475.      } while(rescan == 1);
  476.      if(m) mm = 1;
  477.       if(nxtln)
  478.         break;
  479.     }/*jpat*/
  480.     if (!mflag)
  481.       printf("%s", lbuf);
  482.     else if(mm && !vflag || !mm && vflag) {
  483.       if(cflag)
  484.         count++;
  485.       else {
  486.         if(nflag)
  487.           printf("%d\t", lno);
  488.         printf("%s\n", lbuf);
  489.       }
  490.     }
  491.    }/*wh*/
  492.    if (cflag)
  493.       printf("%d\n", count);
  494. }
  495.  
  496. /*******************************************************/
  497.  
  498. match(jp)
  499. /*
  500.  * Match the current line (in lbuf[]), return 1 if it does.
  501.  */
  502.   int  jp;
  503. {
  504.    register char   *l;        /* Line pointer       */
  505.    char *pmatch(), *movs();
  506.   char  *s, *pat, *lst;
  507.   int km;
  508.  
  509.    km=0;
  510.    pat = mpp[jp];
  511.    l = lst = lbuf;
  512.    while(*l) {
  513.       nws = 0;
  514.       s=pmatch(l,pat);
  515.       if (s){
  516.         if(s < l) break;    /* BOL impossible */
  517.         km = 1;
  518.         if(mflag) break;
  519.         wldstr[0][0]=l;
  520.         wldstr[0][1]=s;
  521.         substit(lst, jp);
  522.         lst = s;
  523.         l = s - 1;
  524.       }
  525.       if(nxtln) break;
  526.       l++;
  527.    }
  528.    if(km && !mflag) {
  529.      substit(lst, 0);
  530.      l = movs(slbuf,slbuf+LMAX,lbuf);
  531.      *l = 0;
  532.    }
  533.    return(km);
  534. }
  535.  
  536. /*******************************************************/
  537.  
  538. char *
  539. pmatch(line, pattern)
  540. char               *line;     /* (partial) line to match      */
  541. char               *pattern;  /* (partial) pattern to match   */
  542. {
  543.    register char   *l;        /* Current line pointer         */
  544.    register char   *p;        /* Current pattern pointer      */
  545.    register char   c;         /* Current character            */
  546.    char            *e;        /* End for STAR and PLUS match  */
  547.    int             op;        /* Pattern operation            */
  548.    int             n;         /* Class counter                */
  549.    char            *are;      /* Start of STAR match          */
  550.    int  ows;
  551.    static int wss;            /* Wild string switch */
  552.  
  553.    l = line;
  554.    if (debug > 1)
  555.       printf("pmatch(\"%s\")\n", line);
  556.    p = pattern;
  557.    while ((op = *p++) != ENDPAT) {
  558.       if (debug > 1)
  559.          printf("byte[%d] = 0%o, '%c', op = 0%o\n",
  560.                l-line, *l, *l, op);
  561.       switch(op) {
  562.  
  563.       case CHR:
  564.          c = yflag?tolower(*l++):*l++;
  565.          if (c != *p++)
  566.             return(0);
  567.          break;
  568.  
  569.       case SCOP:
  570.          if(*p++ == 'r')
  571.            rescan = 1;
  572.          else
  573.            nxtln = 1;
  574.          break;
  575.  
  576.       case BEOL:
  577.          if((p-1) == pattern && l != lbuf) return(line-1);
  578.          if((p-1) != pattern && *l != '\n') return(0);
  579.          break;
  580.  
  581.       case ANY:
  582.          if (*l++ == '\n')
  583.             return(0);
  584.          break;
  585.  
  586.       case DIGIT:
  587.          if((c = *l++) < '0' || c > '9') return(0);
  588.          break;
  589.  
  590.       case ALPHA:
  591.          c = tolower(*l++);
  592.          if (c < 'a' || c > 'z')
  593.             return(0);
  594.          break;
  595.  
  596.       case NALPHA:
  597.          c = tolower(*l++);
  598.          if (c >= 'a' && c <= 'z')
  599.             break;
  600.          else if (c < '0' || c > '9')
  601.             return(0);
  602.          break;
  603.  
  604.       case PUNCT:
  605.          c = *l++;
  606.          if (c == '\n' || c > ' ')
  607.             return(0);
  608.          break;
  609.  
  610.       case CLASS:
  611.       case NCLASS:
  612.          c = yflag?tolower(*l++):*l++;
  613.          n = *p++ & 0377;
  614.          do {
  615.             if (*p == RANGE) {
  616.                p += 3;
  617.                n -= 2;
  618.                if (c >= p[-2] && c <= p[-1])
  619.                   break;
  620.             }
  621.             else {
  622.               if(c == '\n')
  623.                 return(0);
  624.               if (c == *p++) break;
  625.             }
  626.          } while (--n > 1);
  627.           if(op == CLASS && n <= 1) return(0);
  628.           if(op != CLASS && n > 1) return(0);
  629.          if (op == CLASS)
  630.             p += n - 2;
  631.          break;
  632.  
  633.       case MINUS:
  634.          e = pmatch(l, p);       /* Look for a match    */
  635.          while (*p++ != ENDPAT); /* Skip over pattern   */
  636.          if (e)                  /* Got a match?        */
  637.             l = e;               /* Yes, update string  */
  638.          break;                  /* Always succeeds     */
  639.  
  640.       case PLUS:                 /* One or more ...     */
  641.          wss=1;            /* wldstr switch on */
  642.          if ((l = pmatch(l, p)) == 0){
  643.             wss=0;
  644.             return(0);           /* Gotta have a match  */
  645.          }
  646.       case STAR:                 /* Zero or more ...    */
  647.          are = l;                /* Remember line start */
  648.          wss = 1;          /* wldstr switch on */
  649.          while (*l && (e = pmatch(l, p)))
  650.             l = e;               /* Get longest match   */
  651.          wss = 0;
  652.          ows = ++nws;  /* Save wildstring number */
  653.          while (*p++ != ENDPAT); /* Skip over pattern   */
  654.          while (l >= are) {      /* Try to match rest   */
  655.             if (e = pmatch(l, p)){
  656.              wldstr[ows][0]=are - op + 7; /* Subtract 1 if plus */
  657.              wldstr[ows][1]=l;
  658.               return(e);
  659.              }
  660.             nws = ows;
  661.             --l;                 /* Nope, try earlier   */
  662.          }
  663.          return(0);              /* Nothing else worked */
  664.  
  665.       default:
  666.          printf("Bad op code %d\n", op);
  667.          error("Cannot happen -- match\n");
  668.       }
  669.       if((wss == 0) && (op >= 4) && (op <= 13)){
  670.         ++nws;
  671.         wldstr[nws][0] = l-1;  /* single character */
  672.         wldstr[nws][1] = l;
  673.         if(op == 9 && e == 0)
  674.           wldstr[nws][0] = l;  /* null string */
  675.       }
  676.   }
  677.    return(l);
  678. }
  679.  
  680. /*******************************************************/
  681.  
  682. error(s)
  683. char *s;
  684. {
  685.    fprintf(stderr, "%s", s);
  686.    exit(1);
  687. }
  688.  
  689. compat(patfile)
  690. /* Read in pattern file and compile patterns */
  691. char  *patfile;
  692. {
  693. FILE  *fp;
  694. char  *l, *fgets();
  695. int  i;
  696. if((fp=fopen(patfile,"r")) == NULL) cant(patfile);
  697. npat = 0;
  698. mpp[1] = pp = pbuf;
  699. mpsp[1] = psp = spbuf;
  700. while(1){
  701.   l= fgets(slbuf,LMAX,fp);
  702.   if(!l) break;
  703.   npat += 1;
  704.   compile(slbuf);
  705.   if(!mflag) {
  706.     l =  fgets(slbuf,LMAX,fp);
  707.     compsub();
  708.   }
  709. }
  710.    if(debug) printf(" npat = %d \n",npat);
  711.     fclose(patfile);
  712. }
  713.  
  714. compsub()
  715. /* Compile substitute pattern into spbuf */
  716. {
  717. char *l, *p, c;
  718.   if(debug) printf(" Subspat = %s \n",slbuf);
  719.   p = psp;
  720.   for(l=slbuf;*l;l++){
  721.     c = *l;
  722.     switch(c){
  723.     case '?':
  724.       *p++ = 7;
  725.       l++;
  726.       *p++ = (*l - 48);
  727.       break;
  728.     case '\\':
  729.       c = *(++l);
  730.     default:
  731.       *p++ = c;
  732.     }
  733.   }
  734.     p--;         /* delete linefeed */
  735.     *p = 0;
  736.     psp = ++p;
  737.    mpsp[npat+1] = psp;
  738.    if(debug){
  739.     for(l=mpsp[npat];*l;l++){
  740.       if((c = (*l & 0377)) < ' ') printf("\\%x ",c);
  741.       else printf("%c ",c);
  742.     }
  743.     printf("\n");
  744.    }
  745. }
  746.  
  747. char  *movs(l1,l2,p)
  748. /* Move string from l1 to p */
  749. char  *l1, *l2, *p;
  750. {
  751. char  *l;
  752.   for(l = l1; l < l2 && *l; l++)
  753.     *p++ = *l;
  754.   return(p);
  755. }
  756.  
  757. substit(lb, jpat)
  758. /* construct output record */
  759. char  *lb;
  760. int  jpat;
  761. {
  762. char  *movs();
  763. static char  *sl = slbuf;
  764. char   *p, *l;
  765. int  k;
  766.  if(jpat == 0){
  767.   sl =  movs(wldstr[0][1],lbuf+LMAX,sl);
  768.   *sl = 0;
  769.   sl = slbuf;
  770.   return;
  771.  }
  772.   psp = mpsp[jpat];
  773.   sl = movs(lb,wldstr[0][0],sl);
  774.   for(p=psp; *p; p++){
  775.     switch(*p) {
  776.     case 7:
  777.       p++;
  778.       k = *p;
  779.       sl =   movs(wldstr[k][0],wldstr[k][1],sl);
  780.       break;
  781.     default:
  782.       *sl++ = *p;
  783.     }/*sw*/
  784.   }
  785. }
  786.  
  787.