home *** CD-ROM | disk | FTP | other *** search
- /*
- ** EMAKE
- ** Run /lib/cpp over Dmakefile (if necessary), then call make.
- ** There is a prolog file, the Dmakefile, and the epilog file;
- ** see the List variable to set these.
- **
- ** This creates a makefile called MakeAuto, so you don't have to
- ** spend all that silly time in cpp if the Dmakefile hasn't changed.
- */
- #include <stdio.h>
- #include <errno.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/file.h>
-
- #ifdef WAIT_UNION
- #include <sys/wait.h>
- #define WAITVALUE(W) ((W).w_retcode)
- typedef union wait WAITER;
- #else
- #define WAITVALUE(W) ((W) >> 8)
- typedef int WAITER;
- #endif /* WAIT_UNION */
-
-
- /*
- ** Handy shorthands.
- */
- #define STDOUT 1
- #define STDERR 2
- #define WHITE(c) ((c) == ' ' || (c) == '\t')
- #define WRITE(s) (void)write(STDERR, s, sizeof s - 1);
-
-
- /*
- ** Datatype and variable to hold the list of CPP directives that we should
- ** pass through (make's comment character is '#', which clashes).
- */
- typedef struct {
- char Value[8];
- int Length;
- } ALIST;
-
- ALIST Directives[] = {
- { "include", 7 }, { "define", 6 }, { "ifndef", 6 },
- { "ifdef", 5 }, { "undef", 5 }, { "endif", 5 },
- { "else", 4 }, { "line", 4 }, { "if", 2},
- { "", -1 }
- };
-
- /* Other globals. */
- char TempInput[] = "MakeIXXXXXX"; /* CPP input file */
- char TempOutput[] = "MakeOXXXXXX"; /* CPP output file */
- char DMAKEFILE[] = "Dmakefile"; /* Emake's makefile */
- char MAKEFILE[] = "MakeAuto"; /* Generated makefile */
- char *List[] = { /* Sources for emake */
- "/usr/cronus/clib/dmakedefs", DMAKEFILE, "/usr/cronus/clib/dtargets", NULL
- };
-
- /* Linked in later. */
- extern int errno;
- extern char *mktemp();
- extern char *malloc();
-
-
- /*
- ** Print error message, clean up, and die.
- */
- void
- Quit(s)
- char *s;
- {
- perror(s);
- #ifndef DEBUG
- if ((unlink(TempInput) < 0 && errno != ENOENT)
- || (unlink(TempOutput) < 0 && errno != ENOENT))
- perror("Error in QUIT cleanup");
- #endif /* DEBUG */
- _exit(1);
- }
-
-
- /*
- ** Pre-process the input files, building the make control file.
- */
- void
- Prepare(Cargv)
- char **Cargv;
- {
- register ALIST *D;
- register FILE *F;
- register FILE *In;
- register char *p;
- register int i;
- register int j;
- WAITER W;
- char **Name;
- char buff[BUFSIZ];
-
- /* Create tempfile for CPP input. */
- if ((F = fopen(TempInput, "w")) == NULL)
- Quit(TempInput);
-
- /* Write each input file to the temporary output. */
- for (Name = List; *Name; Name++) {
- if ((In = fopen(*Name, "r")) == NULL)
- Quit(*Name);
-
- /* Read input, eliding #foo lines if foo is not a cpp directive. */
- while (fgets(buff, sizeof buff, In))
- if (buff[0] != '#')
- (void)fputs(buff, F);
- else {
- for (p = &buff[1]; *p && WHITE(*p); p++)
- p++;
- for (i = strlen(p), D = Directives; D->Length >= 0; D++)
- if (i > D->Length
- && strncmp(p, D->Value, D->Length) == 0
- && WHITE(p[D->Length])) {
- (void)fputs(buff, F);
- break;
- }
- }
-
- (void)fclose(In);
- }
- (void)fclose(F);
-
- /* Create a file to hold the cpp output. */
- i = open(TempOutput, O_WRONLY | O_TRUNC | O_CREAT, 0666);
-
- /* Call the pre-processor. */
- if ((j = fork()) == 0) {
- /* I tried to use dup() and dup2(), but they didn't work... */
- if (close(STDOUT) < 0 || dup(i) != STDOUT)
- perror("Error in CPP redirection");
- execv(Cargv[0], Cargv);
- perror(Cargv[0]);
- _exit(1);
- }
-
- /* Wait for it. */
- while (wait(&W) != j)
- ;
- if (WAITVAL(W))
- Quit("CPP failure");
-
- /* Copy cpp output to MAKEFILE, eliding all "#" lines. */
- (void)close(i);
- if ((In = fopen(TempOutput, "r")) == NULL
- || (F = fopen(MAKEFILE, "w")) == NULL)
- Quit("Scanning cpp output");
- (void)fputs("## HANDS OFF THIS FILE--IT WAS AUTOMATICALLY CREATED!!\n", F);
- while (fgets(buff, sizeof buff, In))
- if (buff[0] != '#')
- for (p = buff; *p && *p != '\n'; p++)
- if (!WHITE(*p)) {
- (void)fputs(buff, F);
- break;
- }
- (void)fclose(In);
- (void)fclose(F);
- if (unlink(TempInput) < 0 || unlink(TempOutput) < 0)
- perror("Error in cleaning up temp files");
- }
-
-
- main(ac, av)
- int ac;
- register char *av[];
- {
- register char **Margv;
- register char **Cargv;
- register char *p;
- register int Mcount;
- register int Ccount;
- register int Force;
- struct stat Sb1;
- struct stat Sb2;
-
- /* Is it all there? */
- if (stat(DMAKEFILE, &Sb1) < 0)
- Quit("Required file Dmakefile is missing");
-
- /* Is Dmakefile newer than MakeFile? */
- Force = stat(MAKEFILE, &Sb2) < 0 || Sb1.st_mtime >= Sb2.st_mtime;
-
- /* Build argument list stubs. */
- Margv = (char **)malloc((unsigned int)(ac + 4) * sizeof (char *));
- Margv[0] = "make";
- Margv[1] = "-f";
- Margv[2] = MAKEFILE;
- Cargv = (char **)malloc((unsigned int)(ac + 3) * sizeof (char *));
- Cargv[0] = "/lib/cpp";
- Cargv[1] = "-I/usr/cronus/include";
-
- /* Create spool files. */
- (void)mktemp(TempInput);
- (void)mktemp(TempOutput);
-
- /* Scan arg list, moving "-Dxxx" to cpp, all other stuff to make. */
- for (Mcount = 3, Ccount = 2; p = *++av; )
- if (p[0] == '-' && p[1] == 'D') {
- Force++;
- Cargv[Ccount++] = p;
- }
- else
- Margv[Mcount++] = p;
- Cargv[Ccount++] = TempInput;
- Cargv[Ccount] = NULL;
- Margv[Mcount] = NULL;
-
- /* Rebuild MAKEFILE if necessary. */
- if (Force) {
- static char REBUILD[] = "Rebuilding...";
- static char DONE[] = " done\n";
-
- WRITE(REBUILD);
- Prepare(Cargv);
- WRITE(DONE);
- }
-
- /* Now have make do the real work. */
- (void)execvp(Margv[0], Margv);
- Quit(Margv[0]);
- }
-