home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 594a.lha / imake / imake.c < prev    next >
C/C++ Source or Header  |  1991-10-18  |  21KB  |  900 lines

  1. /*****************************************************************************\
  2.  *                                         *
  3.  *                  Porting Note                     *
  4.  *                                         *
  5.  * Add the value of BOOTSTRAPCFLAGS to the cpp_argv table so that it will be *
  6.  * passed to the template file.                          *
  7.  *                                         *
  8. \*****************************************************************************/
  9.  
  10.  
  11.  
  12. /*
  13.  *
  14.  * Copyright 1985, 1986, 1987 by the Massachusetts Institute of Technology
  15.  *
  16.  * Permission to use, copy, modify, and distribute this
  17.  * software and its documentation for any purpose and without
  18.  * fee is hereby granted, provided that the above copyright
  19.  * notice appear in all copies and that both that copyright
  20.  * notice and this permission notice appear in supporting
  21.  * documentation, and that the name of M.I.T. not be used in
  22.  * advertising or publicity pertaining to distribution of the
  23.  * software without specific, written prior permission.
  24.  * M.I.T. makes no representations about the suitability of
  25.  * this software for any purpose.  It is provided "as is"
  26.  * without express or implied warranty.
  27.  *
  28.  * $XConsortium: imake.c,v 1.51 89/12/12 12:37:30 jim Exp $
  29.  * $Locker:  $
  30.  *
  31.  * Author:
  32.  *    Todd Brunhoff
  33.  *    Tektronix, inc.
  34.  *    While a guest engineer at Project Athena, MIT
  35.  *
  36.  * imake: the include-make program.
  37.  *
  38.  * Usage: imake [-Idir] [-Ddefine] [-T] [-f imakefile ] [-s] [-e] [-v] [make flags]
  39.  *
  40.  * Imake takes a template makefile (Imake.tmpl) and runs cpp on it
  41.  * producing a temporary makefile in /tmp.  It then runs make on
  42.  * this pre-processed makefile.
  43.  * Options:
  44.  *        -D    define.  Same as cpp -D argument.
  45.  *        -I    Include directory.  Same as cpp -I argument.
  46.  *        -T    template.  Designate a template other
  47.  *            than Imake.tmpl
  48.  *        -s[F]    show.  Show the produced makefile on the standard
  49.  *            output.  Make is not run is this case.    If a file
  50.  *            argument is provided, the output is placed there.
  51.  *        -e[F]    execute instead of show; optionally name Makefile F
  52.  *        -v    verbose.  Show the make command line executed.
  53.  *
  54.  * Environment variables:
  55.  *
  56.  *        IMAKEINCLUDE    Include directory to use in addition to "."
  57.  *        IMAKECPP    Cpp to use instead of /lib/cpp
  58.  *        IMAKEMAKE    make program to use other than what is
  59.  *                found by searching the $PATH variable.
  60.  * Other features:
  61.  *    imake reads the entire cpp output into memory and then scans it
  62.  *    for occurences of "@@".  If it encounters them, it replaces it with
  63.  *    a newline.  It also trims any trailing white space on output lines
  64.  *    (because make gets upset at them).  This helps when cpp expands
  65.  *    multi-line macros but you want them to appear on multiple lines.
  66.  *
  67.  *    The macros MAKEFILE and MAKE are provided as macros
  68.  *    to make.  MAKEFILE is set to imake's makefile (not the constructed,
  69.  *    preprocessed one) and MAKE is set to argv[0], i.e. the name of
  70.  *    the imake program.
  71.  *
  72.  * Theory of operation:
  73.  *   1. Determine the name of the imakefile from the command line (-f)
  74.  *    or from the content of the current directory (Imakefile or imakefile).
  75.  *    Call this <imakefile>.    This gets added to the arguments for
  76.  *    make as MAKEFILE=<imakefile>.
  77.  *   2. Determine the name of the template from the command line (-T)
  78.  *    or the default, Imake.tmpl.  Call this <template>
  79.  *   3. Start up cpp an provide it with three lines of input:
  80.  *        #define IMAKE_TEMPLATE        " <template> "
  81.  *        #define INCLUDE_IMAKEFILE    < <imakefile> >
  82.  *        #include IMAKE_TEMPLATE
  83.  *    Note that the define for INCLUDE_IMAKEFILE is intended for
  84.  *    use in the template file.  This implies that the imake is
  85.  *    useless unless the template file contains at least the line
  86.  *        #include INCLUDE_IMAKEFILE
  87.  *   4. Gather the output from cpp, and clean it up, expanding @@ to
  88.  *    newlines, stripping trailing white space, cpp control lines,
  89.  *    and extra blank lines.    This cleaned output is placed in a
  90.  *    temporary file.  Call this <makefile>.
  91.  *   5. Start up make specifying <makefile> as its input.
  92.  *
  93.  * The design of the template makefile should therefore be:
  94.  *    <set global macros like CFLAGS, etc.>
  95.  *    <include machine dependent additions>
  96.  *    #include INCLUDE_IMAKEFILE
  97.  *    <add any global targets like 'clean' and long dependencies>
  98.  */
  99. #include    <stdio.h>
  100. #include    <ctype.h>
  101. #include    <sys/types.h>
  102. #ifdef SYSV
  103. #ifndef macII            /* mac will get the stuff out of file.h */
  104. #include    <fcntl.h>
  105. #endif
  106. #else    /* !SYSV */
  107. #ifndef AMIGA
  108. #include    <sys/wait.h>
  109. #endif /* !AMIGA */
  110. #endif    /* !SYSV */
  111. #ifndef AMIGA
  112. #include    <sys/file.h>
  113. #endif /* !AMIGA */
  114. #include    <signal.h>
  115. #include    <sys/stat.h>
  116. #include "imakemdep.h"
  117.  
  118. #ifdef AMIGA
  119. #ifdef __SASC
  120. #include <proto/dos.h>
  121. #endif /* __SASC */
  122. FILE *popen(char *, char *);
  123. char *BuildCommandLine();
  124. #endif /* !AMIGA */
  125.  
  126. #define TRUE        1
  127. #define FALSE        0
  128.  
  129. #ifdef FIXUP_CPP_WHITESPACE
  130. int    InRule = FALSE;
  131. #endif
  132.  
  133. /*
  134.  * Some versions of cpp reduce all tabs in macro expansion to a single
  135.  * space.  In addition, the escaped newline may be replaced with a
  136.  * space instead of being deleted.  Blech.
  137.  */
  138. #ifndef FIXUP_CPP_WHITESPACE
  139. #define KludgeOutputLine(arg)
  140. #define KludgeResetRule()
  141. #endif
  142.  
  143. typedef unsigned char    boolean;
  144.  
  145. #ifndef DEFAULT_CPP
  146. #define DEFAULT_CPP "/lib/cpp"
  147. #endif
  148.  
  149. char *cpp = DEFAULT_CPP;
  150.  
  151. #ifdef AMIGA
  152. char    *tmpMakefile    = "T:Imf.XXXXXX";
  153. char    *tmpImakefile     = "T:IIf.XXXXXX";
  154. #else /* !AMIGA */
  155. char    *tmpMakefile    = "/tmp/Imf.XXXXXX";
  156. char    *tmpImakefile     = "/tmp/IIf.XXXXXX";
  157. #endif /* !AMIGA */
  158.  
  159. char    *make_argv[ ARGUMENTS ] = { "make" };
  160.  
  161. int    make_argindex;
  162. int    cpp_argindex;
  163. char    *make = NULL;
  164. char    *Imakefile = NULL;
  165. char    *Makefile = "Makefile";
  166. char    *Template = "Imake.tmpl";
  167. char    *program;
  168. char    *FindImakefile();
  169. char    *ReadLine();
  170. char    *CleanCppInput();
  171. char    *strdup();
  172.  
  173. boolean verbose = FALSE;
  174. boolean show = TRUE;
  175. extern int    errno;
  176. extern char    *Emalloc();
  177. extern char    *realloc();
  178. extern char    *getenv();
  179. extern char    *mktemp();
  180.  
  181. main(argc, argv)
  182.     int    argc;
  183.     char    **argv;
  184. {
  185.     FILE    *tmpfd;
  186.     char    makeMacro[ BUFSIZ ];
  187.     char    makefileMacro[ BUFSIZ ];
  188.  
  189.     init();
  190.     SetOpts(argc, argv);
  191.  
  192.     Imakefile = FindImakefile(Imakefile);
  193.     if (Makefile)
  194.         tmpMakefile = Makefile;
  195.     else
  196.         tmpMakefile = mktemp(strdup(tmpMakefile));
  197.     AddMakeArg("-f");
  198.     AddMakeArg( tmpMakefile );
  199.     sprintf(makeMacro, "MAKE=%s", program);
  200.     AddMakeArg( makeMacro );
  201.     sprintf(makefileMacro, "MAKEFILE=%s", Imakefile);
  202.     AddMakeArg( makefileMacro );
  203.  
  204. #ifdef AMIGA
  205.     cppit(Imakefile, Template, tmpMakefile);
  206.     if ((tmpfd = fopen(tmpMakefile, "r")) == NULL)
  207.         LogFatal("Cannot open temporary file %s.", tmpMakefile);
  208. #else /* !AMIGA */
  209.     if ((tmpfd = fopen(tmpMakefile, "w+")) == NULL)
  210.         LogFatal("Cannot create temporary file %s.", tmpMakefile);
  211.  
  212.     cppit(Imakefile, Template, tmpfd, tmpMakefile);
  213. #endif /* !AMIGA */
  214.  
  215.     if (show) {
  216.         if (Makefile == NULL)
  217.             showit(tmpfd);
  218.     } else
  219.         makeit();
  220. #ifdef AMIGA
  221.     fclose(tmpfd);
  222. #endif /* !AMIGA */
  223.     wrapup();
  224.     exit(0);
  225. }
  226.  
  227. showit(fd)
  228.     FILE    *fd;
  229. {
  230.     char    buf[ BUFSIZ ];
  231.     int    red;
  232.  
  233.     fseek(fd, 0, 0);
  234.     while ((red = fread(buf, 1, BUFSIZ, fd)) > 0)
  235.         fwrite(buf, red, 1, stdout);
  236. #ifdef AMIGA
  237.     if (red < 0)
  238.     {
  239.         fclose(fd);
  240.         LogFatal("Cannot write stdout.", "");
  241.     }
  242. #else /* !AMIGA */
  243.     if (red < 0)
  244.         LogFatal("Cannot write stdout.", "");
  245. #endif /* !AMIGA */
  246. }
  247.  
  248. wrapup()
  249. {
  250.     if (tmpMakefile != Makefile)
  251.         unlink(tmpMakefile);
  252.     unlink(tmpImakefile);
  253. }
  254.  
  255. #if SIGNALRETURNSINT
  256. int
  257. #else
  258. void
  259. #endif
  260. catch(sig)
  261.     int    sig;
  262. {
  263.     errno = 0;
  264.     LogFatalI("Signal %d.", sig);
  265. }
  266.  
  267. /*
  268.  * Initialize some variables.
  269.  */
  270. init()
  271. {
  272.     char    *p;
  273.  
  274.     make_argindex=0;
  275.     while (make_argv[ make_argindex ] != NULL)
  276.         make_argindex++;
  277.     cpp_argindex = 0;
  278.     while (cpp_argv[ cpp_argindex ] != NULL)
  279.         cpp_argindex++;
  280.  
  281.     /*
  282.      * See if the standard include directory is different than
  283.      * the default.  Or if cpp is not the default.    Or if the make
  284.      * found by the PATH variable is not the default.
  285.      */
  286.     if (p = getenv("IMAKEINCLUDE")) {
  287.         if (*p != '-' || *(p+1) != 'I')
  288.             LogFatal("Environment var IMAKEINCLUDE %s\n",
  289.                 "must begin with -I");
  290.         AddCppArg(p);
  291.         for (; *p; p++)
  292.             if (*p == ' ') {
  293.                 *p++ = '\0';
  294.                 AddCppArg(p);
  295.             }
  296.     }
  297.     if (p = getenv("IMAKECPP"))
  298.         cpp = p;
  299.     if (p = getenv("IMAKEMAKE"))
  300.         make = p;
  301.  
  302.     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  303.         signal(SIGINT, catch);
  304. }
  305.  
  306. AddMakeArg(arg)
  307.     char    *arg;
  308. {
  309.     errno = 0;
  310.     if (make_argindex >= ARGUMENTS-1)
  311.         LogFatal("Out of internal storage.", "");
  312.     make_argv[ make_argindex++ ] = arg;
  313.     make_argv[ make_argindex ] = NULL;
  314. }
  315.  
  316. AddCppArg(arg)
  317.     char    *arg;
  318. {
  319.     errno = 0;
  320.     if (cpp_argindex >= ARGUMENTS-1)
  321.         LogFatal("Out of internal storage.", "");
  322.     cpp_argv[ cpp_argindex++ ] = arg;
  323.     cpp_argv[ cpp_argindex ] = NULL;
  324. }
  325.  
  326. SetOpts(argc, argv)
  327.     int    argc;
  328.     char    **argv;
  329. {
  330.     errno = 0;
  331.     /*
  332.      * Now gather the arguments for make
  333.      */
  334.     program = argv[0];
  335.     for(argc--, argv++; argc; argc--, argv++) {
  336.         /*
  337.          * We intercept these flags.
  338.          */
  339.         if (argv[0][0] == '-') {
  340.         if (argv[0][1] == 'D') {
  341.             AddCppArg(argv[0]);
  342.         } else if (argv[0][1] == 'I') {
  343.             AddCppArg(argv[0]);
  344.         } else if (argv[0][1] == 'f') {
  345.             if (argv[0][2])
  346.             Imakefile = argv[0]+2;
  347.             else {
  348.             argc--, argv++;
  349.             if (! argc)
  350.                 LogFatal("No description arg after -f flag\n", "");
  351.             Imakefile = argv[0];
  352.             }
  353.         } else if (argv[0][1] == 's') {
  354.             if (argv[0][2])
  355.             Makefile = (argv[0][2] == '-') ? NULL : argv[0]+2;
  356.             else if (argc > 1 && argv[1][0] != '-') {
  357.             argc--, argv++;
  358.             Makefile = argv[0];
  359.             }
  360.             show = TRUE;
  361.         } else if (argv[0][1] == 'e') {
  362.            Makefile = (argv[0][2] ? argv[0]+2 : NULL);
  363.            show = FALSE;
  364.         } else if (argv[0][1] == 'T') {
  365.             if (argv[0][2])
  366.             Template = argv[0]+2;
  367.             else {
  368.             argc--, argv++;
  369.             if (! argc)
  370.                 LogFatal("No description arg after -T flag\n", "");
  371.             Template = argv[0];
  372.             }
  373.         } else if (argv[0][1] == 'v') {
  374.             verbose = TRUE;
  375.         } else
  376.             AddMakeArg(argv[0]);
  377.         } else
  378.         AddMakeArg(argv[0]);
  379.     }
  380. }
  381.  
  382. char *FindImakefile(Imakefile)
  383.     char    *Imakefile;
  384. {
  385.     int    fd;
  386.  
  387.     if (Imakefile) {
  388.         if ((fd = open(Imakefile, O_RDONLY)) < 0)
  389.             LogFatal("Cannot open %s.", Imakefile);
  390.     } else {
  391.         if ((fd = open("Imakefile", O_RDONLY)) < 0)
  392.             if ((fd = open("imakefile", O_RDONLY)) < 0)
  393.                 LogFatal("No description file.", "");
  394.             else
  395.                 Imakefile = "imakefile";
  396.         else
  397.             Imakefile = "Imakefile";
  398.     }
  399.     close (fd);
  400.     return(Imakefile);
  401. }
  402.  
  403. LogFatalI(s, i)
  404.     char *s;
  405.     int i;
  406. {
  407.     /*NOSTRICT*/
  408.     LogFatal(s, (char *)i);
  409. }
  410.  
  411. LogFatal(x0,x1)
  412.     char *x0, *x1;
  413. {
  414.     extern char    *sys_errlist[];
  415.     static boolean    entered = FALSE;
  416.  
  417.     if (entered)
  418.         return;
  419.     entered = TRUE;
  420.  
  421.     fprintf(stderr, "%s: ", program);
  422.     if (errno)
  423.         fprintf(stderr, "%s: ", sys_errlist[ errno ]);
  424.     fprintf(stderr, x0,x1);
  425.     fprintf(stderr, "  Stop.\n");
  426.     wrapup();
  427.     exit(1);
  428. }
  429.  
  430. showargs(argv)
  431.     char    **argv;
  432. {
  433.     for (; *argv; argv++)
  434.         fprintf(stderr, "%s ", *argv);
  435.     fprintf(stderr, "\n");
  436. }
  437.  
  438. #ifdef AMIGA
  439. cppit(Imakefile, template, outfname)
  440.     char    *Imakefile;
  441.     char    *template;
  442.     char    *outfname;
  443. {
  444.     FILE    *pipeFile;
  445.     FILE    *outfd;
  446.     char    *cleanedImakefile;
  447.  
  448.     if (verbose)
  449.         showargs(cpp_argv);
  450.     if ((pipeFile =
  451.            popen(BuildCommandLine(cpp, cpp_argv, outfname), "w")) == NULL)
  452.         LogFatal("Cannot popen.", "");
  453.  
  454.     cleanedImakefile = CleanCppInput(Imakefile);
  455.     fprintf(pipeFile, "#define IMAKE_TEMPLATE\t\"%s\"\n", template);
  456.     fprintf(pipeFile, "#define INCLUDE_IMAKEFILE\t<%s>\n",
  457.         cleanedImakefile);
  458.     fprintf(pipeFile, "#include IMAKE_TEMPLATE\n");
  459.     pclose(pipeFile);
  460.  
  461.     if ((outfd = fopen(outfname, "r")) == NULL)
  462.         LogFatal("Cannot open cpp output file %s.", outfname);
  463.     CleanCppOutput(outfd, outfname);
  464.     fclose(outfd);
  465. }
  466. #else /* !AMIGA */
  467. cppit(Imakefile, template, outfd, outfname)
  468.     char    *Imakefile;
  469.     char    *template;
  470.     FILE    *outfd;
  471.     char    *outfname;
  472. {
  473.     FILE    *pipeFile;
  474.     int    pid, pipefd[2];
  475. #ifdef SYSV
  476.     int    status;
  477. #else    /* !SYSV */
  478.     union wait    status;
  479. #endif    /* !SYSV */
  480.     char    *cleanedImakefile;
  481.  
  482.     /*
  483.      * Get a pipe.
  484.      */
  485.     if (pipe(pipefd) < 0)
  486.         LogFatal("Cannot make a pipe.", "");
  487.  
  488.     /*
  489.      * Fork and exec cpp
  490.      */
  491.     pid = fork();
  492.     if (pid < 0)
  493.         LogFatal("Cannot fork.", "");
  494.     if (pid) {      /* parent */
  495.         close(pipefd[0]);
  496.         cleanedImakefile = CleanCppInput(Imakefile);
  497.         if ((pipeFile = fdopen(pipefd[1], "w")) == NULL)
  498.             LogFatalI("Cannot fdopen fd %d for output.", pipefd[1]);
  499.         fprintf(pipeFile, "#define IMAKE_TEMPLATE\t\"%s\"\n",
  500.             template);
  501.         fprintf(pipeFile, "#define INCLUDE_IMAKEFILE\t<%s>\n",
  502.             cleanedImakefile);
  503.         fprintf(pipeFile, "#include IMAKE_TEMPLATE\n");
  504.         fclose(pipeFile);
  505.         while (wait(&status) > 0) {
  506.             errno = 0;
  507. #ifdef SYSV
  508.             if ((status >> 8) & 0xff)
  509.                 LogFatalI("Signal %d.", (status >> 8) & 0xff);
  510.             if (status & 0xff)
  511.                 LogFatalI("Exit code %d.", status & 0xff);
  512. #else    /* !SYSV */
  513.             if (status.w_termsig)
  514.                 LogFatalI("Signal %d.", status.w_termsig);
  515.             if (status.w_retcode)
  516.                 LogFatalI("Exit code %d.", status.w_retcode);
  517. #endif    /* !SYSV */
  518.         }
  519.         CleanCppOutput(outfd, outfname);
  520.     } else {    /* child... dup and exec cpp */
  521.         if (verbose)
  522.             showargs(cpp_argv);
  523.         dup2(pipefd[0], 0);
  524.         dup2(fileno(outfd), 1);
  525.         close(pipefd[1]);
  526.         execv(cpp, cpp_argv);
  527.         LogFatal("Cannot exec %s.", cpp);
  528.     }
  529. }
  530. #endif /* !AMIGA */
  531.  
  532. #ifdef AMIGA
  533. makeit()
  534. {
  535.     long status;
  536.  
  537.     if (verbose)
  538.         showargs(make_argv);
  539.     if ((status =
  540.         SystemTagList(BuildCommandLine(make ? make : "make",
  541.                            make_argv, NULL), NULL)) == -1)
  542.         LogFatal("Cannot exec %s.", make ? make : "make");
  543.     else if (status > 0)
  544.         LogFatalI("Exit code %d.", status);
  545. }
  546. #else /* !AMIGA */
  547. makeit()
  548. {
  549.     int    pid;
  550. #ifdef SYSV
  551.     int    status;
  552. #else    /* !SYSV */
  553.     union wait    status;
  554. #endif    /* !SYSV */
  555.  
  556.     /*
  557.      * Fork and exec make
  558.      */
  559.     pid = fork();
  560.     if (pid < 0)
  561.         LogFatal("Cannot fork.", "");
  562.     if (pid) {      /* parent... simply wait */
  563.         while (wait(&status) > 0) {
  564.             errno = 0;
  565. #ifdef SYSV
  566.             if ((status >> 8) & 0xff)
  567.                 LogFatalI("Signal %d.", (status >> 8) & 0xff);
  568.             if (status & 0xff)
  569.                 LogFatalI("Exit code %d.", status & 0xff);
  570. #else    /* !SYSV */
  571.             if (status.w_termsig)
  572.                 LogFatalI("Signal %d.", status.w_termsig);
  573.             if (status.w_retcode)
  574.                 LogFatalI("Exit code %d.", status.w_retcode);
  575. #endif    /* !SYSV */
  576.         }
  577.     } else {    /* child... dup and exec cpp */
  578.         if (verbose)
  579.             showargs(make_argv);
  580.         if (make)
  581.             execv(make, make_argv);
  582.         else
  583.             execvp("make", make_argv);
  584.         LogFatal("Cannot exec %s.", cpp);
  585.     }
  586. }
  587. #endif /* !AMIGA */
  588.  
  589. char *CleanCppInput(Imakefile)
  590.     char    *Imakefile;
  591. {
  592.     FILE    *outFile = NULL;
  593.     int    infd;
  594.     char    *buf,        /* buffer for file content */
  595.         *pbuf,        /* walking pointer to buf */
  596.         *punwritten,    /* pointer to unwritten portion of buf */
  597.         *cleanedImakefile = Imakefile,    /* return value */
  598.         *ptoken,    /* pointer to # token */
  599.         *pend,        /* pointer to end of # token */
  600.         savec;        /* temporary character holder */
  601.     struct stat    st;
  602.  
  603.     /*
  604.      * grab the entire file.
  605.      */
  606.     if ((infd = open(Imakefile, O_RDONLY)) < 0)
  607.         LogFatal("Cannot open %s for input.", Imakefile);
  608.     fstat(infd, &st);
  609.     buf = Emalloc(st.st_size+1);
  610.     if (read(infd, buf, st.st_size) != st.st_size)
  611.         LogFatal("Cannot read all of %s:", Imakefile);
  612.     close(infd);
  613.     buf[ st.st_size ] = '\0';
  614.  
  615.     punwritten = pbuf = buf;
  616.     while (*pbuf) {
  617.         /* pad make comments for cpp */
  618.         if (*pbuf == '#' && (pbuf == buf || pbuf[-1] == '\n')) {
  619.  
  620.         ptoken = pbuf+1;
  621.         while (*ptoken == ' ' || *ptoken == '\t')
  622.             ptoken++;
  623.         pend = ptoken;
  624.         while (*pend && *pend != ' ' && *pend != '\t' && *pend != '\n')
  625.             pend++;
  626.         savec = *pend;
  627.         *pend = '\0';
  628.         if (strcmp(ptoken, "include")
  629.          && strcmp(ptoken, "define")
  630.          && strcmp(ptoken, "undef")
  631.          && strcmp(ptoken, "ifdef")
  632.          && strcmp(ptoken, "ifndef")
  633.          && strcmp(ptoken, "else")
  634.          && strcmp(ptoken, "endif")
  635.          && strcmp(ptoken, "if")) {
  636.             if (outFile == NULL) {
  637.             tmpImakefile = mktemp(strdup(tmpImakefile));
  638.             cleanedImakefile = tmpImakefile;
  639.             outFile = fopen(tmpImakefile, "w");
  640.             if (outFile == NULL)
  641.                 LogFatal("Cannot open %s for write.\n",
  642.                 tmpImakefile);
  643.             }
  644.             fwrite(punwritten, sizeof(char), pbuf-punwritten, outFile);
  645.             fputs("/**/", outFile);
  646.             punwritten = pbuf;
  647.         }
  648.         *pend = savec;
  649.         }
  650.         pbuf++;
  651.     }
  652.     if (outFile) {
  653.         fwrite(punwritten, sizeof(char), pbuf-punwritten, outFile);
  654.         fclose(outFile); /* also closes the pipe */
  655.     }
  656.  
  657.     return(cleanedImakefile);
  658. }
  659.  
  660. CleanCppOutput(tmpfd, tmpfname)
  661.     FILE    *tmpfd;
  662.     char    *tmpfname;
  663. {
  664.     char    *input;
  665.     int    blankline = 0;
  666.  
  667.     while(input = ReadLine(tmpfd, tmpfname)) {
  668.         if (isempty(input)) {
  669.             if (blankline++)
  670.                 continue;
  671.             KludgeResetRule();
  672.         } else {
  673.             blankline = 0;
  674.             KludgeOutputLine(&input);
  675.             fputs(input, tmpfd);
  676.         }
  677.         putc('\n', tmpfd);
  678.     }
  679.     fflush(tmpfd);
  680. #ifdef NFS_STDOUT_BUG
  681.     /*
  682.      * On some systems, NFS seems to leave a large number of nulls at
  683.      * the end of the file.  Ralph Swick says that this kludge makes the
  684.      * problem go away.
  685.      */
  686.     ftruncate (fileno(tmpfd), (off_t)ftell(tmpfd));
  687. #endif
  688. }
  689.  
  690. /*
  691.  * Determine of a line has nothing in it.  As a side effect, we trim white
  692.  * space from the end of the line.  Cpp magic cookies are also thrown away.
  693.  */
  694. isempty(line)
  695.     char    *line;
  696. {
  697.     char    *pend;
  698.  
  699.     /*
  700.      * Check for lines of the form
  701.      *    # n "...
  702.      * or
  703.      *    # line n "...
  704.      */
  705.     if (*line == '#') {
  706.         pend = line+1;
  707.         if (*pend == ' ')
  708.             pend++;
  709.         if (strncmp(pend, "line ", 5) == 0)
  710.             pend += 5;
  711.         if (isdigit(*pend)) {
  712.             while (isdigit(*pend))
  713.                 pend++;
  714.             if (*pend++ == ' ' && *pend == '"')
  715.                 return(TRUE);
  716.         }
  717.     }
  718.  
  719.     /*
  720.      * Find the end of the line and then walk back.
  721.      */
  722.     for (pend=line; *pend; pend++) ;
  723.  
  724.     pend--;
  725.     while (pend >= line && (*pend == ' ' || *pend == '\t'))
  726.         pend--;
  727.     *++pend = '\0';
  728.     return (*line == '\0');
  729. }
  730.  
  731. /*ARGSUSED*/
  732. char *ReadLine(tmpfd, tmpfname)
  733.     FILE    *tmpfd;
  734.     char    *tmpfname;
  735. {
  736.     static boolean    initialized = FALSE;
  737.     static char    *buf, *pline, *end;
  738.     char    *p1, *p2;
  739.  
  740.     if (! initialized) {
  741.         int    total_red;
  742.         struct stat    st;
  743.  
  744.         /*
  745.          * Slurp it all up.
  746.          */
  747.         fseek(tmpfd, 0, 0);
  748.         fstat(fileno(tmpfd), &st);
  749.         pline = buf = Emalloc(st.st_size+1);
  750.         total_red = read(fileno(tmpfd), buf, st.st_size);
  751.         if (total_red != st.st_size)
  752.             LogFatal("cannot read %s\n", tmpMakefile);
  753.         end = buf + st.st_size;
  754.         *end = '\0';
  755.         lseek(fileno(tmpfd), 0, 0);
  756. #if defined(SYSV) || defined(AMIGA)
  757.         freopen(tmpfname, "w+", tmpfd);
  758. #else    /* !SYSV */
  759.         ftruncate(fileno(tmpfd), 0);
  760. #endif    /* !SYSV */
  761.         initialized = TRUE;
  762.         fprintf (tmpfd, "# Makefile generated by imake - do not edit!\n");
  763.         fprintf (tmpfd, "# %s\n",
  764.         "$XConsortium: imake.c,v 1.51 89/12/12 12:37:30 jim Exp $");
  765.  
  766. #ifdef FIXUP_CPP_WHITESPACE
  767.         {
  768.         static char *cpp_warning[] = {
  769. "#",
  770. "# The cpp used on this machine replaces all newlines and multiple tabs and",
  771. "# spaces in a macro expansion with a single space.  Imake tries to compensate",
  772. "# for this, but is not always successful.",
  773. "#",
  774. NULL };
  775.         char **cpp;
  776.  
  777.         for (cpp = cpp_warning; *cpp; cpp++) {
  778.             fprintf (tmpfd, "%s\n", *cpp);
  779.         }
  780.         }
  781. #endif /* FIXUP_CPP_WHITESPACE */
  782.     }
  783.  
  784.     for (p1 = pline; p1 < end; p1++) {
  785.         if (*p1 == '@' && *(p1+1) == '@') { /* soft EOL */
  786.             *p1++ = '\0';
  787.             p1++; /* skip over second @ */
  788.             break;
  789.         }
  790.         else if (*p1 == '\n') { /* real EOL */
  791.             *p1++ = '\0';
  792.             break;
  793.         }
  794.     }
  795.  
  796.     /*
  797.      * return NULL at the end of the file.
  798.      */
  799.     p2 = (pline == p1 ? NULL : pline);
  800.     pline = p1;
  801.     return(p2);
  802. }
  803.  
  804. writetmpfile(fd, buf, cnt)
  805.     FILE    *fd;
  806.     int    cnt;
  807.     char    *buf;
  808. {
  809.     errno = 0;
  810.     if (fwrite(buf, cnt, 1, fd) != 1)
  811.         LogFatal("Cannot write to %s.", tmpMakefile);
  812. }
  813.  
  814. char *Emalloc(size)
  815.     int    size;
  816. {
  817.     char    *p, *malloc();
  818.  
  819.     if ((p = malloc(size)) == NULL)
  820.         LogFatalI("Cannot allocate %d bytes\n", size);
  821.     return(p);
  822. }
  823.  
  824. #ifdef FIXUP_CPP_WHITESPACE
  825. KludgeOutputLine(pline)
  826.     char    **pline;
  827. {
  828.     char    *p = *pline;
  829.  
  830.     switch (*p) {
  831.         case '#':   /*Comment - ignore*/
  832.         break;
  833.         case '\t':  /*Already tabbed - ignore it*/
  834.         break;
  835.         case ' ':   /*May need a tab*/
  836.         default:
  837.         for (; *p; p++) if (p[0] == ':' &&
  838.                     p > *pline && p[-1] != '\\') {
  839.             if (**pline == ' ')
  840.             (*pline)++;
  841.             InRule = TRUE;
  842.             break;
  843.         }
  844.         if (InRule && **pline == ' ')
  845.             **pline = '\t';
  846.         break;
  847.     }
  848. }
  849.  
  850. KludgeResetRule()
  851. {
  852.     InRule = FALSE;
  853. }
  854. #endif /* FIXUP_CPP_WHITESPACE */
  855.  
  856. char *strdup(cp)
  857.     register char *cp;
  858. {
  859.     register char *new = Emalloc(strlen(cp) + 1);
  860.  
  861.     strcpy(new, cp);
  862.     return new;
  863. }
  864.  
  865.  
  866. #ifdef AMIGA
  867. char *BuildCommandLine(Command, Argv, Output)
  868.     char *Command;
  869.     char **Argv;
  870.     char *Output;
  871. {
  872.     unsigned int linelen =
  873.         strlen(Command) + (Output ? strlen(Output) + 2 : 0);
  874.     unsigned int linesize = (linelen + 255) & ~255;
  875.     char *line = Emalloc(linesize);
  876.  
  877.     sprintf(line, Output ? "%s >%s" : "%s", Command, Output);
  878.  
  879.     while (*++Argv)
  880.     {
  881.         unsigned int arglen = strlen(*Argv);
  882.  
  883.         if (arglen + linelen + 2 > linesize)
  884.         {
  885.             char *newline = Emalloc(linesize += 256);
  886.  
  887.             strcpy(newline, line);
  888.             free(line);
  889.             line = newline;
  890.         }
  891.  
  892.         line[linelen++] = ' ';
  893.         strcpy(line + linelen, *Argv);
  894.         linelen += arglen;
  895.     }
  896.  
  897.     return line;
  898. }
  899. #endif /* !AMIGA */
  900.