home *** CD-ROM | disk | FTP | other *** search
- /*
- * build.c An imitation of the Unix MAKE facility
- *
- * 88-10-01 v1.0 created by greg yachuk, placed in the public domain
- * 88-10-06 v1.1 changed prerequisite list handling
- * 88-11-11 v1.2 fixed some bugs and added environment variables
- * 89-07-12 v1.3 stop appending shell commands, and flush output
- * 89-08-01 v1.4 AB lots of new options and code
- * 89-10-30 v1.5 -f -S -q options, took some changes from v1.4
- * 90-04-18 v1.6 -b -- -W options, emulate <<, non-BSD cleanup
- */
-
- #include <stdio.h>
- #include <string.h>
- #ifdef MSDOS
- #include <stdlib.h>
- #include <process.h>
- #endif
- #ifdef BSD
- #include <sys/wait.h>
- #endif
-
- #include "make.h"
- #include "tstring.h"
- #include "decl.h"
-
- #ifndef MSDOS
- char **bsearch();
- #endif
-
- char *tmpfn = NULL;
- #define shellunlink() if(tmpfn!=NULL)unlink(tmpfn),tfree(tmpfn),tmpfn=NULL
-
- /*
- * shell_cmpr - comparison routine for "shell command" binary search.
- */
- shell_cmpr(key, list)
- char *key;
- char **list;
- {
- return (strcmp(key, *list));
- }
-
- /*
- * build - process the shell commands
- */
- build(shellp)
- shellptr *shellp;
- {
- char **argv; /* argified version of scmd */
- int runst; /* exec return status */
- char *scmd; /* command with symbols broken out */
- char *tcmd; /* copy of scmd for `tokenize' */
- char *errnum; /* error number in ascii */
- char *errmsg; /* error message */
- int i;
- char *sp;
- char *tp;
- char **shcp; /* pointer to shell command list */
-
- if (shellp == NULL || opts.query)
- return (0);
-
- /* process every shell line */
-
- for (; *shellp != NULL;
- tfree(scmd), tfree(tcmd), tfree(argv), ++shellp)
- {
- /* breakout runtime symbols (e.g. $* $@ $<) */
- scmd = breakout((*shellp)->scmd);
-
- /* make a copy because tokenize litters '\0's */
- tcmd = tstrcpy(scmd);
- argv = tokenize(tcmd);
-
- for (tp = scmd, i = 0; argv[i]; i++)
- {
- /* pretend to handle inline input ("<<" operator) */
- while ((sp = strchr(argv[i], '<')) != NULL)
- {
- if (*++sp != '<')
- continue;
-
- sp[-1] = '\0';
-
- /* got "<<". collect commands into a file */
- if (*++sp != '\0') /* got "<<TAG" */
- sp = shellinput(&shellp, sp);
- else
- {
- /* got "<< TAG" (note space before TAG) */
- sp = shellinput(&shellp, argv[i + 1]);
- if (argv[i + 1])
- {
- tfree(argv[i + 1]);
- argv[i + 1] = tstrcpy("");
- }
- }
-
- /* add the filename to the argument */
- sp = tstrcat(argv[i], sp);
- tfree(argv[i]);
- argv[i] = sp;
- }
-
- /* now strip the quotes from the argument */
- strcpy(tp, tunquote(argv[i]));
- while (*tp++);
- tp[-1] = ' ';
- }
-
- /* finally, terminate the command line (scmd) */
- tp[-1] = '\0';
-
- if (!opts.silent && (opts.noexec || !(*shellp)->s_silent))
- {
- puts(scmd);
- fflush(stdout);
- }
-
- /* look for $(MAKE) */
- if (equal(argv[0], opts.make))
- {
- /* call ourselves recursively */
- new_make(argv);
- continue;
- }
-
- if (opts.noexec)
- continue;
-
- /* any SHELL meta-characters MUST be handled by the shell */
- if (!(*shellp)->s_shell && strpbrk(scmd, SHELL_METAS))
- (*shellp)->s_shell = 1;
-
- if (shell_cmds && !(*shellp)->s_shell)
- {
- /* check for COMMAND.COM builtin commands */
- for (shcp = shell_cmds; *shcp; ++shcp);
- shcp = bsearch(argv[0], shell_cmds,
- shcp - shell_cmds - 1,
- sizeof(char *), shell_cmpr);
- (*shellp)->s_shell = (shcp != NULL);
- }
-
- /* run without COMMAND.COM if possible, 'cause it uses RAM */
- if (!(*shellp)->s_shell)
- runst = spawnvp(P_WAIT, argv[0], argv);
- else
- runst = system(scmd);
-
- shellunlink();
-
- if (runst == 0)
- continue;
-
- /* uh-oh, an error */
- if (runst == -1)
- perror("make");
-
- errnum = talloc(18);
- #ifdef MSDOS
- errnum = itoa(runst, errnum, 10);
- #else
- sprintf(errnum, "%d", runst);
- #endif
- errmsg = (opts.keepon) ? "\007*** Ignoring Error code "
- : "\007*** Error code ";
- errmsg = tstrcat(errmsg, errnum);
- terror(0, errmsg);
- tfree(errmsg);
- tfree(errnum);
-
- if (opts.keepon)
- return (1);
-
- if (!opts.ignore && !(*shellp)->s_ignore)
- exit(1);
- }
-
- return (0);
- }
-
-
- /*
- * shellinput - write the list of commands into a temp file, and return name
- */
- char *shellinput(shellp, eof)
- shellptr **shellp;
- char *eof;
- {
- int eoflen;
- char *scmd;
- FILE *tfp;
-
- /* get rid of obvious errors */
- if (shellp == NULL || *shellp == NULL)
- return (NULL);
-
- eoflen = (eof) ? strlen(eof) : 0;
-
- /* find the name of a candidate temporary file */
- tmpfn = tempnam(NULL, "mk");
-
- /* write contents to stdout when '-n' is specified */
- if (opts.noexec && !opts.silent && !(**shellp)->s_silent)
- tfp = stdout;
- else
- tfp = fopen(tmpfn, "w");
-
- while (*++*shellp)
- {
- /* break out the current shell command */
- scmd = breakout((**shellp)->scmd);
-
- /* propogate the shell command attributes */
- (**shellp)->s_silent = ((*shellp)[-1])->s_silent;
- (**shellp)->s_ignore = ((*shellp)[-1])->s_ignore;
- (**shellp)->s_shell = ((*shellp)[-1])->s_shell;
-
- /* see if we've reached the eof-word */
- if (eof && !strncmp(scmd, eof, eoflen))
- break;
-
- /* no there, so write out the command to the temp file */
- if (tfp)
- {
- fputs(scmd, tfp);
- fputc('\n', tfp);
- }
-
- /* free the string allocated by breakout() */
- tfree(scmd);
- }
-
- if (tfp != stdout)
- fclose(tfp);
-
- if (**shellp == NULL)
- --* shellp; /* point at last shell command */
- else
- tfree(scmd); /* free EOF-word */
-
- return (tmpfn);
- }
-
-
- /*
- * new_make - save current environment
- * - call make() recursively (actually main())
- * - clean up new environment
- * - restore environment
- */
- new_make(argv)
- char **argv;
- {
- targptr thead, tnext, tsuffix;
- fileptr fhead, fnext;
- symptr shead, snext;
- shellptr shhead, shnext;
- char **shcmds;
- char **ttlist;
- long tnow;
- optnode topts;
- int i;
-
- /* save all the globals */
- tsuffix = suffix_targ;
- thead = target_list;
- fhead = file_list;
- shead = symbol_list;
- shhead = shell_list;
- shcmds = shell_cmds;
- ttlist = tlist;
- tnow = now;
- topts = opts;
-
- /* count the arguments */
- for (i = 0; argv[i]; ++i)
- tunquote(argv[i]);
-
- /* call ourselves recursively; this inherits flags */
- ++make_level;
- main(i, argv);
- --make_level;
-
- /* we're back, so gotta clean up and dispose of a few things */
- while (target_list)
- {
- tnext = target_list->tnext;
- if (target_list->tpreq)
- tfree(target_list->tpreq);
- if (target_list->tshell)
- tfree(target_list->tshell);
- tfree(target_list);
- target_list = tnext;
- }
-
- while (file_list)
- {
- fnext = file_list->fnext;
- tfree(file_list->fname);
- tfree(file_list);
- file_list = fnext;
- }
-
- /* don't drop all symbols, just the new ones */
-
- while (symbol_list != shead)
- {
- snext = symbol_list->snext;
- tfree(symbol_list->sname);
- tfree(symbol_list->svalue);
- tfree(symbol_list);
- symbol_list = snext;
- }
-
- while (shell_list)
- {
- shnext = shell_list->slink;
- tfree(shell_list->scmd);
- tfree(shell_list);
- shell_list = shnext;
- }
-
- /* restore our original globals */
- suffix_targ = tsuffix;
- target_list = thead;
- file_list = fhead;
- symbol_list = shead;
- shell_list = shhead;
- shell_cmds = shcmds;
- tlist = ttlist;
- now = tnow;
- opts = topts;
- }
-
-
- #ifndef MSDOS
- int spawnvp(mode, path, args)
- int mode;
- char *path;
- char **args;
- {
- int pid = 0;
- int retpid;
- #ifdef BSD
- union wait waitword;
- #else
- int waitword;
- #endif
-
- if (mode != P_OVERLAY)
- pid = fork();
-
- if (pid == 0)
- execvp(path, args);
-
- while (((retpid = wait(&waitword)) != pid) && (retpid > 0))
- ;
- #ifdef BSD
- return ((retpid == pid) ? waitword.w_retcode : (-1));
- #else
- return ((retpid == pid) ? ((waitword >> 8) & 0x00ff) : (-1));
- #endif
- }
- #endif
-