home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / tools / make / pdmake / build.c next >
Encoding:
C/C++ Source or Header  |  1990-07-06  |  7.4 KB  |  368 lines

  1. /*
  2.  * build.c    An imitation of the Unix MAKE facility
  3.  *
  4.  * 88-10-01 v1.0    created by greg yachuk, placed in the public domain
  5.  * 88-10-06 v1.1    changed prerequisite list handling
  6.  * 88-11-11 v1.2    fixed some bugs and added environment variables
  7.  * 89-07-12 v1.3    stop appending shell commands, and flush output
  8.  * 89-08-01 v1.4 AB    lots of new options and code
  9.  * 89-10-30 v1.5    -f -S -q options, took some changes from v1.4
  10.  * 90-04-18 v1.6    -b -- -W options, emulate <<, non-BSD cleanup
  11.  */
  12.  
  13. #include <stdio.h>
  14. #include <string.h>
  15. #ifdef    MSDOS
  16. #include <stdlib.h>
  17. #include <process.h>
  18. #endif
  19. #ifdef    BSD
  20. #include <sys/wait.h>
  21. #endif
  22.  
  23. #include "make.h"
  24. #include "tstring.h"
  25. #include "decl.h"
  26.  
  27. #ifndef    MSDOS
  28. char  **bsearch();
  29. #endif
  30.  
  31. char   *tmpfn = NULL;
  32. #define    shellunlink()    if(tmpfn!=NULL)unlink(tmpfn),tfree(tmpfn),tmpfn=NULL
  33.  
  34. /*
  35.  * shell_cmpr    - comparison routine for "shell command" binary search.
  36.  */
  37. shell_cmpr(key, list)
  38. char   *key;
  39. char  **list;
  40. {
  41.     return (strcmp(key, *list));
  42. }
  43.  
  44. /*
  45.  * build    - process the shell commands
  46.  */
  47. build(shellp)
  48. shellptr *shellp;
  49. {
  50.     char  **argv;        /* argified version of scmd */
  51.     int     runst;        /* exec return status */
  52.     char   *scmd;        /* command with symbols broken out */
  53.     char   *tcmd;        /* copy of scmd for `tokenize' */
  54.     char   *errnum;        /* error number in ascii */
  55.     char   *errmsg;        /* error message */
  56.     int     i;
  57.     char   *sp;
  58.     char   *tp;
  59.     char  **shcp;        /* pointer to shell command list */
  60.  
  61.     if (shellp == NULL || opts.query)
  62.         return (0);
  63.  
  64.     /* process every shell line */
  65.  
  66.     for (; *shellp != NULL;
  67.          tfree(scmd), tfree(tcmd), tfree(argv), ++shellp)
  68.     {
  69.         /* breakout runtime symbols (e.g. $* $@ $<) */
  70.         scmd = breakout((*shellp)->scmd);
  71.  
  72.         /* make a copy because tokenize litters '\0's */
  73.         tcmd = tstrcpy(scmd);
  74.         argv = tokenize(tcmd);
  75.  
  76.         for (tp = scmd, i = 0; argv[i]; i++)
  77.         {
  78.             /* pretend to handle inline input ("<<" operator) */
  79.             while ((sp = strchr(argv[i], '<')) != NULL)
  80.             {
  81.                 if (*++sp != '<')
  82.                     continue;
  83.  
  84.                 sp[-1] = '\0';
  85.  
  86.                 /* got "<<".  collect commands into a file */
  87.                 if (*++sp != '\0')    /* got "<<TAG" */
  88.                     sp = shellinput(&shellp, sp);
  89.                 else
  90.                 {
  91.                     /* got "<< TAG" (note space before TAG) */
  92.                     sp = shellinput(&shellp, argv[i + 1]);
  93.                     if (argv[i + 1])
  94.                     {
  95.                         tfree(argv[i + 1]);
  96.                         argv[i + 1] = tstrcpy("");
  97.                     }
  98.                 }
  99.  
  100.                 /* add the filename to the argument */
  101.                 sp = tstrcat(argv[i], sp);
  102.                 tfree(argv[i]);
  103.                 argv[i] = sp;
  104.             }
  105.  
  106.             /* now strip the quotes from the argument */
  107.             strcpy(tp, tunquote(argv[i]));
  108.             while (*tp++);
  109.             tp[-1] = ' ';
  110.         }
  111.  
  112.         /* finally, terminate the command line (scmd) */
  113.         tp[-1] = '\0';
  114.  
  115.         if (!opts.silent && (opts.noexec || !(*shellp)->s_silent))
  116.         {
  117.             puts(scmd);
  118.             fflush(stdout);
  119.         }
  120.  
  121.         /* look for $(MAKE) */
  122.         if (equal(argv[0], opts.make))
  123.         {
  124.             /* call ourselves recursively */
  125.             new_make(argv);
  126.             continue;
  127.         }
  128.  
  129.         if (opts.noexec)
  130.             continue;
  131.  
  132.         /* any SHELL meta-characters MUST be handled by the shell */
  133.         if (!(*shellp)->s_shell && strpbrk(scmd, SHELL_METAS))
  134.             (*shellp)->s_shell = 1;
  135.  
  136.         if (shell_cmds && !(*shellp)->s_shell)
  137.         {
  138.             /* check for COMMAND.COM builtin commands */
  139.             for (shcp = shell_cmds; *shcp; ++shcp);
  140.             shcp = bsearch(argv[0], shell_cmds,
  141.                        shcp - shell_cmds - 1,
  142.                        sizeof(char *), shell_cmpr);
  143.             (*shellp)->s_shell = (shcp != NULL);
  144.         }
  145.  
  146.         /* run without COMMAND.COM if possible, 'cause it uses RAM */
  147.         if (!(*shellp)->s_shell)
  148.             runst = spawnvp(P_WAIT, argv[0], argv);
  149.         else
  150.             runst = system(scmd);
  151.  
  152.         shellunlink();
  153.  
  154.         if (runst == 0)
  155.             continue;
  156.  
  157.         /* uh-oh, an error */
  158.         if (runst == -1)
  159.             perror("make");
  160.  
  161.         errnum = talloc(18);
  162. #ifdef    MSDOS
  163.         errnum = itoa(runst, errnum, 10);
  164. #else
  165.         sprintf(errnum, "%d", runst);
  166. #endif
  167.         errmsg = (opts.keepon) ? "\007*** Ignoring Error code "
  168.             : "\007*** Error code ";
  169.         errmsg = tstrcat(errmsg, errnum);
  170.         terror(0, errmsg);
  171.         tfree(errmsg);
  172.         tfree(errnum);
  173.  
  174.         if (opts.keepon)
  175.             return (1);
  176.  
  177.         if (!opts.ignore && !(*shellp)->s_ignore)
  178.             exit(1);
  179.     }
  180.  
  181.     return (0);
  182. }
  183.  
  184.  
  185. /*
  186.  * shellinput    - write the list of commands into a temp file, and return name
  187.  */
  188. char   *shellinput(shellp, eof)
  189. shellptr **shellp;
  190. char   *eof;
  191. {
  192.     int     eoflen;
  193.     char   *scmd;
  194.     FILE   *tfp;
  195.  
  196.     /* get rid of obvious errors */
  197.     if (shellp == NULL || *shellp == NULL)
  198.         return (NULL);
  199.  
  200.     eoflen = (eof) ? strlen(eof) : 0;
  201.  
  202.     /* find the name of a candidate temporary file */
  203.     tmpfn = tempnam(NULL, "mk");
  204.  
  205.     /* write contents to stdout when '-n' is specified */
  206.     if (opts.noexec && !opts.silent && !(**shellp)->s_silent)
  207.         tfp = stdout;
  208.     else
  209.         tfp = fopen(tmpfn, "w");
  210.  
  211.     while (*++*shellp)
  212.     {
  213.         /* break out the current shell command */
  214.         scmd = breakout((**shellp)->scmd);
  215.  
  216.         /* propogate the shell command attributes */
  217.         (**shellp)->s_silent = ((*shellp)[-1])->s_silent;
  218.         (**shellp)->s_ignore = ((*shellp)[-1])->s_ignore;
  219.         (**shellp)->s_shell = ((*shellp)[-1])->s_shell;
  220.  
  221.         /* see if we've reached the eof-word */
  222.         if (eof && !strncmp(scmd, eof, eoflen))
  223.             break;
  224.  
  225.         /* no there, so write out the command to the temp file */
  226.         if (tfp)
  227.         {
  228.             fputs(scmd, tfp);
  229.             fputc('\n', tfp);
  230.         }
  231.  
  232.         /* free the string allocated by breakout() */
  233.         tfree(scmd);
  234.     }
  235.  
  236.     if (tfp != stdout)
  237.         fclose(tfp);
  238.  
  239.     if (**shellp == NULL)
  240.         --* shellp;    /* point at last shell command */
  241.     else
  242.         tfree(scmd);    /* free EOF-word */
  243.  
  244.     return (tmpfn);
  245. }
  246.  
  247.  
  248. /*
  249.  * new_make    - save current environment
  250.  *        - call make() recursively (actually main())
  251.  *        - clean up new environment
  252.  *        - restore environment
  253.  */
  254. new_make(argv)
  255. char  **argv;
  256. {
  257.     targptr thead, tnext, tsuffix;
  258.     fileptr fhead, fnext;
  259.     symptr  shead, snext;
  260.     shellptr shhead, shnext;
  261.     char  **shcmds;
  262.     char  **ttlist;
  263.     long    tnow;
  264.     optnode topts;
  265.     int     i;
  266.  
  267.     /* save all the globals */
  268.     tsuffix = suffix_targ;
  269.     thead = target_list;
  270.     fhead = file_list;
  271.     shead = symbol_list;
  272.     shhead = shell_list;
  273.     shcmds = shell_cmds;
  274.     ttlist = tlist;
  275.     tnow = now;
  276.     topts = opts;
  277.  
  278.     /* count the arguments */
  279.     for (i = 0; argv[i]; ++i)
  280.         tunquote(argv[i]);
  281.  
  282.     /* call ourselves recursively; this inherits flags */
  283.     ++make_level;
  284.     main(i, argv);
  285.     --make_level;
  286.  
  287.     /* we're back, so gotta clean up and dispose of a few things */
  288.     while (target_list)
  289.     {
  290.         tnext = target_list->tnext;
  291.         if (target_list->tpreq)
  292.             tfree(target_list->tpreq);
  293.         if (target_list->tshell)
  294.             tfree(target_list->tshell);
  295.         tfree(target_list);
  296.         target_list = tnext;
  297.     }
  298.  
  299.     while (file_list)
  300.     {
  301.         fnext = file_list->fnext;
  302.         tfree(file_list->fname);
  303.         tfree(file_list);
  304.         file_list = fnext;
  305.     }
  306.  
  307.     /* don't drop all symbols, just the new ones */
  308.  
  309.     while (symbol_list != shead)
  310.     {
  311.         snext = symbol_list->snext;
  312.         tfree(symbol_list->sname);
  313.         tfree(symbol_list->svalue);
  314.         tfree(symbol_list);
  315.         symbol_list = snext;
  316.     }
  317.  
  318.     while (shell_list)
  319.     {
  320.         shnext = shell_list->slink;
  321.         tfree(shell_list->scmd);
  322.         tfree(shell_list);
  323.         shell_list = shnext;
  324.     }
  325.  
  326.     /* restore our original globals */
  327.     suffix_targ = tsuffix;
  328.     target_list = thead;
  329.     file_list = fhead;
  330.     symbol_list = shead;
  331.     shell_list = shhead;
  332.     shell_cmds = shcmds;
  333.     tlist = ttlist;
  334.     now = tnow;
  335.     opts = topts;
  336. }
  337.  
  338.  
  339. #ifndef    MSDOS
  340. int     spawnvp(mode, path, args)
  341. int     mode;
  342. char   *path;
  343. char  **args;
  344. {
  345.     int     pid = 0;
  346.     int     retpid;
  347. #ifdef    BSD
  348.     union wait waitword;
  349. #else
  350.     int     waitword;
  351. #endif
  352.  
  353.     if (mode != P_OVERLAY)
  354.         pid = fork();
  355.  
  356.     if (pid == 0)
  357.         execvp(path, args);
  358.  
  359.     while (((retpid = wait(&waitword)) != pid) && (retpid > 0))
  360.         ;
  361. #ifdef    BSD
  362.     return ((retpid == pid) ? waitword.w_retcode : (-1));
  363. #else
  364.     return ((retpid == pid) ? ((waitword >> 8) & 0x00ff) : (-1));
  365. #endif
  366. }
  367. #endif
  368.