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

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