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

  1. /*
  2. **    Module to expand out commands in patterns and actions.
  3. */
  4.  
  5. static    char
  6. rcs_id[] = "$Header: /mip/zs/src/sys/cake/RCS/expand.c,v 1.14 86/07/19 12:23:01 zs Exp $";
  7.  
  8. #include    "cake.h"
  9. #include    <ctype.h>
  10.  
  11. /*
  12. **    Expand any commands in actions. Doing this here instead of
  13. **    in the shell saves time because of cake's command cache.
  14. */
  15.  
  16. char *
  17. expand_cmds(str)
  18. reg    char    *str;
  19. {
  20.     extern    char    *get_output();
  21.     reg    char    *s;
  22.     reg    int    n, cmds, offset;
  23.     reg    int    stackp;
  24.     reg    char    *rightbr;
  25.     char        *leftbr_stack[MAXNEST];
  26.     char        *nextbr_stack[MAXNEST];
  27.     char        copybuf[MAXSIZE], buf[MAXSIZE];
  28.     reg    char    *result;
  29.  
  30.     if (index(str, '[') == NULL)
  31.         return str;
  32.  
  33.     put_trail("expand_cmds", "start");
  34.     cmds = 0;
  35.     stackp = 0;
  36.     if (strlen(str) >= MAXSIZE)
  37.     {
  38.         fprintf(stderr, "cake internal error: command too long %s\n", str);
  39.         exit_cake(FALSE);
  40.     }
  41.  
  42.     strcpy(copybuf, str);
  43.     leftbr_stack[stackp] = copybuf;
  44.     nextbr_stack[stackp] = NULL;
  45.  
  46.     /* Leftbr_stack[stackp] and rightbr enclose commands       */
  47.     /* for stackp > 0; for stackp == 0 they enclose the string */
  48.     /* Nextbr_stack gives the beginning of the next segment       */
  49.     /* after the corresponding leftbr; == 0 if not known (yet) */
  50.     /* The top entry on the stack always has nextbr == NULL       */
  51.  
  52.     for (s = copybuf; s[0] != '\0'; s++)
  53.     {
  54.         if (s[0] == '[' && s[1] == '[')
  55.         {
  56.             nextbr_stack[stackp] = s;
  57.             if (++stackp >= MAXNEST)
  58.             {
  59.                 fprintf(stderr, "cake internal error: command nesting level too deep\n");
  60.                 exit_cake(FALSE);
  61.             }
  62.  
  63.             leftbr_stack[stackp] = s;
  64.             nextbr_stack[stackp] = NULL;
  65.             s++;    /* avoid problems with [[[cmd]] ... */
  66.         }
  67.         or (s[0] == ']' && s[1] == ']')
  68.         {
  69.             if (stackp <= 0)
  70.                 continue;
  71.  
  72.             cmds++;
  73.             rightbr = s;
  74.  
  75.             leftbr_stack[stackp][0] = '\0';
  76.             leftbr_stack[stackp][1] = '\0';
  77.             rightbr[0] = '\0';
  78.             rightbr[1] = '\0';
  79.  
  80.             result = get_output(new_name(leftbr_stack[stackp]+2));
  81.             cdebug("expansion [[%s]] => [[%s]]\n", leftbr_stack[stackp]+2, result);
  82.  
  83.             segcpy(buf, leftbr_stack[stackp-1], nextbr_stack[stackp-1]);
  84.             strcat(buf, result);
  85.             offset = strlen(buf) - 1;
  86.             strcat(buf, rightbr+2);
  87.  
  88.             if (strlen(buf) >= MAXSIZE)
  89.             {
  90.                 fprintf(stderr, "cake: expansion result '%s' is too long\n", buf);
  91.                 exit_cake(FALSE);
  92.             }
  93.  
  94.             stackp--;
  95.             leftbr_stack[stackp] = new_name(buf);
  96.             nextbr_stack[stackp] = NULL;
  97.  
  98.             /* start next iteration with the */
  99.             /* first character after the ]]  */
  100.             s = leftbr_stack[stackp] + offset;
  101.         }
  102.         or (s[0] == '\\')
  103.         {
  104.             /* don't check next char */
  105.             if (s[1] != '\0')
  106.                 s++; 
  107.         }
  108.     }
  109.  
  110. #ifdef    CAKEDEBUG
  111.     if (entrydebug)
  112.         printf("after expand_cmds: [[%s]]\n", str);
  113. #endif
  114.  
  115.     if (cmds <= 0)
  116.     {
  117.         put_trail("expand_cmds", "finish");
  118.         return str;
  119.     }
  120.     or (stackp == 0)
  121.     {
  122.         put_trail("expand_cmds", "finish");
  123.         return leftbr_stack[0];
  124.     }
  125.  
  126.     segcpy(buf, leftbr_stack[0], nextbr_stack[0]);
  127.     for (n = 1; n <= stackp; n++)
  128.         segcat(buf, leftbr_stack[n], nextbr_stack[n]);
  129.  
  130.     if (strlen(buf) >= MAXSIZE)
  131.     {
  132.         fprintf(stderr, "cake: expansion result '%s' is too long\n", buf);
  133.         exit_cake(FALSE);
  134.     }
  135.  
  136.     put_trail("expand_cmds", "finish");
  137.     return new_name(buf);
  138. }
  139.  
  140. segcpy(target, left, right)
  141. reg    char    *target, *left, *right;
  142. {
  143.     reg    int    i;
  144.     reg    char    *s;
  145.  
  146.     if (right == NULL)
  147.         strcpy(target, left);
  148.     else
  149.     {
  150.         for (s = left, i = 0; s != right; s++, i++)
  151.             target[i] = *s;
  152.  
  153.         target[i] = '\0';
  154.     }
  155. }
  156.  
  157. segcat(target, left, right)
  158. reg    char    *target, *left, *right;
  159. {
  160.     reg    int    i;
  161.     reg    char    *s;
  162.  
  163.     if (right == NULL)
  164.         strcat(target, left);
  165.     else
  166.     {
  167.         for (s = left, i = strlen(target); s != right; s++, i++)
  168.             target[i] = *s;
  169.  
  170.         target[i] = '\0';
  171.     }
  172. }
  173.  
  174. /*
  175. **    Execute the given command and return its output.
  176. **    It is a fatal error for the command to terminate abnormally.
  177. */
  178.  
  179. char *
  180. get_output(cmd)
  181. reg    char    *cmd;
  182. {
  183.     extern    char    *mktemp();
  184.     extern    char    *get_out();
  185.     extern    char    *flatten();
  186.     extern    int    cake_proc();
  187.     extern    Wait    cake_wait();
  188.     char        buf[MAXSIZE];
  189.     Wait        code;
  190.     reg    char    *out_filename;
  191.     reg    FILE    *fp;
  192.     reg    int    i, c;
  193.     reg    int    pid;
  194.     reg    char    *s, *result;
  195.  
  196.     put_trail("get_output", "start");
  197.     cdebug("get_output of [%s]\n", cmd);
  198.  
  199.     /* see if we have tried this command before */
  200.     if ((result = get_out(cmd)) != NULL)
  201.     {
  202.         cdebug("cache yields [%s]\n", result);
  203.         put_trail("get_output", "early finish");
  204.         return result;
  205.     }
  206.  
  207.     out_filename = get_newname();
  208.     pid = cake_proc(cmd, Exec, out_filename, (Node *) NULL, (int (*)()) NULL, (List *) NULL);
  209.     code = cake_wait(pid);
  210.     if (code.w_status != 0 && ! zflag)
  211.     {
  212.         printf("cake, %s: nonzero exit status\n", cmd);
  213.         exit_cake(FALSE);
  214.     }
  215.  
  216.     if ((fp = fopen(out_filename, "r")) == NULL)
  217.     {
  218.         sprintf(scratchbuf, "cake system error, fopen %s", out_filename);
  219.         perror(scratchbuf);
  220.         exit_cake(FALSE);
  221.     }
  222.  
  223.     /* convert the chars in file fp to a string */
  224.     i = 0;
  225.     while ((c = getc(fp)) != EOF)
  226.         buf[i++] = c;
  227.     
  228.     buf[i] = '\0';
  229.     fclose(fp);
  230.     if (MAXSIZE <= i)
  231.     {
  232.         printf("cake, %s: output too long\n", cmd);
  233.         exit_cake(FALSE);
  234.     }
  235.  
  236. #ifndef    LEAVE_DIR
  237.     cdebug("get_output unlink out_filename %s\n", out_filename);
  238.     if (unlink(out_filename) != 0)
  239.     {
  240.         sprintf(scratchbuf, "cake system error, unlink %s", out_filename);
  241.         perror(scratchbuf);
  242.     }
  243. #endif
  244.  
  245.     /* save the result for posterity */
  246.     s = new_name(flatten(buf));
  247.     new_out(cmd, s);
  248.     cdebug("put result [%s] into cache\n", s);
  249.     put_trail("get_output", "finish");
  250.     return s;
  251. }
  252.  
  253. /*
  254. **    Flatten the output of commands by converting newlines to spaces
  255. **    and by removing blanks around the edges.
  256. */
  257.  
  258. char *
  259. flatten(str)
  260. reg    char    *str;
  261. {
  262.     reg    char    *s;
  263.  
  264.     /* convert newlines (and formfeeds) to spaces */
  265.     for (s = str; *s != '\0'; s++)
  266.         if (*s == '\n' || *s == '\f')
  267.             *s = ' ';
  268.  
  269.     /* remove blanks around the edges */
  270.     for (s = str+strlen(str)-1; str <= s && isspace(*s); s--)
  271.         *s = '\0';
  272.     for (s = str; *s != '\0' && isspace(*s); s++)
  273.         ;
  274.  
  275.     return s;
  276. }
  277.