home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / Fresco / build / Unix / config / imake / imake.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-12  |  24.3 KB  |  1,030 lines

  1. /* $XConsortium: imake.c,v 1.91 95/01/12 16:15:47 kaleb Exp $ */
  2.  
  3. /***************************************************************************
  4.  *                                                                         *
  5.  *                                Porting Note                             *
  6.  *                                                                         *
  7.  * Add the value of BOOTSTRAPCFLAGS to the cpp_argv table so that it will  *
  8.  * be passed to the template file.                                         *
  9.  *                                                                         *
  10.  ***************************************************************************/
  11.  
  12. /*
  13.  * 
  14. Copyright (c) 1985, 1986, 1987  X Consortium
  15.  
  16. Permission is hereby granted, free of charge, to any person obtaining a copy
  17. of this software and associated documentation files (the "Software"), to deal
  18. in the Software without restriction, including without limitation the rights
  19. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  20. copies of the Software, and to permit persons to whom the Software is
  21. furnished to do so, subject to the following conditions:
  22.  
  23. The above copyright notice and this permission notice shall be included in
  24. all copies or substantial portions of the Software.
  25.  
  26. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  27. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  28. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
  29. X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  30. AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  31. CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  32.  
  33. Except as contained in this notice, the name of the X Consortium shall not be
  34. used in advertising or otherwise to promote the sale, use or other dealings
  35. in this Software without prior written authorization from the X Consortium.
  36.  * 
  37.  * Original Author:
  38.  *    Todd Brunhoff
  39.  *    Tektronix, inc.
  40.  *    While a guest engineer at Project Athena, MIT
  41.  *
  42.  * imake: the include-make program.
  43.  *
  44.  * Usage: imake [-Idir] [-Ddefine] [-T template] [-f imakefile ] [-C Imakefile.c ] [-s] [-e] [-v] [make flags]
  45.  *
  46.  * Imake takes a template file (Imake.tmpl) and a prototype (Imakefile)
  47.  * and runs cpp on them producing a Makefile.  It then optionally runs make
  48.  * on the Makefile.
  49.  * Options:
  50.  *        -D    define.  Same as cpp -D argument.
  51.  *        -I    Include directory.  Same as cpp -I argument.
  52.  *        -T    template.  Designate a template other
  53.  *            than Imake.tmpl
  54.  *        -f    specify the Imakefile file
  55.  *        -C    specify the name to use instead of Imakefile.c
  56.  *        -s[F]    show.  Show the produced makefile on the standard
  57.  *            output.  Make is not run is this case.  If a file
  58.  *            argument is provided, the output is placed there.
  59.  *              -e[F]   execute instead of show; optionally name Makefile F
  60.  *        -v    verbose.  Show the make command line executed.
  61.  *
  62.  * Environment variables:
  63.  *        
  64.  *        IMAKEINCLUDE    Include directory to use in addition to "."
  65.  *        IMAKECPP    Cpp to use instead of /lib/cpp
  66.  *        IMAKEMAKE    make program to use other than what is
  67.  *                found by searching the $PATH variable.
  68.  * Other features:
  69.  *    imake reads the entire cpp output into memory and then scans it
  70.  *    for occurences of "@@".  If it encounters them, it replaces it with
  71.  *    a newline.  It also trims any trailing white space on output lines
  72.  *    (because make gets upset at them).  This helps when cpp expands
  73.  *    multi-line macros but you want them to appear on multiple lines.
  74.  *    It also changes occurences of "XCOMM" to "#", to avoid problems
  75.  *    with treating commands as invalid preprocessor commands.
  76.  *
  77.  *    The macros MAKEFILE and MAKE are provided as macros
  78.  *    to make.  MAKEFILE is set to imake's makefile (not the constructed,
  79.  *    preprocessed one) and MAKE is set to argv[0], i.e. the name of
  80.  *    the imake program.
  81.  *
  82.  * Theory of operation:
  83.  *   1. Determine the name of the imakefile from the command line (-f)
  84.  *    or from the content of the current directory (Imakefile or imakefile).
  85.  *    Call this <imakefile>.  This gets added to the arguments for
  86.  *    make as MAKEFILE=<imakefile>.
  87.  *   2. Determine the name of the template from the command line (-T)
  88.  *    or the default, Imake.tmpl.  Call this <template>
  89.  *   3. Determine the name of the imakeCfile from the command line (-C)
  90.  *    or the default, Imakefile.c.  Call this <imakeCfile>
  91.  *   3. Store three lines of input into <imakeCfile>:
  92.  *        #define IMAKE_TEMPLATE        " <template> "
  93.  *        #define INCLUDE_IMAKEFILE    < <imakefile> >
  94.  *        #include IMAKE_TEMPLATE
  95.  *    Start up cpp and provide it with this file.
  96.  *    Note that the define for INCLUDE_IMAKEFILE is intended for
  97.  *    use in the template file.  This implies that the imake is
  98.  *    useless unless the template file contains at least the line
  99.  *        #include INCLUDE_IMAKEFILE
  100.  *   4. Gather the output from cpp, and clean it up, expanding @@ to
  101.  *    newlines, stripping trailing white space, cpp control lines,
  102.  *    and extra blank lines, and changing XCOMM to #.  This cleaned
  103.  *    output is placed in a new file, default "Makefile", but can
  104.  *    be specified with -s or -e options.
  105.  *   5. Optionally start up make on the resulting file.
  106.  *
  107.  * The design of the template makefile should therefore be:
  108.  *    <set global macros like CFLAGS, etc.>
  109.  *    <include machine dependent additions>
  110.  *    #include INCLUDE_IMAKEFILE
  111.  *    <add any global targets like 'clean' and long dependencies>
  112.  */
  113. #include <unistd.h>
  114. #include <stdio.h>
  115. #include <ctype.h>
  116. #include "Xosdefs.h"
  117. #ifdef WIN32
  118. #include "Xw32defs.h"
  119. #endif
  120. #ifndef X_NOT_POSIX
  121. #ifndef _POSIX_SOURCE
  122. #define _POSIX_SOURCE
  123. #endif
  124. #endif
  125. #include <sys/types.h>
  126. #include <fcntl.h>
  127. #ifdef X_NOT_POSIX
  128. #ifndef WIN32
  129. #include <sys/file.h>
  130. #endif
  131. #else
  132. #include <unistd.h>
  133. #endif
  134. #if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE)
  135. #include <signal.h>
  136. #else
  137. #define _POSIX_SOURCE
  138. #include <signal.h>
  139. #undef _POSIX_SOURCE
  140. #endif
  141. #include <sys/stat.h>
  142. #ifndef X_NOT_POSIX
  143. #ifdef _POSIX_SOURCE
  144. #include <sys/wait.h>
  145. #else
  146. #define _POSIX_SOURCE
  147. #include <sys/wait.h>
  148. #undef _POSIX_SOURCE
  149. #endif
  150. #define waitCode(w)    WEXITSTATUS(w)
  151. #define waitSig(w)    WTERMSIG(w)
  152. typedef int        waitType;
  153. #else /* X_NOT_POSIX */
  154. #ifdef SYSV
  155. #define waitCode(w)    (((w) >> 8) & 0x7f)
  156. #define waitSig(w)    ((w) & 0xff)
  157. typedef int        waitType;
  158. #else /* SYSV */
  159. #ifdef WIN32
  160. #include <process.h>
  161. typedef int        waitType;
  162. #else
  163. #include <sys/wait.h>
  164. #define waitCode(w)    ((w).w_T.w_Retcode)
  165. #define waitSig(w)    ((w).w_T.w_Termsig)
  166. typedef union wait    waitType;
  167. #endif
  168. #endif
  169. #ifndef WIFSIGNALED
  170. #define WIFSIGNALED(w) waitSig(w)
  171. #endif
  172. #ifndef WIFEXITED
  173. #define WIFEXITED(w) waitCode(w)
  174. #endif
  175. #endif /* X_NOT_POSIX */
  176. #ifndef X_NOT_STDC_ENV
  177. #include <stdlib.h>
  178. #else
  179. char *malloc(), *realloc();
  180. void exit();
  181. #endif
  182. #if defined(macII) && !defined(__STDC__)  /* stdlib.h fails to define these */
  183. char *malloc(), *realloc();
  184. #endif /* macII */
  185. #ifdef X_NOT_STDC_ENV
  186. extern char    *getenv();
  187. #endif
  188. #include <errno.h>
  189. #ifdef X_NOT_STDC_ENV
  190. extern int    errno;
  191. #endif
  192. #include "imakemdep.h"
  193.  
  194.  
  195. #define    TRUE        1
  196. #define    FALSE        0
  197.  
  198. #ifdef FIXUP_CPP_WHITESPACE
  199. int    InRule = FALSE;
  200. #ifdef INLINE_SYNTAX
  201. int    InInline = 0;
  202. #endif
  203. #endif
  204. #ifdef MAGIC_MAKE_VARS
  205. int xvariable = 0;
  206. int xvariables[10];
  207. #endif
  208.  
  209. /*
  210.  * Some versions of cpp reduce all tabs in macro expansion to a single
  211.  * space.  In addition, the escaped newline may be replaced with a
  212.  * space instead of being deleted.  Blech.
  213.  */
  214. #ifdef FIXUP_CPP_WHITESPACE
  215. void KludgeOutputLine(), KludgeResetRule();
  216. #else
  217. #define KludgeOutputLine(arg)
  218. #define KludgeResetRule()
  219. #endif
  220.  
  221. typedef    unsigned char    boolean;
  222.  
  223. #ifdef USE_CC_E
  224. #ifndef DEFAULT_CC
  225. #define DEFAULT_CC "cc"
  226. #endif
  227. #else
  228. #ifndef DEFAULT_CPP
  229. #ifdef CPP_PROGRAM
  230. #define DEFAULT_CPP CPP_PROGRAM
  231. #else
  232. #define DEFAULT_CPP "/lib/cpp"
  233. #endif
  234. #endif
  235. #endif
  236.  
  237. char *cpp = NULL;
  238.  
  239. char    *tmpMakefile    = "/tmp/Imf.XXXXXX";
  240. char    *tmpImakefile    = "/tmp/IIf.XXXXXX";
  241. char    *make_argv[ ARGUMENTS ] = {
  242. #ifdef WIN32
  243.     "nmake"
  244. #else
  245.     "make"
  246. #endif
  247. };
  248.  
  249. int    make_argindex;
  250. int    cpp_argindex;
  251. char    *Imakefile = NULL;
  252. char    *Makefile = "Makefile";
  253. char    *Template = "Imake.tmpl";
  254. char    *ImakefileC = "Imakefile.c";
  255. boolean haveImakefileC = FALSE;
  256. char    *cleanedImakefile = NULL;
  257. char    *program;
  258. char    *FindImakefile();
  259. char    *ReadLine();
  260. char    *CleanCppInput();
  261. char    *Strdup();
  262. char    *Emalloc();
  263. void    LogFatalI(), LogFatal();
  264.  
  265. boolean    verbose = FALSE;
  266. boolean    show = TRUE;
  267.  
  268. main(argc, argv)
  269.     int    argc;
  270.     char    **argv;
  271. {
  272.     FILE    *tmpfd;
  273.     char    makeMacro[ BUFSIZ ];
  274.     char    makefileMacro[ BUFSIZ ];
  275.  
  276.     program = argv[0];
  277.     init();
  278.     SetOpts(argc, argv);
  279.  
  280.     Imakefile = FindImakefile(Imakefile);
  281.     CheckImakefileC(ImakefileC);
  282.     if (Makefile)
  283.         tmpMakefile = Makefile;
  284.     else {
  285.         tmpMakefile = Strdup(tmpMakefile);
  286.         (void) mktemp(tmpMakefile);
  287.     }
  288.     AddMakeArg("-f");
  289.     AddMakeArg( tmpMakefile );
  290.     sprintf(makeMacro, "MAKE=%s", program);
  291.     AddMakeArg( makeMacro );
  292.     sprintf(makefileMacro, "MAKEFILE=%s", Imakefile);
  293.     AddMakeArg( makefileMacro );
  294.  
  295.     if ((tmpfd = fopen(tmpMakefile, "w+")) == NULL)
  296.         LogFatal("Cannot create temporary file %s.", tmpMakefile);
  297.  
  298.     cleanedImakefile = CleanCppInput(Imakefile);
  299.     cppit(cleanedImakefile, Template, ImakefileC, tmpfd, tmpMakefile);
  300.  
  301.     if (show) {
  302.         if (Makefile == NULL)
  303.             showit(tmpfd);
  304.     } else
  305.         makeit();
  306.     wrapup();
  307.     exit(0);
  308. }
  309.  
  310. showit(fd)
  311.     FILE    *fd;
  312. {
  313.     char    buf[ BUFSIZ ];
  314.     int    red;
  315.  
  316.     fseek(fd, 0, 0);
  317.     while ((red = fread(buf, 1, BUFSIZ, fd)) > 0)
  318.         writetmpfile(stdout, buf, red, "stdout");
  319.     if (red < 0)
  320.         LogFatal("Cannot read %s.", tmpMakefile);
  321. }
  322.  
  323. wrapup()
  324. {
  325.     if (tmpMakefile != Makefile)
  326.         unlink(tmpMakefile);
  327.     if (cleanedImakefile && cleanedImakefile != Imakefile)
  328.         unlink(cleanedImakefile);
  329.     if (haveImakefileC)
  330.         unlink(ImakefileC);
  331. }
  332.  
  333. #ifdef SIGNALRETURNSINT
  334. int
  335. #else
  336. void
  337. #endif
  338. catch(sig)
  339.     int    sig;
  340. {
  341.     errno = 0;
  342.     LogFatalI("Signal %d.", sig);
  343. }
  344.  
  345. /*
  346.  * Initialize some variables.
  347.  */
  348. init()
  349. {
  350.     register char    *p;
  351.  
  352.     make_argindex=0;
  353.     while (make_argv[ make_argindex ] != NULL)
  354.         make_argindex++;
  355.     cpp_argindex = 0;
  356.     while (cpp_argv[ cpp_argindex ] != NULL)
  357.         cpp_argindex++;
  358.  
  359.     /*
  360.      * See if the standard include directory is different than
  361.      * the default.  Or if cpp is not the default.  Or if the make
  362.      * found by the PATH variable is not the default.
  363.      */
  364.     if (p = getenv("IMAKEINCLUDE")) {
  365.         if (*p != '-' || *(p+1) != 'I')
  366.             LogFatal("Environment var IMAKEINCLUDE %s\n",
  367.                 "must begin with -I");
  368.         AddCppArg(p);
  369.         for (; *p; p++)
  370.             if (*p == ' ') {
  371.                 *p++ = '\0';
  372.                 AddCppArg(p);
  373.             }
  374.     }
  375.     if (p = getenv("IMAKECPP"))
  376.         cpp = p;
  377.     if (p = getenv("IMAKEMAKE"))
  378.         make_argv[0] = p;
  379.  
  380.     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  381.         signal(SIGINT, catch);
  382. }
  383.  
  384. AddMakeArg(arg)
  385.     char    *arg;
  386. {
  387.     errno = 0;
  388.     if (make_argindex >= ARGUMENTS-1)
  389.         LogFatal("Out of internal storage.", "");
  390.     make_argv[ make_argindex++ ] = arg;
  391.     make_argv[ make_argindex ] = NULL;
  392. }
  393.  
  394. AddCppArg(arg)
  395.     char    *arg;
  396. {
  397.     errno = 0;
  398.     if (cpp_argindex >= ARGUMENTS-1)
  399.         LogFatal("Out of internal storage.", "");
  400.     cpp_argv[ cpp_argindex++ ] = arg;
  401.     cpp_argv[ cpp_argindex ] = NULL;
  402. }
  403.  
  404. SetOpts(argc, argv)
  405.     int    argc;
  406.     char    **argv;
  407. {
  408.     errno = 0;
  409.     /*
  410.      * Now gather the arguments for make
  411.      */
  412.     for(argc--, argv++; argc; argc--, argv++) {
  413.         /*
  414.          * We intercept these flags.
  415.          */
  416.         if (argv[0][0] == '-') {
  417.         if (argv[0][1] == 'D') {
  418.             AddCppArg(argv[0]);
  419.         } else if (argv[0][1] == 'I') {
  420.             AddCppArg(argv[0]);
  421.         } else if (argv[0][1] == 'f') {
  422.             if (argv[0][2])
  423.             Imakefile = argv[0]+2;
  424.             else {
  425.             argc--, argv++;
  426.             if (! argc)
  427.                 LogFatal("No description arg after -f flag\n", "");
  428.             Imakefile = argv[0];
  429.             }
  430.         } else if (argv[0][1] == 's') {
  431.             if (argv[0][2])
  432.             Makefile = ((argv[0][2] == '-') && !argv[0][3]) ?
  433.                 NULL : argv[0]+2;
  434.             else {
  435.             argc--, argv++;
  436.             if (!argc)
  437.                 LogFatal("No description arg after -s flag\n", "");
  438.             Makefile = ((argv[0][0] == '-') && !argv[0][1]) ?
  439.                 NULL : argv[0];
  440.             }
  441.             show = TRUE;
  442.         } else if (argv[0][1] == 'e') {
  443.            Makefile = (argv[0][2] ? argv[0]+2 : NULL);
  444.            show = FALSE;
  445.         } else if (argv[0][1] == 'T') {
  446.             if (argv[0][2])
  447.             Template = argv[0]+2;
  448.             else {
  449.             argc--, argv++;
  450.             if (! argc)
  451.                 LogFatal("No description arg after -T flag\n", "");
  452.             Template = argv[0];
  453.             }
  454.         } else if (argv[0][1] == 'C') {
  455.             if (argv[0][2])
  456.             ImakefileC = argv[0]+2;
  457.             else {
  458.             argc--, argv++;
  459.             if (! argc)
  460.                 LogFatal("No imakeCfile arg after -C flag\n", "");
  461.             ImakefileC = argv[0];
  462.             }
  463.         } else if (argv[0][1] == 'v') {
  464.             verbose = TRUE;
  465.         } else
  466.             AddMakeArg(argv[0]);
  467.         } else
  468.         AddMakeArg(argv[0]);
  469.     }
  470. #ifdef USE_CC_E
  471.     if (!cpp)
  472.     {
  473.         AddCppArg("-E");
  474.         cpp = DEFAULT_CC;
  475.     }
  476. #else
  477.     if (!cpp)
  478.         cpp = DEFAULT_CPP;
  479. #endif
  480.     cpp_argv[0] = cpp;
  481.     AddCppArg(ImakefileC);
  482. }
  483.  
  484. char *FindImakefile(Imakefile)
  485.     char    *Imakefile;
  486. {
  487.     if (Imakefile) {
  488.         if (access(Imakefile, R_OK) < 0)
  489.             LogFatal("Cannot find %s.", Imakefile);
  490.     } else {
  491.         if (access("Imakefile", R_OK) < 0)
  492.             if (access("imakefile", R_OK) < 0)
  493.                 LogFatal("No description file.", "");
  494.             else
  495.                 Imakefile = "imakefile";
  496.         else
  497.             Imakefile = "Imakefile";
  498.     }
  499.     return(Imakefile);
  500. }
  501.  
  502. void
  503. LogFatalI(s, i)
  504.     char *s;
  505.     int i;
  506. {
  507.     /*NOSTRICT*/
  508.     LogFatal(s, (char *)i);
  509. }
  510.  
  511. void
  512. LogFatal(x0,x1)
  513.     char *x0, *x1;
  514. {
  515. #ifndef WIN32
  516.     extern char    *sys_errlist[];
  517. #endif
  518.     static boolean    entered = FALSE;
  519.  
  520.     if (entered)
  521.         return;
  522.     entered = TRUE;
  523.  
  524.     fprintf(stderr, "%s: ", program);
  525.     if (errno)
  526.         fprintf(stderr, "%s: ", sys_errlist[ errno ]);
  527.     fprintf(stderr, x0,x1);
  528.     fprintf(stderr, "  Stop.\n");
  529.     wrapup();
  530.     exit(1);
  531. }
  532.  
  533. showargs(argv)
  534.     char    **argv;
  535. {
  536.     for (; *argv; argv++)
  537.         fprintf(stderr, "%s ", *argv);
  538.     fprintf(stderr, "\n");
  539. }
  540.  
  541. #define TmplDef "#define IMAKE_TEMPLATE"
  542. #define ImakeDef "#define INCLUDE_IMAKEFILE"
  543. #define TmplInc "#include IMAKE_TEMPLATE"
  544.  
  545. CheckImakefileC(masterc)
  546.     char *masterc;
  547. {
  548.     char mkcbuf[1024];
  549.     FILE *inFile;
  550.  
  551.     if (access(masterc, F_OK) == 0) {
  552.         inFile = fopen(masterc, "r");
  553.         if (inFile == NULL)
  554.             LogFatal("Refuse to overwrite: %s", masterc);
  555.         if ((fgets(mkcbuf, sizeof(mkcbuf), inFile) &&
  556.              strncmp(mkcbuf, TmplDef, sizeof(TmplDef)-1)) ||
  557.             (fgets(mkcbuf, sizeof(mkcbuf), inFile) &&
  558.              strncmp(mkcbuf, ImakeDef, sizeof(ImakeDef)-1)) ||
  559.             (fgets(mkcbuf, sizeof(mkcbuf), inFile) &&
  560.              strncmp(mkcbuf, TmplInc, sizeof(TmplInc)-1)) ||
  561.             fgets(mkcbuf, sizeof(mkcbuf), inFile))
  562.         {
  563.             fclose(inFile);
  564.             LogFatal("Refuse to overwrite: %s", masterc);
  565.         }
  566.         fclose(inFile);
  567.     }
  568. }
  569.  
  570. cppit(imakefile, template, masterc, outfd, outfname)
  571.     char    *imakefile;
  572.     char    *template;
  573.     char    *masterc;
  574.     FILE    *outfd;
  575.     char    *outfname;
  576. {
  577.     FILE    *inFile;
  578.     int    pid;
  579.     waitType    status;
  580.  
  581.     haveImakefileC = TRUE;
  582.     inFile = fopen(masterc, "w");
  583.     if (inFile == NULL)
  584.         LogFatal("Cannot open %s for output.", masterc);
  585.     if (fprintf(inFile, "%s \"%s\"\n", TmplDef, template) < 0 ||
  586.         fprintf(inFile, "%s <%s>\n", ImakeDef, imakefile) < 0 ||
  587.         fprintf(inFile, "%s\n", TmplInc) < 0 ||
  588.         fclose(inFile))
  589.         LogFatal("Cannot write to %s.", masterc);
  590.     /*
  591.      * Fork and exec cpp
  592.      */
  593. #ifdef WIN32
  594.     dup2(fileno(outfd), 1);
  595.     status = _spawnvp(_P_WAIT, cpp, cpp_argv);
  596.     if (status < 0)
  597.         LogFatal("Cannot spawn.", "");
  598.     if (status > 0)
  599.         LogFatalI("Exit code %d.", status);
  600. #else
  601.     pid = fork();
  602.     if (pid < 0)
  603.         LogFatal("Cannot fork.", "");
  604.     if (pid) {    /* parent */
  605.         while (wait(&status) > 0) {
  606.             errno = 0;
  607.             if (WIFSIGNALED(status))
  608.                 LogFatalI("Signal %d.", waitSig(status));
  609.             if (WIFEXITED(status) && waitCode(status))
  610.                 LogFatalI("Exit code %d.", waitCode(status));
  611.         }
  612.     }
  613.     else {    /* child... dup and exec cpp */
  614.         if (verbose)
  615.             showargs(cpp_argv);
  616.         dup2(fileno(outfd), 1);
  617.         execvp(cpp, cpp_argv);
  618.         LogFatal("Cannot exec %s.", cpp);
  619.     }
  620. #endif
  621.     CleanCppOutput(outfd, outfname);
  622. }
  623.  
  624. makeit()
  625. {
  626.     int    pid;
  627.     waitType    status;
  628.  
  629.     /*
  630.      * Fork and exec make
  631.      */
  632. #ifdef WIN32
  633.     status = _spawnvp(_P_WAIT, make_argv[0], make_argv);
  634.     if (status < 0)
  635.         LogFatal("Cannot spawn %s.", make_argv[0]);
  636.     if (status > 0)
  637.         LogFatalI("Exit code %d.", status);
  638. #else
  639.     pid = fork();
  640.     if (pid < 0)
  641.         LogFatal("Cannot fork.", "");
  642.     if (pid) {    /* parent... simply wait */
  643.         while (wait(&status) > 0) {
  644.             errno = 0;
  645.             if (WIFSIGNALED(status))
  646.                 LogFatalI("Signal %d.", waitSig(status));
  647.             if (WIFEXITED(status) && waitCode(status))
  648.                 LogFatalI("Exit code %d.", waitCode(status));
  649.         }
  650.     } else {    /* child... dup and exec cpp */
  651.         if (verbose)
  652.             showargs(make_argv);
  653.         execvp(make_argv[0], make_argv);
  654.         LogFatal("Cannot exec %s.", make_argv[0]);
  655.     }
  656. #endif
  657. }
  658.  
  659. char *CleanCppInput(imakefile)
  660.     char    *imakefile;
  661. {
  662.     FILE    *outFile = NULL;
  663.     FILE    *inFile;
  664.     char    *buf,        /* buffer for file content */
  665.         *pbuf,        /* walking pointer to buf */
  666.         *punwritten,    /* pointer to unwritten portion of buf */
  667.         *ptoken,    /* pointer to # token */
  668.         *pend,        /* pointer to end of # token */
  669.         savec;        /* temporary character holder */
  670.     int    count;
  671.     struct stat    st;
  672.  
  673.     /*
  674.      * grab the entire file.
  675.      */
  676.     if (!(inFile = fopen(imakefile, "r")))
  677.         LogFatal("Cannot open %s for input.", imakefile);
  678.     if (fstat(fileno(inFile), &st) < 0)
  679.         LogFatal("Cannot stat %s for size.", imakefile);
  680.     buf = Emalloc((int)st.st_size+3);
  681.     count = fread(buf + 2, 1, st.st_size, inFile);
  682.     if (count == 0  &&  st.st_size != 0)
  683.         LogFatal("Cannot read %s:", imakefile);
  684.     fclose(inFile);
  685.     buf[0] = '\n';
  686.     buf[1] = '\n';
  687.     buf[count + 2] = '\0';
  688.  
  689.     punwritten = pbuf = buf + 2;
  690.     while (*pbuf) {
  691.         /* for compatibility, replace make comments for cpp */
  692.         if (*pbuf == '#' && pbuf[-1] == '\n' && pbuf[-2] != '\\') {
  693.         ptoken = pbuf+1;
  694.         while (*ptoken == ' ' || *ptoken == '\t')
  695.             ptoken++;
  696.         pend = ptoken;
  697.         while (*pend && *pend != ' ' && *pend != '\t' && *pend != '\n')
  698.             pend++;
  699.         savec = *pend;
  700.         *pend = '\0';
  701.         if (strcmp(ptoken, "define") &&
  702.             strcmp(ptoken, "if") &&
  703.             strcmp(ptoken, "ifdef") &&
  704.             strcmp(ptoken, "ifndef") &&
  705.             strcmp(ptoken, "include") &&
  706.             strcmp(ptoken, "line") &&
  707.             strcmp(ptoken, "else") &&
  708.             strcmp(ptoken, "elif") &&
  709.             strcmp(ptoken, "endif") &&
  710.             strcmp(ptoken, "error") &&
  711.             strcmp(ptoken, "pragma") &&
  712.             strcmp(ptoken, "undef")) {
  713.             if (outFile == NULL) {
  714.             tmpImakefile = Strdup(tmpImakefile);
  715.             (void) mktemp(tmpImakefile);
  716.             outFile = fopen(tmpImakefile, "w");
  717.             if (outFile == NULL)
  718.                 LogFatal("Cannot open %s for write.\n",
  719.                 tmpImakefile);
  720.             }
  721.             writetmpfile(outFile, punwritten, pbuf-punwritten,
  722.                  tmpImakefile);
  723.             if (ptoken > pbuf + 1)
  724.             writetmpfile(outFile, "XCOMM", 5, tmpImakefile);
  725.             else
  726.             writetmpfile(outFile, "XCOMM ", 6, tmpImakefile);
  727.             punwritten = pbuf + 1;
  728.         }
  729.         *pend = savec;
  730.         }
  731.         pbuf++;
  732.     }
  733.     if (outFile) {
  734.         writetmpfile(outFile, punwritten, pbuf-punwritten, tmpImakefile);
  735.         fclose(outFile);
  736.         return tmpImakefile;
  737.     }
  738.  
  739.     return(imakefile);
  740. }
  741.  
  742. CleanCppOutput(tmpfd, tmpfname)
  743.     FILE    *tmpfd;
  744.     char    *tmpfname;
  745. {
  746.     char    *input;
  747.     int    blankline = 0;
  748.  
  749.     while(input = ReadLine(tmpfd, tmpfname)) {
  750.         if (isempty(input)) {
  751.             if (blankline++)
  752.                 continue;
  753.             KludgeResetRule();
  754.         } else {
  755.             blankline = 0;
  756.             KludgeOutputLine(&input);
  757.             writetmpfile(tmpfd, input, strlen(input), tmpfname);
  758.         }
  759.         writetmpfile(tmpfd, "\n", 1, tmpfname);
  760.     }
  761.     fflush(tmpfd);
  762. #ifdef NFS_STDOUT_BUG
  763.     /*
  764.      * On some systems, NFS seems to leave a large number of nulls at
  765.      * the end of the file.  Ralph Swick says that this kludge makes the
  766.      * problem go away.
  767.      */
  768.     ftruncate (fileno(tmpfd), (off_t)ftell(tmpfd));
  769. #endif
  770. }
  771.  
  772. /*
  773.  * Determine if a line has nothing in it.  As a side effect, we trim white
  774.  * space from the end of the line.  Cpp magic cookies are also thrown away.
  775.  * "XCOMM" token is transformed to "#".
  776.  */
  777. isempty(line)
  778.     register char    *line;
  779. {
  780.     register char    *pend;
  781.  
  782.     /*
  783.      * Check for lines of the form
  784.      *    # n "...
  785.      * or
  786.      *    # line n "...
  787.      */
  788.     if (*line == '#') {
  789.         pend = line+1;
  790.         if (*pend == ' ')
  791.             pend++;
  792.         if (*pend == 'l' && pend[1] == 'i' && pend[2] == 'n' &&
  793.             pend[3] == 'e' && pend[4] == ' ')
  794.             pend += 5;
  795.         if (isdigit(*pend)) {
  796.                 do {
  797.                 pend++;
  798.             } while (isdigit(*pend));
  799.             if (*pend == '\n' || *pend == '\0')
  800.                 return(TRUE);
  801.             if (*pend++ == ' ' && *pend == '"')
  802.                 return(TRUE);
  803.         }
  804.         while (*pend)
  805.             pend++;
  806.     } else {
  807.         for (pend = line; *pend; pend++) {
  808.         if (*pend == 'X' && pend[1] == 'C' && pend[2] == 'O' &&
  809.             pend[3] == 'M' && pend[4] == 'M' &&
  810.             (pend == line || pend[-1] == ' ' || pend[-1] == '\t') &&
  811.             (pend[5] == ' ' || pend[5] == '\t' || pend[5] == '\0'))
  812.         {
  813.             *pend = '#';
  814.             strcpy(pend+1, pend+5);
  815.         }
  816. #ifdef MAGIC_MAKE_VARS
  817.         if (*pend == 'X' && pend[1] == 'V' && pend[2] == 'A' &&
  818.             pend[3] == 'R')
  819.         {
  820.             char varbuf[5];
  821.             int i;
  822.  
  823.             if (pend[4] == 'd' && pend[5] == 'e' && pend[6] == 'f' &&
  824.             pend[7] >= '0' && pend[7] <= '9')
  825.             {
  826.             i = pend[7] - '0';
  827.             sprintf(varbuf, "%0.4d", xvariable);
  828.             strncpy(pend+4, varbuf, 4);
  829.             xvariables[i] = xvariable;
  830.             xvariable = (xvariable + 1) % 10000;
  831.             }
  832.             else if (pend[4] == 'u' && pend[5] == 's' &&
  833.                  pend[6] == 'e' && pend[7] >= '0' &&
  834.                  pend[7] <= '9')
  835.             {
  836.             i = pend[7] - '0';
  837.             sprintf(varbuf, "%0.4d", xvariables[i]);
  838.             strncpy(pend+4, varbuf, 4);
  839.             }
  840.         }
  841. #endif
  842.         }
  843.     }
  844.     while (--pend >= line && (*pend == ' ' || *pend == '\t')) ;
  845.     pend[1] = '\0';
  846.     return (*line == '\0');
  847. }
  848.  
  849. /*ARGSUSED*/
  850. char *ReadLine(tmpfd, tmpfname)
  851.     FILE    *tmpfd;
  852.     char    *tmpfname;
  853. {
  854.     static boolean    initialized = FALSE;
  855.     static char    *buf, *pline, *end;
  856.     register char    *p1, *p2;
  857.  
  858.     if (! initialized) {
  859.         int    total_red;
  860.         struct stat    st;
  861.  
  862.         /*
  863.          * Slurp it all up.
  864.          */
  865.         fseek(tmpfd, 0, 0);
  866.         if (fstat(fileno(tmpfd), &st) < 0)
  867.             LogFatal("cannot stat %s for size\n", tmpMakefile);
  868.         pline = buf = Emalloc((int)st.st_size+1);
  869.         total_red = fread(buf, 1, st.st_size, tmpfd);
  870.         if (total_red == 0  &&  st.st_size != 0)
  871.             LogFatal("cannot read %s\n", tmpMakefile);
  872.         end = buf + total_red;
  873.         *end = '\0';
  874.         fseek(tmpfd, 0, 0);
  875. #if defined(SYSV) || defined(WIN32)
  876.         freopen(tmpfname, "w+", tmpfd);
  877. #else    /* !SYSV */
  878.         ftruncate(fileno(tmpfd), (off_t) 0);
  879. #endif    /* !SYSV */
  880.         initialized = TRUE;
  881.         fprintf (tmpfd, "# Makefile generated by imake - do not edit!\n");
  882.         fprintf (tmpfd, "# %s\n",
  883.         "$XConsortium: imake.c,v 1.91 95/01/12 16:15:47 kaleb Exp $");
  884.     }
  885.  
  886.     for (p1 = pline; p1 < end; p1++) {
  887.         if (*p1 == '@' && *(p1+1) == '@') { /* soft EOL */
  888.             *p1++ = '\0';
  889.             p1++; /* skip over second @ */
  890.             break;
  891.         }
  892.         else if (*p1 == '\n') { /* real EOL */
  893. #ifdef WIN32
  894.             if (p1 > pline && p1[-1] == '\r')
  895.                 p1[-1] = '\0';
  896. #endif
  897.             *p1++ = '\0';
  898.             break;
  899.         }
  900.     }
  901.  
  902.     /*
  903.      * return NULL at the end of the file.
  904.      */
  905.     p2 = (pline == p1 ? NULL : pline);
  906.     pline = p1;
  907.     return(p2);
  908. }
  909.  
  910. writetmpfile(fd, buf, cnt, fname)
  911.     FILE    *fd;
  912.     int    cnt;
  913.     char    *buf;
  914.     char    *fname;
  915. {
  916.     if (fwrite(buf, sizeof(char), cnt, fd) != cnt)
  917.         LogFatal("Cannot write to %s.", fname);
  918. }
  919.  
  920. char *Emalloc(size)
  921.     int    size;
  922. {
  923.     char    *p;
  924.  
  925.     if ((p = malloc(size)) == NULL)
  926.         LogFatalI("Cannot allocate %d bytes\n", size);
  927.     return(p);
  928. }
  929.  
  930. #ifdef FIXUP_CPP_WHITESPACE
  931. void
  932. KludgeOutputLine(pline)
  933.     char    **pline;
  934. {
  935.     char    *p = *pline;
  936.     char    quotechar = '\0';
  937.  
  938.     switch (*p) {
  939.         case '#':    /*Comment - ignore*/
  940.         break;
  941.         case '\t':    /*Already tabbed - ignore it*/
  942.             break;
  943.         case ' ':    /*May need a tab*/
  944.         default:
  945. #ifdef INLINE_SYNTAX
  946.         if (*p == '<' && p[1] == '<') { /* inline file close */
  947.             InInline--;
  948.             InRule = TRUE;
  949.             break;
  950.         }
  951. #endif
  952.         /*
  953.          * The following cases should not be treated as beginning of 
  954.          * rules:
  955.          * variable := name    (GNU make)
  956.          * variable = .*:.*    (':' should be allowed as value)
  957.          *    sed 's:/a:/b:'    (: used in quoted values)
  958.          */
  959.         for (; *p; p++) {
  960.             if (quotechar) {
  961.             if (quotechar == '\\' ||
  962.                 (*p == quotechar &&
  963. #ifdef WIN32
  964.                  quotechar != ')' &&
  965. #endif
  966.                  p[-1] != '\\'))
  967.                 quotechar = '\0';
  968.             continue;
  969.             }
  970.             switch (*p) {
  971.             case '\\':
  972.             case '"':
  973.             case '\'':
  974.             quotechar = *p;
  975.             break;
  976.             case '(':
  977.             quotechar = ')';
  978.             break;
  979.             case '{':
  980.             quotechar = '}';
  981.             break;
  982.             case '[':
  983.             quotechar = ']';
  984.             break;
  985.             case '=':
  986. #ifdef REMOVE_CPP_LEADSPACE
  987.             if (!InRule && **pline == ' ') {
  988.                 while (**pline == ' ')
  989.                 (*pline)++;
  990.             }
  991. #endif
  992.             goto breakfor;
  993. #ifdef INLINE_SYNTAX
  994.             case '<':
  995.             if (p[1] == '<') /* inline file start */
  996.                 InInline++;
  997.             break;
  998. #endif
  999.             case ':':
  1000.             if (p[1] == '=')
  1001.                 goto breakfor;
  1002.             while (**pline == ' ')
  1003.                 (*pline)++;
  1004.             InRule = TRUE;
  1005.             return;
  1006.             }
  1007.         }
  1008. breakfor:
  1009.         if (InRule && **pline == ' ')
  1010.             **pline = '\t';
  1011.         break;
  1012.     }
  1013. }
  1014.  
  1015. void
  1016. KludgeResetRule()
  1017. {
  1018.     InRule = FALSE;
  1019. }
  1020. #endif /* FIXUP_CPP_WHITESPACE */
  1021.  
  1022. char *Strdup(cp)
  1023.     register char *cp;
  1024. {
  1025.     register char *new = Emalloc(strlen(cp) + 1);
  1026.  
  1027.     strcpy(new, cp);
  1028.     return new;
  1029. }
  1030.