home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume12 / cake / part04 / Aux / sub.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-10-14  |  4.2 KB  |  282 lines

  1. /*
  2. **    Sub - do substitutions on arguments
  3. */
  4.  
  5. static    char
  6. rcs_id[] = "$Header$";
  7.  
  8. #include    "std.h"
  9. #include    <ctype.h>
  10.  
  11. char    var_char = 'X';
  12.  
  13. main(argc, argv)
  14. int    argc;
  15. char    **argv;
  16. {
  17.     extern    bool    match();
  18.     extern    char    *ground();
  19.     reg    char    *old, *new;
  20.     reg    bool    ignore;
  21.     reg    int    unmatched, i;
  22.     reg    char    *sep;
  23.  
  24.     ignore = FALSE;
  25.     unmatched = 0;
  26.     while (argc > 1 && argv[1][0] == '-')
  27.     {
  28.         for (i = 1; argv[1][i] != '\0'; i++)
  29.         {
  30.             switch (argv[1][i])
  31.             {
  32.  
  33.         when 'i':
  34.                 ignore = TRUE;
  35.         when 'v':
  36.                 if (argv[1][i+2] != '\0')
  37.                     usage();
  38.  
  39.                 var_char = argv[1][i+1];
  40.                 goto nextword;
  41.         otherwise:
  42.                 usage();
  43.             }
  44.         }
  45.  
  46. nextword:
  47.         argc--;
  48.         argv++;
  49.     }
  50.  
  51.     if (argc < 2)
  52.         usage();
  53.     
  54.     old = argv[1];
  55.     new = argv[2];
  56.     argv += 2;
  57.     argc -= 2;
  58.  
  59.     sep = "";
  60.     while (argc > 1)
  61.     {
  62.         if (! match(argv[1], old))
  63.             unmatched++;
  64.         else
  65.         {
  66.             printf("%s%s", sep, ground(new));
  67.             sep = " ";
  68.         }
  69.  
  70.         argc--;
  71.         argv++;
  72.     }
  73.  
  74.     printf("\n");
  75.     exit(ignore? 0: unmatched);
  76. }
  77.  
  78. /*
  79. **    Tell the unfortunate user how to use sub.
  80. */
  81.  
  82. usage()
  83. {
  84.     printf("Usage: sub [-i] [-vX] oldpattern newpattern name ...\n");
  85.     exit(1);
  86. }
  87.  
  88. /*
  89. **    Module to manipulate Cake patterns.
  90. */
  91.  
  92. typedef    struct    s_env
  93. {
  94.     char    *en_val;
  95.     bool    en_bound;
  96. } Env;
  97.  
  98. #define    NOVAR     10
  99. #define    MAXVAR     11
  100. #define    MAXSIZE    128
  101.  
  102. Env    env[MAXVAR];
  103.  
  104. /*
  105. **    This function initialises the environment of domatch.
  106. */
  107.  
  108. bool
  109. match(str, pat)
  110. reg    char    *str;
  111. reg    char    *pat;
  112. {
  113.     extern    bool    domatch();
  114.     reg    int    i;
  115.     reg    char    *s, *p;
  116.  
  117.     p = pat+strlen(pat)-1;
  118.     if (*p != var_char && !isdigit(*p))    /* not part of a var */
  119.     {
  120.         s = str+strlen(str)-1;
  121.         if (*s != *p)            /* last chars differ */
  122.             return FALSE;
  123.     }
  124.  
  125.     for (i = 0; i < MAXVAR; i++)
  126.         env[i].en_bound = FALSE;
  127.  
  128.     return domatch(str, pat);
  129. }
  130.  
  131. /*
  132. **    Match a string against a pattern.
  133. **    The pattern is expected to have been dereferenced.
  134. **    To handle nondeterminism, a brute force recursion approach
  135. **    is taken.
  136. */
  137.  
  138. bool
  139. domatch(str, patstr)
  140. reg    char    *str;
  141. reg    char    *patstr;
  142. {
  143.     extern    char    *new_name();
  144.     char        buf[MAXSIZE];
  145.     reg    char    *follow;
  146.     reg    char    *s, *t;
  147.     reg    int    varno;
  148.     reg    int    i;
  149.     reg    bool    more;
  150.  
  151.     if (patstr[0] == var_char)
  152.     {
  153.         if (isdigit(patstr[1]))
  154.         {
  155.             varno  = patstr[1] - '0';
  156.             follow = patstr + 2;
  157.         }
  158.         else
  159.         {
  160.             varno  = NOVAR;
  161.             follow = patstr + 1;
  162.         }
  163.  
  164.         if (env[varno].en_bound)
  165.         {
  166.             /* lifetime of buf is local */
  167.             strcpy(buf, env[varno].en_val);
  168.             strcat(buf, follow);
  169.             return domatch(str, buf);
  170.         }
  171.  
  172.         i = 0;
  173.         buf[0] = '\0';
  174.         env[varno].en_bound = TRUE;
  175.         env[varno].en_val = buf;
  176.  
  177.         /* keep invariant: buf = tentative value of var  */
  178.         /* must consider *s == \0, but do not overshoot  */
  179.         for (s = str, more = TRUE; more; s++)
  180.         {
  181.             if (domatch(s, follow))
  182.             {
  183.                 /* lifetime of buf is now global */
  184.                 env[varno].en_val = new_name(buf);
  185.                 return TRUE;
  186.             }
  187.  
  188.             /* maintain invariant */
  189.             buf[i++] = *s;
  190.             buf[i]   = '\0';
  191.  
  192.             more = (*s != '\0');
  193.         }
  194.         
  195.         /* no luck, match failed */
  196.         env[varno].en_bound = FALSE;
  197.         return FALSE;
  198.     }
  199.  
  200.     /* here we have something other than a variable first off */
  201.     for (s = str, t = patstr; *t != '\0' && *t != var_char; s++, t++)
  202.     {
  203.         if (*t == '\\')
  204.             t++;    /* the new *t is not checked for % */
  205.         
  206.         if (*s != *t)
  207.             return FALSE;
  208.     }
  209.  
  210.     /* see if we have come to the end of the pattern */
  211.     if (*t == '\0')
  212.         return *s == '\0';
  213.     
  214.     /* if not, recurse on the next variable */
  215.     return domatch(s, t);
  216. }
  217.  
  218. /*
  219. **    Ground the argument string, i.e. replace all occurrences
  220. **    of variables in it. It is fatal error for the string to
  221. **    contain a variable which has no value.
  222. */
  223.  
  224. char *
  225. ground(str)
  226. reg    char    *str;
  227. {
  228.     extern    char    *new_name();
  229.     reg    char    *s, *t;
  230.     reg    int    i, var;
  231.     char        buf[MAXSIZE];
  232.  
  233.     i = 0;
  234.     for (s = str; *s != '\0'; s++)
  235.     {
  236.         if (*s == var_char)
  237.         {
  238.             if (isdigit(s[1]))
  239.                 var = *++s - '0';
  240.             else
  241.                 var = NOVAR;
  242.             
  243.             if (! env[var].en_bound)
  244.             {
  245.                 printf("Attempt to use undefined value in %s\n", str);
  246.                 exit(1);
  247.             }
  248.  
  249.             for (t = env[var].en_val; *t != '\0'; t++)
  250.                 buf[i++] = *t;
  251.         }
  252.         or (*s == '\\')
  253.         {
  254.             if (s[1] != '\0')
  255.                 buf[i++] = *++s;
  256.         }
  257.         else
  258.             buf[i++] = *s;
  259.     }
  260.  
  261.     if (i >= MAXSIZE)
  262.     {
  263.         printf("Ran out of buffer\n");
  264.         exit(1);
  265.     }
  266.  
  267.     buf[i] = '\0';
  268.     return new_name(buf);
  269. }
  270.  
  271. char *
  272. new_name(str)
  273. reg    char    *str;
  274. {
  275.     extern    char    *malloc();
  276.     reg    char    *copy;
  277.  
  278.     copy = malloc(strlen(str) + 1);
  279.     strcpy(copy, str);
  280.     return copy;
  281. }
  282.