home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume2 / emake / emake.c
Encoding:
C/C++ Source or Header  |  1991-08-07  |  5.5 KB  |  227 lines

  1. /*
  2. **  EMAKE
  3. **  Run /lib/cpp over Dmakefile (if necessary), then call make.
  4. **  There is a prolog file, the Dmakefile, and the epilog file;
  5. **  see the List variable to set these.
  6. **
  7. **  This creates a makefile called MakeAuto, so you don't have to
  8. **  spend all that silly time in cpp if the Dmakefile hasn't changed.
  9. */
  10. #include <stdio.h>
  11. #include <errno.h>
  12. #include <sys/types.h>
  13. #include <sys/stat.h>
  14. #include <sys/file.h>
  15.  
  16. #ifdef    WAIT_UNION
  17. #include <sys/wait.h>
  18. #define WAITVALUE(W)        ((W).w_retcode)
  19. typedef union wait WAITER;
  20. #else
  21. #define WAITVALUE(W)        ((W) >> 8)
  22. typedef int WAITER;
  23. #endif    /* WAIT_UNION */
  24.  
  25.  
  26. /*
  27. **  Handy shorthands.
  28. */
  29. #define STDOUT        1
  30. #define STDERR        2
  31. #define WHITE(c)    ((c) == ' ' || (c) == '\t')
  32. #define WRITE(s)    (void)write(STDERR, s, sizeof s - 1);
  33.  
  34.  
  35. /*
  36. **  Datatype and variable to hold the list of CPP directives that we should
  37. **  pass through (make's comment character is '#', which clashes).
  38. */
  39. typedef struct {
  40.     char    Value[8];
  41.     int        Length;
  42. } ALIST;
  43.  
  44. ALIST      Directives[] = {
  45.     { "include", 7 },    { "define", 6 },    { "ifndef", 6 },
  46.     { "ifdef", 5 },    { "undef", 5 },        { "endif", 5 },
  47.     { "else", 4 },    { "line", 4 },        { "if", 2},
  48.     { "", -1 }
  49. };
  50.  
  51. /* Other globals. */
  52. char      TempInput[]  = "MakeIXXXXXX";    /* CPP input file        */
  53. char      TempOutput[] = "MakeOXXXXXX";    /* CPP output file        */
  54. char      DMAKEFILE[] = "Dmakefile";    /* Emake's makefile        */
  55. char      MAKEFILE[] = "MakeAuto";    /* Generated makefile        */
  56. char     *List[] = {            /* Sources for emake        */
  57.     "/usr/cronus/clib/dmakedefs", DMAKEFILE, "/usr/cronus/clib/dtargets", NULL
  58. };
  59.  
  60. /* Linked in later. */
  61. extern int     errno;
  62. extern char    *mktemp();
  63. extern char    *malloc();
  64.  
  65.  
  66. /*
  67. **  Print error message, clean up, and die.
  68. */
  69. void
  70. Quit(s)
  71.     char    *s;
  72. {
  73.     perror(s);
  74. #ifndef    DEBUG
  75.     if ((unlink(TempInput) < 0 && errno != ENOENT)
  76.      || (unlink(TempOutput) < 0 && errno != ENOENT))
  77.     perror("Error in QUIT cleanup");
  78. #endif    /* DEBUG */
  79.     _exit(1);
  80. }
  81.  
  82.  
  83. /*
  84. **  Pre-process the input files, building the make control file.
  85. */
  86. void
  87. Prepare(Cargv)
  88.     char        **Cargv;
  89. {
  90.     register ALIST     *D;
  91.     register FILE     *F;
  92.     register FILE     *In;
  93.     register char     *p;
  94.     register int      i;
  95.     register int      j;
  96.     WAITER          W;
  97.     char        **Name;
  98.     char          buff[BUFSIZ];
  99.  
  100.     /* Create tempfile for CPP input. */
  101.     if ((F = fopen(TempInput, "w")) == NULL)
  102.     Quit(TempInput);
  103.  
  104.     /* Write each input file to the temporary output. */
  105.     for (Name = List; *Name; Name++) {
  106.     if ((In = fopen(*Name, "r")) == NULL)
  107.         Quit(*Name);
  108.  
  109.     /* Read input, eliding #foo lines if foo is not a cpp directive. */
  110.     while (fgets(buff, sizeof buff, In))
  111.         if (buff[0] != '#')
  112.         (void)fputs(buff, F);
  113.         else {
  114.         for (p = &buff[1]; *p && WHITE(*p); p++)
  115.             p++;
  116.         for (i = strlen(p), D = Directives; D->Length >= 0; D++)
  117.             if (i > D->Length
  118.              && strncmp(p, D->Value, D->Length) == 0
  119.              && WHITE(p[D->Length])) {
  120.             (void)fputs(buff, F);
  121.             break;
  122.             }
  123.         }
  124.  
  125.     (void)fclose(In);
  126.     }
  127.     (void)fclose(F);
  128.  
  129.     /* Create a file to hold the cpp output. */
  130.     i = open(TempOutput, O_WRONLY | O_TRUNC | O_CREAT, 0666);
  131.  
  132.     /* Call the pre-processor. */
  133.     if ((j =  fork()) == 0) {
  134.     /* I tried to use dup() and dup2(), but they didn't work... */
  135.     if (close(STDOUT) < 0 || dup(i) != STDOUT)
  136.         perror("Error in CPP redirection");
  137.     execv(Cargv[0], Cargv);
  138.     perror(Cargv[0]);
  139.     _exit(1);
  140.     }
  141.  
  142.     /* Wait for it. */
  143.     while (wait(&W) != j)
  144.     ;
  145.     if (WAITVAL(W))
  146.     Quit("CPP failure");
  147.  
  148.     /* Copy cpp output to MAKEFILE, eliding all "#" lines. */
  149.     (void)close(i);
  150.     if ((In = fopen(TempOutput, "r")) == NULL
  151.      || (F = fopen(MAKEFILE, "w")) == NULL)
  152.     Quit("Scanning cpp output");
  153.     (void)fputs("## HANDS OFF THIS FILE--IT WAS AUTOMATICALLY CREATED!!\n", F);
  154.     while (fgets(buff, sizeof buff, In))
  155.     if (buff[0] != '#')
  156.         for (p = buff; *p && *p != '\n'; p++)
  157.         if (!WHITE(*p)) {
  158.             (void)fputs(buff, F);
  159.             break;
  160.         }
  161.     (void)fclose(In);
  162.     (void)fclose(F);
  163.     if (unlink(TempInput) < 0 || unlink(TempOutput) < 0)
  164.     perror("Error in cleaning up temp files");
  165. }
  166.  
  167.  
  168. main(ac, av)
  169.     int              ac;
  170.     register char     *av[];
  171. {
  172.     register char    **Margv;
  173.     register char    **Cargv;
  174.     register char     *p;
  175.     register int      Mcount;
  176.     register int      Ccount;
  177.     register int      Force;
  178.     struct stat          Sb1;
  179.     struct stat          Sb2;
  180.  
  181.     /* Is it all there? */
  182.     if (stat(DMAKEFILE, &Sb1) < 0)
  183.     Quit("Required file Dmakefile is missing");
  184.  
  185.     /* Is Dmakefile newer than MakeFile? */
  186.     Force = stat(MAKEFILE, &Sb2) < 0 || Sb1.st_mtime >= Sb2.st_mtime;
  187.  
  188.     /* Build argument list stubs. */
  189.     Margv = (char **)malloc((unsigned int)(ac + 4) * sizeof (char *));
  190.     Margv[0] = "make";
  191.     Margv[1] = "-f";
  192.     Margv[2] = MAKEFILE;
  193.     Cargv = (char **)malloc((unsigned int)(ac + 3) * sizeof (char *));
  194.     Cargv[0] = "/lib/cpp";
  195.     Cargv[1] = "-I/usr/cronus/include";
  196.  
  197.     /* Create spool files. */
  198.     (void)mktemp(TempInput);
  199.     (void)mktemp(TempOutput);
  200.  
  201.     /* Scan arg list, moving "-Dxxx" to cpp, all other stuff to make. */
  202.     for (Mcount = 3, Ccount = 2; p = *++av; )
  203.     if (p[0] == '-' && p[1] == 'D') {
  204.         Force++;
  205.         Cargv[Ccount++] = p;
  206.     }
  207.     else
  208.         Margv[Mcount++] = p;
  209.     Cargv[Ccount++] = TempInput;
  210.     Cargv[Ccount] = NULL;
  211.     Margv[Mcount] = NULL;
  212.  
  213.     /* Rebuild MAKEFILE if necessary. */
  214.     if (Force) {
  215.     static char    REBUILD[] = "Rebuilding...";
  216.     static char    DONE[] = "  done\n";
  217.  
  218.     WRITE(REBUILD);
  219.     Prepare(Cargv);
  220.     WRITE(DONE);
  221.     }
  222.  
  223.     /* Now have make do the real work. */
  224.     (void)execvp(Margv[0], Margv);
  225.     Quit(Margv[0]);
  226. }
  227.