add packaging
[platform/upstream/imake.git] / imake.c
1
2 /***************************************************************************
3  *                                                                         *
4  *                                Porting Note                             *
5  *                                                                         *
6  * Add the value of BOOTSTRAPCFLAGS to the cpp_argv table so that it will  *
7  * be passed to the template file.                                         *
8  *                                                                         *
9  ***************************************************************************/
10 /*
11  *
12 Copyright (c) 1985, 1986, 1987, 1998 The Open Group
13
14 Permission to use, copy, modify, distribute, and sell this software and its
15 documentation for any purpose is hereby granted without fee, provided that
16 the above copyright notice appear in all copies and that both that
17 copyright notice and this permission notice appear in supporting
18 documentation.
19
20 The above copyright notice and this permission notice shall be included in
21 all copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
26 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
27 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
28 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
30 Except as contained in this notice, the name of The Open Group shall not be
31 used in advertising or otherwise to promote the sale, use or other dealings
32 in this Software without prior written authorization from The Open Group.
33  *
34  * Original Author:
35  *      Todd Brunhoff
36  *      Tektronix, inc.
37  *      While a guest engineer at Project Athena, MIT
38  *
39  * imake: the include-make program.
40  *
41  * Usage: imake [-Idir] [-Ddefine] [-T template] [-f imakefile ] [-C Imakefile.c ] [-s] [-e] [-v] [make flags]
42  *
43  * Imake takes a template file (Imake.tmpl) and a prototype (Imakefile)
44  * and runs cpp on them producing a Makefile.  It then optionally runs make
45  * on the Makefile.
46  * Options:
47  *              -D      define.  Same as cpp -D argument.
48  *              -U      undefine.  Same as cpp -U argument.
49  *              -W      warning.  Same as cpp -W argument.
50  *              -I      Include directory.  Same as cpp -I argument.
51  *              -T      template.  Designate a template other
52  *                      than Imake.tmpl
53  *              -f      specify the Imakefile file
54  *              -C      specify the name to use instead of Imakefile.c
55  *              -s[F]   show.  Show the produced makefile on the standard
56  *                      output.  Make is not run is this case.  If a file
57  *                      argument is provided, the output is placed there.
58  *              -e[F]   execute instead of show; optionally name Makefile F
59  *              -v      verbose.  Show the make command line executed.
60  *
61  * Environment variables:
62  *
63  *              IMAKEINCLUDE    Include directory to use in addition to "."
64  *              IMAKECPP        Cpp to use instead of /lib/cpp
65  *              IMAKEMAKE       make program to use other than what is
66  *                              found by searching the $PATH variable.
67  * Other features:
68  *      imake reads the entire cpp output into memory and then scans it
69  *      for occurences of "@@".  If it encounters them, it replaces it with
70  *      a newline.  It also trims any trailing white space on output lines
71  *      (because make gets upset at them).  This helps when cpp expands
72  *      multi-line macros but you want them to appear on multiple lines.
73  *      It also changes occurences of "XCOMM" to "#", to avoid problems
74  *      with treating commands as invalid preprocessor commands.
75  *
76  *      The macros MAKEFILE and MAKE are provided as macros
77  *      to make.  MAKEFILE is set to imake's makefile (not the constructed,
78  *      preprocessed one) and MAKE is set to argv[0], i.e. the name of
79  *      the imake program.
80  *
81  * Theory of operation:
82  *   1. Determine the name of the imakefile from the command line (-f)
83  *      or from the content of the current directory (Imakefile or imakefile).
84  *      Call this <imakefile>.  This gets added to the arguments for
85  *      make as MAKEFILE=<imakefile>.
86  *   2. Determine the name of the template from the command line (-T)
87  *      or the default, Imake.tmpl.  Call this <template>
88  *   3. Determine the name of the imakeCfile from the command line (-C)
89  *      or the default, Imakefile.c.  Call this <imakeCfile>
90  *   4. Store lines of input into <imakeCfile>:
91  *      - A c-style comment header (see ImakefileCHeader below), used
92  *        to recognize temporary files generated by imake.
93  *      - If DEFAULT_OS_NAME is defined, format the utsname struct and
94  *        call the result <defaultOsName>.  Add:
95  *              #define DefaultOSName <defaultOsName>
96  *      - If DEFAULT_OS_MAJOR_REV is defined, format the utsname struct
97  *        and call the result <defaultOsMajorVersion>.  Add:
98  *              #define DefaultOSMajorVersion <defaultOsMajorVersion>
99  *      - If DEFAULT_OS_MINOR_REV is defined, format the utsname struct
100  *        and call the result <defaultOsMinorVersion>.  Add:
101  *              #define DefaultOSMinorVersion <defaultOsMinorVersion>
102  *      - If DEFAULT_OS_TEENY_REV is defined, format the utsname struct
103  *        and call the result <defaultOsTeenyVersion>.  Add:
104  *              #define DefaultOSTeenyVersion <defaultOsTeenyVersion>
105  *      - If DEFAULT_MACHINE_ARCITECTURE is defined, format the utsname struct
106  *        and define the corresponding macro.  (For example on the amiga,
107  *        this will define amiga in addition to m68k).
108  *      - If the file "localdefines" is readable in the current
109  *        directory, print a warning message to stderr and add:
110  *              #define IMAKE_LOCAL_DEFINES     "localdefines"
111  *              #include IMAKE_LOCAL_DEFINES
112  *      - If the file "admindefines" is readable in the current
113  *        directory, print a warning message to stderr and add:
114  *              #define IMAKE_ADMIN_DEFINES     "admindefines"
115  *              #include IMAKE_ADMIN_DEFINES
116  *      - The following lines:
117  *              #define INCLUDE_IMAKEFILE       < <imakefile> >
118  *              #define IMAKE_TEMPLATE          " <template> "
119  *              #include IMAKE_TEMPLATE
120  *      - If the file "adminmacros" is readable in the current
121  *        directory, print a warning message to stderr and add:
122  *              #define IMAKE_ADMIN_MACROS      "adminmacros"
123  *              #include IMAKE_ADMIN_MACROS
124  *      - If the file "localmacros" is readable in the current
125  *        directory, print a warning message to stderr and add:
126  *              #define IMAKE_LOCAL_MACROS      "localmacros"
127  *              #include IMAKE_LOCAL_MACROS
128  *   5. Start up cpp and provide it with this file.
129  *      Note that the define for INCLUDE_IMAKEFILE is intended for
130  *      use in the template file.  This implies that the imake is
131  *      useless unless the template file contains at least the line
132  *              #include INCLUDE_IMAKEFILE
133  *   6. Gather the output from cpp, and clean it up, expanding @@ to
134  *      newlines, stripping trailing white space, cpp control lines,
135  *      and extra blank lines, and changing XCOMM to #.  This cleaned
136  *      output is placed in a new file, default "Makefile", but can
137  *      be specified with -s or -e options.
138  *   7. Optionally start up make on the resulting file.
139  *
140  * The design of the template makefile should therefore be:
141  *      <set global macros like CFLAGS, etc.>
142  *      <include machine dependent additions>
143  *      #include INCLUDE_IMAKEFILE
144  *      <add any global targets like 'clean' and long dependencies>
145  */
146
147 #include "config.h"
148
149 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
150 /* This needs to be before _POSIX_SOURCE gets defined */
151 # include <sys/param.h>
152 # include <sys/types.h>
153 # include <sys/sysctl.h>
154 #endif
155 #include <stdlib.h>
156 #include <stdio.h>
157 #include <stdarg.h>
158 #include <X11/Xfuncproto.h>
159 #include <X11/Xosdefs.h>
160 #include <string.h>
161 #include <ctype.h>
162 #ifdef WIN32
163 # include "Xw32defs.h"
164 #endif
165 #include <sys/types.h>
166 #include <fcntl.h>
167 #ifdef X_NOT_POSIX
168 # ifndef WIN32
169 #  include <sys/file.h>
170 # endif
171 #else
172 # include <unistd.h>
173 #endif
174 #ifdef ISC
175 # include <unistd.h>
176 #endif
177 #if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE)
178 # include <signal.h>
179 #else
180 # define _POSIX_SOURCE
181 # include <signal.h>
182 # undef _POSIX_SOURCE
183 #endif
184 #if !defined(SIGCHLD) && defined(SIGCLD)
185 # define SIGCHLD                SIGCLD
186 #endif
187 #include <sys/stat.h>
188 #ifndef X_NOT_POSIX
189 # ifdef _POSIX_SOURCE
190 #  ifdef __SCO__
191 #   include <sys/procset.h>
192 #   include <sys/siginfo.h>
193 #  endif
194 #  include <sys/wait.h>
195 # else
196 #  define _POSIX_SOURCE
197 #  include <sys/wait.h>
198 #  undef _POSIX_SOURCE
199 # endif
200 # define waitCode(w)    WEXITSTATUS(w)
201 # define waitSig(w)     WTERMSIG(w)
202 typedef int             waitType;
203 #else /* X_NOT_POSIX */
204 # ifdef SYSV
205 #  define waitCode(w)   (((w) >> 8) & 0x7f)
206 #  define waitSig(w)    ((w) & 0xff)
207 typedef int             waitType;
208 # else /* SYSV */
209 #  ifdef WIN32
210 #   include <process.h>
211 typedef int             waitType;
212 #  else
213 #   include <sys/wait.h>
214 #   define waitCode(w)  ((w).w_T.w_Retcode)
215 #   define waitSig(w)   ((w).w_T.w_Termsig)
216 typedef union wait      waitType;
217 #  endif
218 # endif
219 # ifndef WIFSIGNALED
220 #  define WIFSIGNALED(w) waitSig(w)
221 # endif
222 # ifndef WIFEXITED
223 #  define WIFEXITED(w) waitCode(w)
224 # endif
225 #endif /* X_NOT_POSIX */
226 #include <stdlib.h>
227 #include <errno.h>
228 #ifdef __minix_vmd
229 # define USE_FREOPEN            1
230 #endif
231
232 #ifndef WIN32
233 # include <sys/utsname.h>
234 #else
235 # include <windows.h>
236 #endif
237 #ifndef SYS_NMLN
238 # ifdef _SYS_NMLN
239 #  define SYS_NMLN _SYS_NMLN
240 # else
241 #  define SYS_NMLN 257
242 # endif
243 #endif
244 #if defined(linux) || defined(__GNU__) || defined(__GLIBC__)
245 # include <limits.h>
246 # include <stdio.h>
247 #endif
248 #ifdef __QNX__
249 # include <unix.h>
250 #endif
251
252 #if defined(__NetBSD__)         /* see code clock in init() below */
253 # include <sys/utsname.h>
254 #endif
255
256 typedef unsigned char boolean;
257 #define TRUE            1
258 #define FALSE           0
259
260 #include "imakemdep.h"
261 #ifdef CROSSCOMPILE
262 # include "imakemdep_cpp.h"
263 #endif
264
265 #if defined CROSSCOMPILE || defined FIXUP_CPP_WHITESPACE
266 int InRule = FALSE;
267 #endif
268 #if defined CROSSCOMPILE || defined INLINE_SYNTAX
269 int InInline = 0;
270 #endif
271 #if defined CROSSCOMPILE || defined MAGIC_MAKE_VARS
272 int xvariable = 0;
273 int xvariables[10];
274 #endif
275
276 #ifndef PATH_MAX
277 # define PATH_MAX 1024
278 #endif
279
280 /*
281  * Some versions of cpp reduce all tabs in macro expansion to a single
282  * space.  In addition, the escaped newline may be replaced with a
283  * space instead of being deleted.  Blech.
284  */
285 void KludgeOutputLine(char **), KludgeResetRule(void);
286
287 #ifndef CROSSCOMPILE
288 # ifdef USE_CC_E
289 #  ifndef DEFAULT_CC
290 #   define DEFAULT_CC "cc"
291 #  endif
292 # else
293 #  ifndef DEFAULT_CPP
294 #   ifdef CPP_PROGRAM
295 #    define DEFAULT_CPP CPP_PROGRAM
296 #   else
297 #    define DEFAULT_CPP "/lib/cpp"
298 #   endif
299 #  endif
300 # endif
301 #endif
302
303 const char *cpp = NULL;
304
305 const char      *tmpMakefile;
306 const char      *tmpMakefileTemplate = "/tmp/Imf.XXXXXX";
307 const char      *tmpImakefile;
308 const char      *tmpImakefileTemplate = "/tmp/IIf.XXXXXX";
309 const char      *make_argv[ ARGUMENTS ] = {
310 #ifdef WIN32
311     "nmake"
312 #else
313     "make"
314 #endif
315 };
316
317 int     make_argindex;
318 int     cpp_argindex;
319 const char      *Imakefile = NULL;
320 const char      *Makefile = "Makefile";
321 const char      *Template = "Imake.tmpl";
322 const char      *ImakefileC = "Imakefile.c";
323 boolean haveImakefileC = FALSE;
324 const char      *cleanedImakefile = NULL;
325 const char      *program;
326 const char      *FindImakefile(const char *Imakefile);
327 char    *ReadLine(FILE *tmpfd, const char *tmpfname);
328 const char      *CleanCppInput(const char *imakefile);
329 char    *Strdup(const char *cp);
330 char    *Emalloc(int size);
331 void    LogFatal(const char *x0, ...) _X_ATTRIBUTE_PRINTF(1, 2);
332 void    LogMsg(const char *x0, ...) _X_ATTRIBUTE_PRINTF(1, 2);
333
334 void    showit(FILE *fd);
335 void    wrapup(void);
336 void    init(void);
337 void    AddMakeArg(const char *arg);
338 void    AddCppArg(const char *arg);
339 #ifdef CROSSCOMPILE
340 char    *CrossCompileCPP(void);
341 #endif
342 void    SetOpts(int argc, char **argv);
343 void    CheckImakefileC(const char *masterc);
344 void    cppit(const char *imakefile, const char *template, const char *masterc,
345               FILE *outfd, const char *outfname);
346 void    makeit(void);
347 void    CleanCppOutput(FILE *tmpfd, const char *tmpfname);
348 boolean isempty(char *line);
349 void    writetmpfile(FILE *fd, const char *buf, int cnt, const char *fname);
350 #ifdef SIGNALRETURNSINT
351 int     catch(int sig);
352 #else
353 void    catch(int sig);
354 #endif
355 void    showargs(const char **argv);
356 boolean optional_include(FILE *inFile, const char *defsym, const char *fname);
357 void      doit(FILE *outfd, const char *cmd, const char **argv);
358 boolean define_os_defaults(FILE *inFile);
359 #ifdef CROSSCOMPILE
360 static void get_cross_compile_dir(FILE *inFile);
361 #endif
362 #ifdef CROSSCOMPILEDIR
363 const char *CrossCompileDir = CROSSCOMPILEDIR;
364 #else
365 const char *CrossCompileDir = "";
366 #endif
367 boolean CrossCompiling = FALSE;
368
369
370
371 boolean verbose = FALSE;
372 boolean show = TRUE;
373
374 int
375 main(int argc, char *argv[])
376 {
377         FILE    *tmpfd = NULL;
378         char    makeMacro[ BUFSIZ ];
379         char    makefileMacro[ BUFSIZ ];
380         int     lenCrossCompileDir = 0;
381
382         program = argv[0];
383         init();
384
385         lenCrossCompileDir = strlen(CrossCompileDir);
386         if (lenCrossCompileDir) {
387             if (lenCrossCompileDir > (PATH_MAX - 20))
388               LogFatal("Cross compile directory path too long %s\n",
389                        CrossCompileDir);
390             else
391                 CrossCompiling = TRUE;
392         }
393
394         SetOpts(argc, argv);
395         Imakefile = FindImakefile(Imakefile);
396         CheckImakefileC(ImakefileC);
397         if (Makefile) {
398                 tmpMakefile = Makefile;
399                 if ((tmpfd = fopen(tmpMakefile, "w+")) == NULL)
400                    LogFatal("Cannot create temporary file %s.", tmpMakefile);
401         } else {
402 #ifdef HAVE_MKSTEMP
403                 int fd;
404 #endif
405                 char *tmpMakefileName = Strdup(tmpMakefileTemplate);
406 #ifndef HAVE_MKSTEMP
407                 if (mktemp(tmpMakefileName) == NULL ||
408                     (tmpfd = fopen(tmpMakefileName, "w+")) == NULL) {
409                    LogFatal("Cannot create temporary file %s.", tmpMakefileName);
410                 }
411 #else
412                 fd = mkstemp(tmpMakefileName);
413                 if (fd == -1 || (tmpfd = fdopen(fd, "w+")) == NULL) {
414                    if (fd != -1) {
415                       unlink(tmpMakefileName); close(fd);
416                    }
417                    LogFatal("Cannot create temporary file %s.", tmpMakefileName);
418                 }
419 #endif
420                 tmpMakefile = tmpMakefileName;
421         }
422         AddMakeArg("-f");
423         AddMakeArg( tmpMakefile );
424         sprintf(makeMacro, "MAKE=%s", program);
425         AddMakeArg( makeMacro );
426         sprintf(makefileMacro, "MAKEFILE=%s", Imakefile);
427         AddMakeArg( makefileMacro );
428
429         cleanedImakefile = CleanCppInput(Imakefile);
430         cppit(cleanedImakefile, Template, ImakefileC, tmpfd, tmpMakefile);
431
432         if (show) {
433                 if (Makefile == NULL)
434                         showit(tmpfd);
435         } else
436                 makeit();
437         wrapup();
438         exit(0);
439 }
440
441 void
442 showit(FILE *fd)
443 {
444         char    buf[ BUFSIZ ];
445         int     red;
446
447         fseek(fd, 0, 0);
448         while ((red = fread(buf, 1, BUFSIZ, fd)) > 0)
449                 writetmpfile(stdout, buf, red, "stdout");
450         if (red < 0)
451             LogFatal("Cannot read %s.", tmpMakefile);
452 }
453
454 void
455 wrapup(void)
456 {
457         if (tmpMakefile != Makefile)
458                 unlink(tmpMakefile);
459         if (cleanedImakefile && cleanedImakefile != Imakefile)
460                 unlink(cleanedImakefile);
461         if (haveImakefileC)
462                 unlink(ImakefileC);
463 }
464
465 #ifdef SIGNALRETURNSINT
466 int
467 #else
468 void
469 #endif
470 catch(int sig)
471 {
472         errno = 0;
473         LogFatal("Signal %d.", sig);
474 }
475
476 /*
477  * Initialize some variables.
478  */
479 void
480 init(void)
481 {
482         register char   *p;
483
484         make_argindex=0;
485         while (make_argv[ make_argindex ] != NULL)
486                 make_argindex++;
487         cpp_argindex = 0;
488         while (cpp_argv[ cpp_argindex ] != NULL)
489                 cpp_argindex++;
490
491 #if defined CROSSCOMPILE
492         if (sys == netBSD)
493           if (CrossCompiling) {
494             LogFatal("fix imake to do crosscompiling for NetBSD\n","");
495           } else
496 #endif
497 #if defined(__NetBSD__) || defined CROSSCOMPILE
498         {
499                 struct utsname uts;
500                 static char argument[512];
501
502                 /*
503                  * Sharable imake configurations require a
504                  * machine identifier.
505                  */
506                 if (uname(&uts) != 0)
507                         LogFatal("uname(3) failed; can't tell what %s",
508                             "kind of machine you have.");
509
510                 memset(argument, 0, sizeof(argument));
511                 (void)snprintf(argument, sizeof(argument) - 1,
512                     "-D__%s__", uts.machine);
513
514                 AddCppArg(argument);
515         }
516 #endif /* __NetBSD__ */
517
518         /*
519          * See if the standard include directory is different than
520          * the default.  Or if cpp is not the default.  Or if the make
521          * found by the PATH variable is not the default.
522          */
523         if ((p = getenv("IMAKEINCLUDE"))) {
524                 if (*p != '-' || *(p+1) != 'I')
525                         LogFatal("Environment var IMAKEINCLUDE %s",
526                                 "must begin with -I");
527                 AddCppArg(p);
528                 for (; *p; p++)
529                         if (*p == ' ') {
530                                 *p++ = '\0';
531                                 AddCppArg(p);
532                         }
533         }
534         if ((p = getenv("IMAKECPP")))
535                 cpp = p;
536         if ((p = getenv("IMAKEMAKE")))
537                 make_argv[0] = p;
538
539         if (signal(SIGINT, SIG_IGN) != SIG_IGN)
540                 signal(SIGINT, catch);
541 #ifdef SIGCHLD
542         signal(SIGCHLD, SIG_DFL);
543 #endif
544 }
545
546 void
547 AddMakeArg(const char *arg)
548 {
549         errno = 0;
550         if (make_argindex >= ARGUMENTS-1)
551                 LogFatal("Out of internal storage.");
552         make_argv[ make_argindex++ ] = arg;
553         make_argv[ make_argindex ] = NULL;
554 }
555
556 void
557 AddCppArg(const char *arg)
558 {
559         errno = 0;
560         if (cpp_argindex >= ARGUMENTS-1)
561                 LogFatal("Out of internal storage.");
562         cpp_argv[ cpp_argindex++ ] = arg;
563         cpp_argv[ cpp_argindex ] = NULL;
564 }
565
566 void
567 SetOpts(int argc, char **argv)
568 {
569
570         errno = 0;
571         /*
572          * Now gather the arguments for make
573          */
574         for(argc--, argv++; argc; argc--, argv++) {
575             /*
576              * We intercept these flags.
577              */
578             if (argv[0][0] == '-') {
579                 if (argv[0][1] == 'D') {
580                     AddCppArg(argv[0]);
581                 } else if (argv[0][1] == 'I') {
582                     AddCppArg(argv[0]);
583                 } else if (argv[0][1] == 'U') {
584                     AddCppArg(argv[0]);
585                 } else if (argv[0][1] == 'W') {
586                     AddCppArg(argv[0]);
587                 } else if (argv[0][1] == 'f') {
588                     if (argv[0][2])
589                         Imakefile = argv[0]+2;
590                     else {
591                         argc--, argv++;
592                         if (! argc)
593                             LogFatal("No description arg after -f flag");
594                         Imakefile = argv[0];
595                     }
596                 } else if (argv[0][1] == 's') {
597                     if (argv[0][2])
598                         Makefile = ((argv[0][2] == '-') && !argv[0][3]) ?
599                             NULL : argv[0]+2;
600                     else {
601                         argc--, argv++;
602                         if (!argc)
603                             LogFatal("No description arg after -s flag");
604                         Makefile = ((argv[0][0] == '-') && !argv[0][1]) ?
605                             NULL : argv[0];
606                     }
607                     show = TRUE;
608                 } else if (argv[0][1] == 'e') {
609                    Makefile = (argv[0][2] ? argv[0]+2 : NULL);
610                    show = FALSE;
611                 } else if (argv[0][1] == 'T') {
612                     if (argv[0][2])
613                         Template = argv[0]+2;
614                     else {
615                         argc--, argv++;
616                         if (! argc)
617                             LogFatal("No description arg after -T flag");
618                         Template = argv[0];
619                     }
620                 } else if (argv[0][1] == 'C') {
621                     if (argv[0][2])
622                         ImakefileC = argv[0]+2;
623                     else {
624                         argc--, argv++;
625                         if (! argc)
626                             LogFatal("No imakeCfile arg after -C flag");
627                         ImakefileC = argv[0];
628                     }
629                 } else if (argv[0][1] == 'v') {
630                     verbose = TRUE;
631                 } else
632                     AddMakeArg(argv[0]);
633             } else
634                 AddMakeArg(argv[0]);
635         }
636
637 #ifndef CROSSCOMPILE
638 # ifdef USE_CC_E
639             if (!cpp)
640             {
641                 AddCppArg("-E");
642 #  ifdef __GNUC__
643                 if (verbose)
644                     AddCppArg("-v");
645 #  endif
646                 cpp = DEFAULT_CC;
647             }
648 # else
649             if (!cpp)
650                 cpp = DEFAULT_CPP;
651 # endif
652 #else
653             if (!cpp)
654                 cpp = CrossCompileCPP();
655 #endif
656
657         cpp_argv[0] = cpp;
658         AddCppArg(ImakefileC);
659 }
660
661 const char *
662 FindImakefile(const char *Imakefile)
663 {
664         if (Imakefile) {
665                 if (access(Imakefile, R_OK) < 0)
666                         LogFatal("Cannot find %s.", Imakefile);
667         } else {
668                 if (access("Imakefile", R_OK) < 0) {
669                         if (access("imakefile", R_OK) < 0)
670                                 LogFatal("No description file.");
671                         else
672                                 Imakefile = "imakefile";
673                 } else
674                         Imakefile = "Imakefile";
675         }
676         return(Imakefile);
677 }
678
679 static void _X_ATTRIBUTE_PRINTF(1, 0)
680 vLogMsg(const char *fmt, va_list args)
681 {
682         int error_number = errno;
683
684         if (error_number) {
685                 fprintf(stderr, "%s: ", program);
686                 fprintf(stderr, "%s\n", strerror(error_number));
687         }
688         fprintf(stderr, "%s: ", program);
689         vfprintf(stderr, fmt, args);
690         fprintf(stderr, "\n");
691 }
692
693 void
694 LogFatal(const char *fmt, ...)
695 {
696         static boolean entered = FALSE;
697         va_list args;
698
699         if (entered)
700                 return;
701         entered = TRUE;
702
703         va_start(args, fmt);
704         vLogMsg(fmt, args);
705         va_end(args);
706         fprintf(stderr, "  Stop.\n");
707         wrapup();
708         exit(1);
709 }
710
711 void
712 LogMsg(const char *fmt, ...)
713 {
714         va_list args;
715
716         va_start(args, fmt);
717         vLogMsg(fmt, args);
718         va_end(args);
719 }
720
721 void
722 showargs(const char **argv)
723 {
724         for (; *argv; argv++)
725                 fprintf(stderr, "%s ", *argv);
726         fprintf(stderr, "\n");
727 }
728
729 #define ImakefileCHeader "/* imake - temporary file */"
730
731 void
732 CheckImakefileC(const char *masterc)
733 {
734         char mkcbuf[1024];
735         FILE *inFile;
736
737         if (access(masterc, F_OK) == 0) {
738                 inFile = fopen(masterc, "r");
739                 if (inFile == NULL)
740                         LogFatal("Refuse to overwrite: %s", masterc);
741                 if ((fgets(mkcbuf, sizeof(mkcbuf), inFile) &&
742                      strncmp(mkcbuf, ImakefileCHeader,
743                              sizeof(ImakefileCHeader)-1)))
744                 {
745                         fclose(inFile);
746                         LogFatal("Refuse to overwrite: %s", masterc);
747                 }
748                 fclose(inFile);
749         }
750 }
751
752 #define LocalDefineFmt  "#define %s \"%s\"\n"
753 #define IncludeFmt      "#include %s\n"
754 #define ImakeDefSym     "INCLUDE_IMAKEFILE"
755 #define ImakeTmplSym    "IMAKE_TEMPLATE"
756 #define OverrideWarning "Warning: local file \"%s\" overrides global macros."
757
758 boolean
759 optional_include(FILE *inFile, const char *defsym, const char *fname)
760 {
761         errno = 0;
762         if (access(fname, R_OK) == 0) {
763                 LogMsg(OverrideWarning, fname);
764                 return (fprintf(inFile, LocalDefineFmt, defsym, fname) < 0 ||
765                         fprintf(inFile, IncludeFmt, defsym) < 0);
766         }
767         return FALSE;
768 }
769
770 void
771 doit(FILE *outfd, const char *cmd, const char **argv)
772 {
773         int             pid;
774         waitType        status;
775
776         /*
777          * Fork and exec the command.
778          */
779 #ifdef WIN32
780         if (outfd)
781                 dup2(fileno(outfd), 1);
782         status = _spawnvp(_P_WAIT, cmd, argv);
783         if (status < 0)
784                 LogFatal("Cannot spawn %s.", cmd);
785         if (status > 0)
786                 LogFatal("Exit code %d.", status);
787 #else
788         pid = fork();
789         if (pid < 0)
790                 LogFatal("Cannot fork.");
791         if (pid) {      /* parent... simply wait */
792                 while (wait(&status) > 0) {
793                         errno = 0;
794                         if (WIFSIGNALED(status))
795                                 LogFatal("Signal %d.", waitSig(status));
796                         if (WIFEXITED(status) && waitCode(status))
797                                 LogFatal("Exit code %d.", waitCode(status));
798                 }
799         }
800         else {  /* child... dup and exec cmd */
801                 if (verbose)
802                         showargs(argv);
803                 if (outfd)
804                         dup2(fileno(outfd), 1);
805                 execvp(cmd, argv);
806                 LogFatal("Cannot exec %s.", cmd);
807         }
808 #endif
809 }
810
811 #if !defined WIN32
812 static void
813 parse_utsname(struct utsname *name, const char *fmt, char *result, const char *msg)
814 {
815   char buf[SYS_NMLN * 5 + 1];
816   char *ptr = buf;
817   int arg;
818
819   if (!name)
820       LogFatal(msg,fmt);
821
822   /* Assemble all the pieces into a buffer. */
823   for (arg = 0; fmt[arg] != ' '; arg++)
824     {
825       /* Our buffer is only guaranteed to hold 5 arguments. */
826       if (arg >= 5)
827         LogFatal(msg, fmt);
828
829       switch (fmt[arg])
830         {
831         case 's':
832           if (arg > 0)
833             *ptr++ = ' ';
834           strcpy(ptr, name->sysname);
835           ptr += strlen(ptr);
836           break;
837
838         case 'n':
839           if (arg > 0)
840             *ptr++ = ' ';
841           strcpy(ptr, name->nodename);
842           ptr += strlen(ptr);
843           break;
844
845         case 'r':
846           if (arg > 0)
847             *ptr++ = ' ';
848           strcpy(ptr, name->release);
849           ptr += strlen(ptr);
850           break;
851
852         case 'v':
853           if (arg > 0)
854             *ptr++ = ' ';
855           strcpy(ptr, name->version);
856           ptr += strlen(ptr);
857           break;
858
859         case 'm':
860           if (arg > 0)
861             *ptr++ = ' ';
862           strcpy(ptr, name->machine);
863           ptr += strlen(ptr);
864           break;
865
866         default:
867           LogFatal(msg, fmt);
868         }
869     }
870
871   /* Just in case... */
872   if (strlen(buf) >= sizeof(buf))
873     LogFatal("Buffer overflow parsing uname.");
874
875   /* Parse the buffer.  The sscanf() return value is rarely correct. */
876   *result = '\0';
877   (void) sscanf(buf, fmt + arg + 1, result);
878 }
879
880 /* Trim leading 0's and periods from version names.  The 0's cause
881    the number to be interpreted as octal numbers.  Some version strings
882    have the potential for different numbers of .'s in them.
883  */
884
885 static char *
886 trim_version(char *p)
887 {
888
889         if (p != 0 && *p != '\0')
890         {
891                 while ((*p == '0' || *p == '.') && *(p + 1) != '\0')
892                         ++p;
893         }
894         return (p);
895 }
896 #endif
897
898 #if defined(linux) || defined(__GLIBC__)
899 const char *libc_c=
900 "#include <stdio.h>\n"
901 "#include <ctype.h>\n"
902 "\n"
903 "#if 1\n"
904 "#pragma weak gnu_get_libc_version\n"
905 "#pragma weak __libc_version\n"
906 "#pragma weak __linux_C_lib_version\n"
907 "#endif\n"
908 "\n"
909 "extern const char * gnu_get_libc_version (void);\n"
910 "extern const char * __linux_C_lib_version;\n"
911 "extern const char __libc_version [];\n"
912 "\n"
913 "int\n"
914 "main ()\n"
915 "{\n"
916 "  int libcmajor = 0, libcminor = 0, libcteeny = 0;\n"
917 "  const char * ptr = NULL;\n"
918 "  int glibcmajor = 0;\n"
919 "\n"
920 "  if (gnu_get_libc_version != 0)\n"
921 "  {\n"
922 "    ptr = gnu_get_libc_version ();\n"
923 "    glibcmajor = 4;\n"
924 "  }\n"
925 "  else if (&__libc_version != 0)\n"
926 "  {\n"
927 "    ptr = __libc_version;\n"
928 "    glibcmajor = 4;\n"
929 "  }\n"
930 "  else if (&__linux_C_lib_version != 0)\n"
931 "  {\n"
932 "    ptr = __linux_C_lib_version;\n"
933 "  }\n"
934 "  else\n"
935 "  {\n"
936 "    libcmajor = 0; libcminor = 0; libcteeny = 0;\n"
937 "  }\n"
938 "\n"
939 "  if (ptr)\n"
940 "  {\n"
941 "    while (!isdigit (*ptr))\n"
942 "      ptr++;\n"
943 "\n"
944 "    sscanf (ptr, \"%d.%d.%d\", &libcmajor, &libcminor, &libcteeny);\n"
945 "    libcmajor += glibcmajor;\n"
946 "  }\n"
947 "\n"
948 "  printf(\"#define DefaultLinuxCLibMajorVersion %d\\n\", libcmajor);\n"
949 "  printf(\"#define DefaultLinuxCLibMinorVersion %d\\n\", libcminor);\n"
950 "  printf(\"#define DefaultLinuxCLibTeenyVersion %d\\n\", libcteeny);\n"
951 "\n"
952 "  return 0;\n"
953 "}\n"
954 ;
955
956 static void
957 get_libc_version(FILE *inFile)
958 {
959   char aout[4096], *tmpdir;
960   FILE *fp;
961   const char *format = "%s -o %s -x c -";
962   char *cc;
963   int len;
964   char *command;
965
966   /* If $TMPDIR is defined and has an acceptable length,
967    * use that as tmp dir, else use /tmp.  That fixes
968    * problems with /tmp mounted "noexec".
969    */
970   if((tmpdir = getenv("TMPDIR")) != NULL && strlen(tmpdir) < (4096-13))
971     strcpy(aout, tmpdir);
972   else
973     strcpy(aout, "/tmp");
974   strcat(aout, "/imakeXXXXXX");
975
976   /* Pre-create temp file safely */
977   {
978     /* Linux + ELF has mkstemp() */
979     int tmpfd;
980     if ((tmpfd = mkstemp(aout)) == -1) {
981       perror("mkstemp");
982       abort();
983     }
984     close(tmpfd);
985   }
986   cc = getenv ("CC");
987   if (cc == NULL)
988     cc = "gcc";
989   len = strlen (aout) + strlen (format) + strlen (cc);
990   if (len < 128) len = 128;
991   if((command = alloca (len)) == NULL)
992     abort();
993
994   if (snprintf (command , len, format, cc, aout) == len)
995     abort ();
996
997   fp = popen (command, "w");
998   if (fp == NULL || fprintf (fp, "%s\n", libc_c) < 0
999       || pclose (fp) != 0)
1000     abort ();
1001
1002   fp = popen (aout, "r");
1003   if (fp == NULL)
1004     abort ();
1005
1006   while (fgets (command, len, fp))
1007     fprintf (inFile, command);
1008
1009   len = pclose (fp);
1010   remove (aout);
1011   if (len)
1012     abort ();
1013 }
1014 #endif
1015
1016 #if defined(__OpenBSD__) || defined(__DragonFly__)
1017 static void
1018 get_stackprotector(FILE *inFile)
1019 {
1020   FILE *fp;
1021   char *cc;
1022   char command[1024], buf[1024];
1023
1024   cc = getenv("CC");
1025   if (cc == NULL) {
1026     cc = "cc";
1027   }
1028   snprintf(command, sizeof(command), "%s -v 2>&1", cc);
1029   fp = popen(command, "r");
1030   if (fp == NULL)
1031     abort();
1032   while (fgets(buf, sizeof(buf), fp)) {
1033     if (strstr(buf, "propolice") != NULL) {
1034       fprintf(inFile, "#define ProPoliceSupport YES\n");
1035       break;
1036     }
1037   }
1038   pclose(fp);
1039 }
1040 #endif
1041
1042
1043 #if defined CROSSCOMPILE || defined linux || defined(__GLIBC__)
1044 static void
1045 get_distrib(FILE *inFile)
1046 {
1047   struct stat sb;
1048
1049   static const char*   suse = "/etc/SuSE-release";
1050   static const char* redhat = "/etc/redhat-release";
1051   static const char* debian = "/etc/debian_version";
1052
1053   fprintf (inFile, "%s\n", "#define LinuxUnknown    0");
1054   fprintf (inFile, "%s\n", "#define LinuxSuSE       1");
1055   fprintf (inFile, "%s\n", "#define LinuxCaldera    2");
1056   fprintf (inFile, "%s\n", "#define LinuxCraftworks 3");
1057   fprintf (inFile, "%s\n", "#define LinuxDebian     4");
1058   fprintf (inFile, "%s\n", "#define LinuxInfoMagic  5");
1059   fprintf (inFile, "%s\n", "#define LinuxKheops     6");
1060   fprintf (inFile, "%s\n", "#define LinuxPro        7");
1061   fprintf (inFile, "%s\n", "#define LinuxRedHat     8");
1062   fprintf (inFile, "%s\n", "#define LinuxSlackware  9");
1063   fprintf (inFile, "%s\n", "#define LinuxTurbo      10");
1064   fprintf (inFile, "%s\n", "#define LinuxWare       11");
1065   fprintf (inFile, "%s\n", "#define LinuxYggdrasil  12");
1066
1067 # ifdef CROSSCOMPILE
1068   if (CrossCompiling) {
1069       fprintf (inFile, "%s\n",
1070                "#define DefaultLinuxDistribution LinuxUnknown");
1071       fprintf (inFile, "%s\n", "#define DefaultLinuxDistName Unknown");
1072       return;
1073   }
1074 # endif
1075   if (lstat (suse, &sb) == 0) {
1076     fprintf (inFile, "%s\n", "#define DefaultLinuxDistribution LinuxSuSE");
1077     fprintf (inFile, "%s\n", "#define DefaultLinuxDistName SuSE");
1078     return;
1079   }
1080   if (lstat (redhat, &sb) == 0) {
1081     fprintf (inFile, "%s\n", "#define DefaultLinuxDistribution LinuxRedHat");
1082     fprintf (inFile, "%s\n", "#define DefaultLinuxDistName RedHat");
1083     return;
1084   }
1085   if (lstat (debian, &sb) == 0) {
1086     fprintf (inFile, "%s\n", "#define DefaultLinuxDistribution LinuxDebian");
1087     fprintf (inFile, "%s\n", "#define DefaultLinuxDistName Debian");
1088     /* You could also try to get the version of the Debian distrib by looking
1089      * at the content of /etc/debian_version */
1090     return;
1091   }
1092   /* what's the definitive way to tell what any particular distribution is? */
1093
1094   fprintf (inFile, "%s\n", "#define DefaultLinuxDistribution LinuxUnknown");
1095   fprintf (inFile, "%s\n", "#define DefaultLinuxDistName Unknown");
1096   /* would like to know what version of the distribution it is */
1097 }
1098
1099 static void
1100 get_ld_version(FILE *inFile)
1101 {
1102   FILE* ldprog;
1103   signed char c;
1104   int ldmajor, ldminor;
1105   const char *ld = "ld -v";
1106
1107 # ifdef CROSSCOMPILE
1108   if (CrossCompiling) {
1109       char cmd[PATH_MAX];
1110       strcpy (cmd, CrossCompileDir);
1111       strcat (cmd,"/");
1112       strcat (cmd,ld);
1113       ldprog = popen (cmd, "r");
1114   } else
1115 # endif
1116       ldprog = popen (ld, "r");
1117
1118   if (ldprog) {
1119     do {
1120       c = fgetc (ldprog);
1121     } while (c != EOF && !isdigit (c));
1122     ungetc (c, ldprog);
1123     (void) fscanf (ldprog, "%d.%d", &ldmajor, &ldminor);
1124     /* Start conversion to a more rational number */
1125     if ((ldmajor > 2) || ((ldmajor == 2) && (ldminor > 9)))
1126         ldmajor *= 100;
1127     else
1128         ldmajor *= 10;
1129
1130     fprintf(inFile, "#define DefaultLinuxBinUtilsMajorVersion %d\n",
1131             ldmajor + ldminor);
1132     pclose (ldprog);
1133   }
1134 }
1135 #endif
1136
1137 #if defined __FreeBSD__
1138 static void
1139 get_binary_format(FILE *inFile)
1140 {
1141   int mib[2];
1142   size_t len;
1143   int osrel = 0;
1144   FILE *objprog = NULL;
1145   int iself = 0;
1146   char buf[10];
1147   char cmd[PATH_MAX];
1148
1149   mib[0] = CTL_KERN;
1150   mib[1] = KERN_OSRELDATE;
1151   len = sizeof(osrel);
1152   sysctl(mib, 2, &osrel, &len, NULL, 0);
1153   if (CrossCompiling) {
1154       strcpy (cmd, CrossCompileDir);
1155       strcat (cmd, "/");
1156       strcat (cmd,"objformat");
1157   } else
1158       strcpy (cmd, "objformat");
1159
1160   if (osrel >= 300004 &&
1161       (objprog = popen(cmd, "r")) != NULL &&
1162       fgets(buf, sizeof(buf), objprog) != NULL &&
1163       strncmp(buf, "elf", 3) == 0)
1164     iself = 1;
1165   if (objprog)
1166     pclose(objprog);
1167
1168   fprintf(inFile, "#define DefaultToElfFormat %s\n", iself ? "YES" : "NO");
1169 }
1170 #endif
1171
1172 #if defined(sun) && defined(__SVR4)
1173 /* Runs Sun compiler command and parses output - this is a bit of a hack
1174  * as it depends on the particular output format of the -V flag, but it's
1175  * worked for many releases.
1176  *
1177  * Input : cmd - command to run (called with -V flag)
1178  *         path - path to command to run (use $PATH if NULL)
1179  * Output: cmajor & cminor - major and minor versions if found
1180  * Returns: 0 if successful, -1 if not.
1181  */
1182 static int
1183 ask_sun_compiler_for_versions(const char *cmd, const char *path,
1184   int *cmajor, int *cminor)
1185 {
1186   char buf[BUFSIZ];
1187   char cmdtorun[PATH_MAX];
1188   char* vptr;
1189   FILE* ccproc;
1190   const char vflag[] = " -V 2>&1";
1191   int retval = -1;
1192
1193   int len = strlen(cmd) + sizeof(vflag);
1194
1195   if (path != NULL) {
1196       len += strlen(path) + 1;
1197   }
1198
1199   if (len < sizeof(cmdtorun)) {
1200       if (path != NULL) {
1201           sprintf(cmdtorun, "%s/%s %s", path, cmd, vflag);
1202       } else {
1203           sprintf(cmdtorun, "%s %s", cmd, vflag);
1204       }
1205
1206       if ((ccproc = popen (cmdtorun, "r")) != NULL) {
1207           if (fgets (buf, sizeof(buf), ccproc) != NULL) {
1208               vptr = strrchr (buf, 'C');
1209               if (vptr) {
1210                   for (; (*vptr != '\0') && !isdigit(*vptr); vptr++) {
1211                       /* Do nothing - just scanning for first digit */
1212                   }
1213                   if (*vptr != '\0') {
1214                       if (sscanf (vptr, "%d.%d", cmajor, cminor) == 2) {
1215                           retval = 0;
1216                       }
1217                   }
1218               }
1219               if (retval != 0) {
1220                   fprintf(stderr,
1221                     "warning: could not parse version number in output of:\n"
1222                     "         %s\n", cmdtorun);
1223               }
1224               while (fgets (buf, sizeof(buf), ccproc) != NULL) {};
1225           }
1226           pclose (ccproc);
1227       }
1228   }
1229   return retval;
1230 }
1231
1232 /* Find Sun compilers and their versions if present */
1233 static void
1234 get_sun_compiler_versions (FILE *inFile)
1235 {
1236   const char* sunpro_path = "/opt/SUNWspro/bin";
1237   int cmajor, cminor, found = 0;
1238
1239   /* If cross-compiling, only check CrossCompilerDir for compilers.
1240    * If not cross-compiling, first check cc in users $PATH,
1241    * then try /opt/SUNWspro if not found in the users $PATH
1242    */
1243
1244 # if defined CROSSCOMPILE
1245   if (CrossCompiling) {
1246       if (ask_sun_compiler_for_versions("cc", CrossCompileDir,
1247         &cmajor, &cminor) == 0) {
1248               found = 1;
1249       }
1250   }
1251   else
1252 # endif
1253   {
1254       if (ask_sun_compiler_for_versions("cc", NULL, &cmajor, &cminor) == 0) {
1255           found = 1;
1256       } else if (ask_sun_compiler_for_versions("cc", sunpro_path,
1257         &cmajor, &cminor) == 0) {
1258           found = 1;
1259           fprintf(inFile, "#define DefaultSunProCCompilerDir %s", sunpro_path);
1260       }
1261   }
1262
1263   if (found) {
1264       fprintf (inFile,
1265         "#define DefaultSunProCCompilerMajorVersion %d\n", cmajor);
1266       fprintf (inFile,
1267         "#define DefaultSunProCCompilerMinorVersion %d\n", cminor);
1268   }
1269
1270   /* Now do it again for C++ compiler (CC) */
1271   found = 0;
1272 # if defined CROSSCOMPILE
1273   if (CrossCompiling) {
1274       if (ask_sun_compiler_for_versions("CC", CrossCompileDir,
1275         &cmajor, &cminor) == 0) {
1276               found = 1;
1277       }
1278   }
1279   else
1280 # endif
1281   {
1282       if (ask_sun_compiler_for_versions("CC", NULL, &cmajor, &cminor) == 0) {
1283           found = 1;
1284       } else if (ask_sun_compiler_for_versions("CC", sunpro_path,
1285         &cmajor, &cminor) == 0) {
1286           found = 1;
1287           fprintf(inFile,
1288                 "#define DefaultSunProCplusplusCompilerDir %s", sunpro_path);
1289       }
1290   }
1291
1292   if (found) {
1293       fprintf (inFile,
1294         "#define DefaultSunProCplusplusCompilerMajorVersion %d\n",
1295         cmajor);
1296       fprintf (inFile,
1297         "#define DefaultSunProCplusplusCompilerMinorVersion %d\n",
1298         cminor);
1299   }
1300 }
1301 #endif
1302
1303 #if defined CROSSCOMPILE || defined  __GNUC__
1304 static void
1305 get_gcc_version(FILE *inFile, char *name)
1306 {
1307     fprintf (inFile, "#define HasGcc 1\n");
1308 # ifdef CROSSCOMPILE
1309     if (CrossCompiling)
1310     {
1311         if (gnu_c > 1) {
1312             fprintf (inFile, "#define HasGcc2 1\n");
1313             if (gnu_c > 2)
1314                 fprintf (inFile, "#define HasGcc3 1\n");
1315         }
1316         fprintf (inFile, "#define GccMajorVersion %d\n", gnu_c);
1317         fprintf (inFile, "#define GccMinorVersion %d\n", gnu_c_minor);
1318     } else
1319 # endif
1320     {
1321 # if __GNUC__ > 1
1322         fprintf (inFile, "#define HasGcc2 1\n");
1323 #  if __GNUC__ > 2
1324         fprintf (inFile, "#define HasGcc3 1\n");
1325 #  endif
1326 # endif
1327         fprintf (inFile, "#define GccMajorVersion %d\n", __GNUC__);
1328         fprintf (inFile, "#define GccMinorVersion %d\n", __GNUC_MINOR__);
1329     }
1330 # if defined(HAS_MERGE_CONSTANTS)
1331     fprintf (inFile, "#define HasGccMergeConstants %d\n", HAS_MERGE_CONSTANTS);
1332 # endif
1333 }
1334 #endif
1335
1336 static boolean
1337 get_gcc(char *cmd)
1338 {
1339   struct stat sb;
1340     static const char* gcc_path[] = {
1341 #if defined(linux) || \
1342      defined(__NetBSD__) || \
1343      defined(__OpenBSD__) || \
1344      defined(__FreeBSD__) || \
1345      defined(__DragonFly__) || \
1346      defined(__APPLE__) || \
1347      defined(__CYGWIN__) || \
1348      defined(__MINGW32__) || \
1349      defined(__GNU__) || \
1350      defined(__GLIBC__)
1351         "/usr/bin/cc",  /* for Linux PostIncDir */
1352 #endif
1353         "/usr/local/bin/gcc",
1354         "/opt/gnu/bin/gcc",
1355         "/usr/pkg/bin/gcc"
1356     };
1357
1358 #ifdef CROSSCOMPILE
1359     static const char* cross_cc_name[] = {
1360         "cc",
1361         "gcc"
1362     };
1363
1364     if (CrossCompiling) {
1365         int i;
1366         for (i = 0; i < sizeof (cross_cc_name) / sizeof cross_cc_name[0]; i++){
1367             strcpy (cmd, CrossCompileDir);
1368             strcat (cmd, "/");
1369             strcat (cmd, cross_cc_name[i]);
1370             if (lstat (cmd, &sb) == 0) {
1371                 return TRUE;
1372                 break;
1373             }
1374         }
1375     } else
1376 #endif
1377       {
1378         int i;
1379         for (i = 0; i < sizeof (gcc_path) / sizeof gcc_path[0]; i++) {
1380             if (lstat (gcc_path[i], &sb) == 0) {
1381                 strcpy (cmd, gcc_path[i]);
1382                 return TRUE;
1383             }
1384         }
1385       }
1386     return FALSE;
1387 }
1388
1389 #if defined CROSSCOMPILE || !defined __UNIXOS2__
1390 static void
1391 get_gcc_incdir(FILE *inFile, char* name)
1392 {
1393   FILE* gccproc;
1394   char buf[PATH_MAX];
1395   char cmd[PATH_MAX];
1396   char* ptr;
1397
1398   strcpy(cmd,name);
1399
1400   buf[0] = '\0';
1401   strcat (cmd, " --print-libgcc-file-name");
1402   if ((gccproc = popen (cmd, "r")) != NULL) {
1403       if (fgets (buf, PATH_MAX, gccproc) != NULL) {
1404           ptr = strstr (buf, "libgcc.a");
1405           if (ptr) strcpy (ptr, "include");
1406       }
1407       (void) pclose (gccproc);
1408   }
1409
1410   if (buf[0])
1411       fprintf (inFile, "#define DefaultGccIncludeDir \"%s\"\n", buf);
1412 }
1413 #endif
1414
1415 boolean
1416 define_os_defaults(FILE *inFile)
1417 {
1418 #if defined CROSSCOMPILE || ( !defined(WIN32) && !defined(__UNIXOS2__) )
1419 # ifdef CROSSCOMPILE
1420 #  ifdef __GNUC__
1421   if (1)
1422 #  else
1423   if ((sys != win32) && (sys != emx))
1424 #  endif
1425 # endif
1426     {
1427 # if (defined(DEFAULT_OS_NAME) || defined(DEFAULT_OS_MAJOR_REV) || \
1428      defined(DEFAULT_OS_MINOR_REV) || defined(DEFAULT_OS_TEENY_REV))
1429         struct utsname *name = NULL;
1430         struct utsname uts_name;
1431         char buf[SYS_NMLN * 5 + 1];
1432
1433         /* Obtain the system information. */
1434 #  ifdef CROSSCOMPILE
1435       if (!CrossCompiling)
1436 #  endif
1437       {
1438           if (uname(&uts_name) < 0)
1439               LogFatal("Cannot invoke uname");
1440           else
1441               name = &uts_name;
1442       }
1443 #  if defined CROSSCOMPILE && (defined linux || defined(__GLIBC__))
1444       else {
1445           strncpy(uts_name.sysname,cross_uts_sysname,SYS_NMLN);
1446           strncpy(uts_name.release,cross_uts_release,SYS_NMLN);
1447           strncpy(uts_name.version,cross_uts_version,SYS_NMLN);
1448           strncpy(uts_name.machine,cross_uts_machine,SYS_NMLN);
1449           name = &uts_name;
1450       }
1451 #  endif
1452 #  ifdef __FreeBSD__
1453        /* Override for compiling in chroot of other OS version, such as
1454         * in the bento build cluster.
1455         */
1456        {
1457          char *e;
1458          if ((e = getenv("OSREL")) != NULL &&
1459              strlen(name->sysname) + strlen(e) + 1 < SYS_NMLN) {
1460           strcpy(name->release, e);
1461           strcpy(name->version, name->sysname);
1462           strcat(name->version, " ");
1463           strcat(name->version, e);
1464          }
1465        }
1466 #  endif
1467
1468 #  if defined DEFAULT_OS_NAME
1469 #   if defined CROSSCOMPILE
1470       if (!CrossCompiling)
1471 #   endif
1472         {
1473           parse_utsname(name, DEFAULT_OS_NAME, buf,
1474                         "Bad DEFAULT_OS_NAME syntax %s");
1475 #   ifdef DEFAULT_OS_NAME_FROB
1476           DEFAULT_OS_NAME_FROB(buf, sizeof buf);
1477 #   endif
1478           if (buf[0] != '\0')
1479             fprintf(inFile, "#define DefaultOSName %s\n", buf);
1480         }
1481 #  endif
1482
1483 #  if defined CROSSCOMPILE
1484         if (CrossCompiling && defaultOsName) {
1485           parse_utsname(name, defaultOsName, buf,
1486                         "Bad DEFAULT_OS_NAME syntax %s");
1487           if (defaultOsNameFrob)
1488             defaultOsNameFrob(buf, sizeof buf);
1489           if (buf[0] != '\0')
1490             fprintf(inFile, "#define DefaultOSName %s\n", buf);
1491         }
1492 #  endif
1493
1494 #  ifdef DEFAULT_OS_MAJOR_REV
1495 #   if defined CROSSCOMPILE
1496         if (!CrossCompiling)
1497 #   endif
1498           {
1499             parse_utsname(name, DEFAULT_OS_MAJOR_REV, buf,
1500                           "Bad DEFAULT_OS_MAJOR_REV syntax %s");
1501 #   ifdef DEFAULT_OS_MAJOR_REV_FROB
1502             DEFAULT_OS_MAJOR_REV_FROB(buf, sizeof buf);
1503 #   endif
1504             fprintf(inFile, "#define DefaultOSMajorVersion %s\n",
1505                     *buf ? trim_version(buf) : "0");
1506           }
1507 #  endif
1508
1509 #  if defined CROSSCOMPILE
1510         if (CrossCompiling && defaultOsMajorRev) {
1511           parse_utsname(name, defaultOsMajorRev, buf,
1512                         "Bad defaultOsMajorRev syntax %s");
1513           if (defaultOsMajorRevFrob)
1514             defaultOsMajorRevFrob(buf, sizeof buf);
1515           fprintf(inFile, "#define DefaultOSMajorVersion %s\n",
1516                   *buf ? trim_version(buf) : "0");
1517         }
1518 #  endif
1519
1520 #  ifdef DEFAULT_OS_MINOR_REV
1521 #   if defined CROSSCOMPILE
1522         if (!CrossCompiling)
1523 #   endif
1524           {
1525             parse_utsname(name, DEFAULT_OS_MINOR_REV, buf,
1526                           "Bad DEFAULT_OS_MINOR_REV syntax %s");
1527 #   ifdef DEFAULT_OS_MINOR_REV_FROB
1528             DEFAULT_OS_MINOR_REV_FROB(buf, sizeof buf);
1529 #   endif
1530             fprintf(inFile, "#define DefaultOSMinorVersion %s\n",
1531                     *buf ? trim_version(buf) : "0");
1532           }
1533 #  endif
1534
1535 #  if defined CROSSCOMPILE
1536         if (CrossCompiling && defaultOsMinorRev) {
1537           parse_utsname(name, defaultOsMinorRev, buf,
1538                         "Bad defaultOsMinorRev syntax %s");
1539           if (defaultOsMinorRevFrob)
1540             defaultOsMinorRevFrob(buf, sizeof buf);
1541           fprintf(inFile, "#define DefaultOSMinorVersion %s\n",
1542                   *buf ? trim_version(buf) : "0");
1543         }
1544 #  endif
1545
1546 #  ifdef DEFAULT_OS_TEENY_REV
1547 #   if defined CROSSCOMPILE
1548         if (!CrossCompiling)
1549 #   endif
1550           {
1551             parse_utsname(name, DEFAULT_OS_TEENY_REV, buf,
1552                           "Bad DEFAULT_OS_TEENY_REV syntax %s");
1553 #   ifdef DEFAULT_OS_TEENY_REV_FROB
1554             DEFAULT_OS_TEENY_REV_FROB(buf, sizeof buf);
1555 #   endif
1556             fprintf(inFile, "#define DefaultOSTeenyVersion %s\n",
1557                     *buf ? trim_version(buf) : "0");
1558           }
1559 #  endif
1560
1561 #  if defined CROSSCOMPILE
1562         if (CrossCompiling && defaultOsTeenyRev) {
1563           parse_utsname(name, defaultOsTeenyRev, buf,
1564                         "Bad defaultOsTeenyRev syntax %s");
1565           if (defaultOsTeenyRevFrob)
1566             defaultOsTeenyRevFrob(buf, sizeof buf);
1567           fprintf(inFile, "#define DefaultOSTeenyVersion %s\n",
1568                   *buf ? trim_version(buf) : "0");
1569         }
1570 #  endif
1571
1572 #  ifdef DEFAULT_MACHINE_ARCHITECTURE
1573 #   if defined CROSSCOMPILE
1574         if (!CrossCompiling)
1575 #   endif
1576           {
1577             parse_utsname(name, DEFAULT_MACHINE_ARCHITECTURE, buf,
1578                           "Bad DEFAULT_MACHINE_ARCHITECTURE %s");
1579             fprintf(inFile, "#ifndef %s\n# define %s\n#endif\n", buf, buf);
1580           }
1581 #  endif
1582
1583 #  if defined CROSSCOMPILE
1584         if (CrossCompiling && defaultMachineArchitecture) {
1585           parse_utsname(name, defaultMachineArchitecture, buf,
1586                         "Bad defaultMachineArchitecture syntax %s");
1587           fprintf(inFile, "#ifndef %s\n# define %s\n#endif\n", buf, buf);
1588         }
1589 #  endif
1590 # endif
1591 # if defined CROSSCOMPILE
1592       if (CrossCompiling)
1593         get_cross_compile_dir(inFile);
1594       else
1595 # endif
1596           fprintf(inFile, "#define CrossCompiling NO\n");
1597 # if defined CROSSCOMPILE
1598       if (CrossCompiling && sys == LinuX)
1599 # endif
1600 # if defined CROSSCOMPILE || defined linux || defined(__GLIBC__)
1601 #  if defined(CROSSCOMPILE) && defined(__linux__)
1602         if (sys == LinuX)
1603 #  endif
1604           get_distrib (inFile);
1605 # endif
1606 # if defined linux || defined(__GLIBC__)
1607 #  if defined CROSSCOMPILE
1608       if (!CrossCompiling)
1609 #  endif
1610           get_libc_version (inFile);
1611 #  if defined CROSSCOMPILE
1612       else {
1613           fprintf(inFile,"#define DefaultLinuxCLibMajorVersion %d\n",
1614                   glibc_major);
1615           fprintf(inFile,"#define DefaultLinuxCLibMinorVersion %d\n",
1616                   glibc_minor);
1617           fprintf(inFile,"#define DefaultLinuxCLibTeenyVersion 0\n");
1618       }
1619 #  endif
1620 # endif /* linux || __GLIBC__ */
1621 # if defined CROSSCOMPILE || defined linux || defined(__GLIBC__)
1622 #  if defined CROSSCOMPILE && defined(__linux__)
1623       if (sys == LinuX)
1624 #  endif
1625           get_ld_version(inFile);
1626 # endif
1627 # if defined (sun) && defined(SVR4)
1628       get_sun_compiler_versions (inFile);
1629 # endif
1630 # if defined CROSSCOMPILE || defined __GNUC__
1631 #  if defined CROSSCOMPILE
1632       if (gnu_c)
1633 #  endif
1634         {
1635           char name[PATH_MAX];
1636           if (get_gcc(name)) {
1637               get_gcc_version (inFile,name);
1638 #  if defined CROSSCOMPILE || !defined __UNIXOS2__
1639 #   if defined CROSSCOMPILE
1640               if (sys != emx)
1641 #   endif
1642                   get_gcc_incdir(inFile,name);
1643 #  endif
1644           }
1645         }
1646 # endif
1647 # if defined __FreeBSD__
1648 #  if defined CROSSCOMPILE
1649       if (sys == freeBSD)
1650 #  endif
1651           get_binary_format(inFile);
1652 # endif
1653     }
1654 #endif /* !WIN32 && !__UNIXOS2__*/
1655 #if defined WIN32
1656 # ifdef CROSSCOMPILE
1657   else if (sys == win32 && !CrossCompiling)
1658 # endif
1659     {
1660       OSVERSIONINFO osvi;
1661       static char* os_names[] = { "Win32s", "Windows 95", "Windows NT" };
1662
1663       memset(&osvi, 0, sizeof(OSVERSIONINFO));
1664       osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
1665       GetVersionEx (&osvi);
1666
1667       fprintf (inFile, "#define DefaultOSName Microsoft %s\n",
1668                os_names[osvi.dwPlatformId]);
1669
1670       fprintf(inFile, "#define DefaultOSMajorVersion %d\n", osvi.dwMajorVersion);
1671       fprintf(inFile, "#define DefaultOSMinorVersion %d\n", osvi.dwMinorVersion);
1672       fprintf(inFile, "#define DefaultOSTeenyVersion %d\n",
1673               osvi.dwBuildNumber & 0xFFFF);
1674     }
1675 #endif /* WIN32 */
1676 #ifdef CROSSCOMPILE
1677   else if (sys == emx)
1678 #endif
1679 #if defined CROSSCOMPILE || defined __UNIXOS2__
1680     {
1681       fprintf(inFile, "#define DefaultOSMajorVersion 4\n");
1682       fprintf(inFile, "#define DefaultOSMinorVersion 0\n");
1683       fprintf(inFile, "#define DefaultOSTeenyVersion 0\n");
1684     }
1685 #endif /* EMX */
1686 #if defined(__OpenBSD__) || defined(__DragonFly__)
1687   get_stackprotector(inFile);
1688 #endif
1689   return FALSE;
1690 }
1691
1692 void
1693 cppit(const char *imakefile, const char *template, const char *masterc,
1694       FILE *outfd, const char *outfname)
1695 {
1696         FILE    *inFile;
1697
1698         haveImakefileC = TRUE;
1699         inFile = fopen(masterc, "w");
1700         if (inFile == NULL)
1701                 LogFatal("Cannot open %s for output.", masterc);
1702         if (fprintf(inFile, "%s\n", ImakefileCHeader) < 0 ||
1703             define_os_defaults(inFile) ||
1704             optional_include(inFile, "IMAKE_LOCAL_DEFINES", "localdefines") ||
1705             optional_include(inFile, "IMAKE_ADMIN_DEFINES", "admindefines") ||
1706             fprintf(inFile, "#define %s <%s>\n", ImakeDefSym, imakefile) < 0 ||
1707             fprintf(inFile, LocalDefineFmt, ImakeTmplSym, template) < 0 ||
1708             fprintf(inFile, IncludeFmt, ImakeTmplSym) < 0 ||
1709             optional_include(inFile, "IMAKE_ADMIN_MACROS", "adminmacros") ||
1710             optional_include(inFile, "IMAKE_LOCAL_MACROS", "localmacros") ||
1711             fflush(inFile) ||
1712             fclose(inFile))
1713                 LogFatal("Cannot write to %s.", masterc);
1714         /*
1715          * Fork and exec cpp
1716          */
1717         doit(outfd, cpp, cpp_argv);
1718         CleanCppOutput(outfd, outfname);
1719 }
1720
1721 void
1722 makeit(void)
1723 {
1724         doit(NULL, make_argv[0], make_argv);
1725 }
1726
1727 const char *
1728 CleanCppInput(const char *imakefile)
1729 {
1730         FILE    *outFile = NULL;
1731         FILE    *inFile;
1732         char    *buf,           /* buffer for file content */
1733                 *pbuf,          /* walking pointer to buf */
1734                 *punwritten,    /* pointer to unwritten portion of buf */
1735                 *ptoken,        /* pointer to # token */
1736                 *pend,          /* pointer to end of # token */
1737                 savec;          /* temporary character holder */
1738         int     count;
1739         struct stat     st;
1740
1741         /*
1742          * grab the entire file.
1743          */
1744         if (!(inFile = fopen(imakefile, "r")))
1745                 LogFatal("Cannot open %s for input.", imakefile);
1746         if (fstat(fileno(inFile), &st) < 0)
1747                 LogFatal("Cannot stat %s for size.", imakefile);
1748         buf = Emalloc((int)st.st_size+3);
1749         count = fread(buf + 2, 1, st.st_size, inFile);
1750         if (count == 0 && st.st_size != 0)
1751                 LogFatal("Cannot read %s:", imakefile);
1752         fclose(inFile);
1753         buf[0] = '\n';
1754         buf[1] = '\n';
1755         buf[count + 2] = '\0';
1756
1757         punwritten = pbuf = buf + 2;
1758         while (*pbuf) {
1759             /* for compatibility, replace make comments for cpp */
1760             if (*pbuf == '#' && pbuf[-1] == '\n' && pbuf[-2] != '\\') {
1761                 ptoken = pbuf+1;
1762                 while (*ptoken == ' ' || *ptoken == '\t')
1763                         ptoken++;
1764                 pend = ptoken;
1765                 while (*pend && *pend != ' ' && *pend != '\t' && *pend != '\n' && *pend != '\r')
1766                         pend++;
1767                 savec = *pend;
1768                 *pend = '\0';
1769                 if (strcmp(ptoken, "define") &&
1770                     strcmp(ptoken, "if") &&
1771                     strcmp(ptoken, "ifdef") &&
1772                     strcmp(ptoken, "ifndef") &&
1773                     strcmp(ptoken, "include") &&
1774                     strcmp(ptoken, "line") &&
1775                     strcmp(ptoken, "else") &&
1776                     strcmp(ptoken, "elif") &&
1777                     strcmp(ptoken, "endif") &&
1778                     strcmp(ptoken, "error") &&
1779                     strcmp(ptoken, "pragma") &&
1780                     strcmp(ptoken, "undef")) {
1781                     if (outFile == NULL) {
1782 #ifdef HAVE_MKSTEMP
1783                         int fd;
1784 #endif
1785                         char *tmpImakefileName = Strdup(tmpImakefileTemplate);
1786 #ifndef HAVE_MKSTEMP
1787                         if (mktemp(tmpImakefileName) == NULL ||
1788                             (outFile = fopen(tmpImakefileName, "w+")) == NULL) {
1789                             LogFatal("Cannot open %s for write.",
1790                                 tmpImakefileName);
1791                         }
1792 #else
1793                         fd=mkstemp(tmpImakefileName);
1794                         if (fd != -1)
1795                             outFile = fdopen(fd, "w");
1796                         if (outFile == NULL) {
1797                             if (fd != -1) {
1798                                unlink(tmpImakefileName); close(fd);
1799                             }
1800                             LogFatal("Cannot open %s for write.",
1801                                 tmpImakefileName);
1802                         }
1803 #endif
1804                         tmpImakefile = tmpImakefileName;
1805                     }
1806                     writetmpfile(outFile, punwritten, pbuf-punwritten,
1807                                  tmpImakefile);
1808                     if (ptoken > pbuf + 1)
1809                         writetmpfile(outFile, "XCOMM", 5, tmpImakefile);
1810                     else
1811                         writetmpfile(outFile, "XCOMM ", 6, tmpImakefile);
1812                     punwritten = pbuf + 1;
1813                 }
1814                 *pend = savec;
1815             }
1816             pbuf++;
1817         }
1818         if (outFile) {
1819             writetmpfile(outFile, punwritten, pbuf-punwritten, tmpImakefile);
1820             fclose(outFile);
1821
1822             return tmpImakefile;
1823         }
1824
1825         return(imakefile);
1826 }
1827
1828 void
1829 CleanCppOutput(FILE *tmpfd, const char *tmpfname)
1830 {
1831         char    *input;
1832         int     blankline = 0;
1833
1834         while((input = ReadLine(tmpfd, tmpfname))) {
1835                 if (isempty(input)) {
1836                         if (blankline++)
1837                                 continue;
1838 #ifdef CROSSCOMPILE
1839                         if (fixup_whitespace)
1840 #endif
1841 #if defined CROSSCOMPILE || defined FIXUP_CPP_WHITESPACE
1842                             KludgeResetRule();
1843 #endif
1844                 } else {
1845                         blankline = 0;
1846 #ifdef CROSSCOMPILE
1847                         if (fixup_whitespace)
1848 #endif
1849 #if defined CROSSCOMPILE || defined FIXUP_CPP_WHITESPACE
1850                             KludgeOutputLine(&input);
1851 #endif
1852                         writetmpfile(tmpfd, input, strlen(input), tmpfname);
1853                 }
1854                 writetmpfile(tmpfd, "\n", 1, tmpfname);
1855         }
1856         fflush(tmpfd);
1857 #ifdef NFS_STDOUT_BUG
1858         /*
1859          * On some systems, NFS seems to leave a large number of nulls at
1860          * the end of the file.  Ralph Swick says that this kludge makes the
1861          * problem go away.
1862          */
1863         ftruncate (fileno(tmpfd), (off_t)ftell(tmpfd));
1864 #endif
1865 }
1866
1867 /*
1868  * Determine if a line has nothing in it.  As a side effect, we trim white
1869  * space from the end of the line.  Cpp magic cookies are also thrown away.
1870  * "XCOMM" token is transformed to "#".
1871  */
1872 boolean
1873 isempty(char *line)
1874 {
1875         char    *pend;
1876
1877         /*
1878          * Check for lines of the form
1879          *      # n "...
1880          * or
1881          *      # line n "...
1882          */
1883         if (*line == '#') {
1884                 pend = line+1;
1885                 if (*pend == ' ')
1886                         pend++;
1887                 if (*pend == 'l' && pend[1] == 'i' && pend[2] == 'n' &&
1888                     pend[3] == 'e' && pend[4] == ' ')
1889                         pend += 5;
1890                 if (isdigit(*pend)) {
1891                         do {
1892                             pend++;
1893                         } while (isdigit(*pend));
1894                         if (*pend == '\n' || *pend == '\0')
1895                                 return(TRUE);
1896                         if (*pend++ == ' ' && *pend == '"')
1897                                 return(TRUE);
1898                 }
1899                 while (*pend)
1900                     pend++;
1901         } else {
1902             for (pend = line; *pend; pend++) {
1903                 if (*pend == 'X' && pend[1] == 'C' && pend[2] == 'O' &&
1904                     pend[3] == 'M' && pend[4] == 'M' &&
1905                     (pend == line || pend[-1] == ' ' || pend[-1] == '\t' || pend[-1] == '\r') &&
1906                     (pend[5] == ' ' || pend[5] == '\t' || pend[5] == '\r' || pend[5] == '\0'))
1907                 {
1908                     *pend = '#';
1909                     memmove(pend+1, pend+5, strlen(pend+5)+1);
1910                 }
1911 #ifdef CROSSCOMPILE
1912                 if (magic_make_vars)
1913 #endif
1914                   {
1915 #if defined CROSSCOMPILE || defined MAGIC_MAKE_VARS
1916                     if (*pend == 'X' && pend[1] == 'V' && pend[2] == 'A' &&
1917                         pend[3] == 'R')
1918                     {
1919                         char varbuf[5];
1920                         int i;
1921
1922                         if (pend[4] == 'd' && pend[5] == 'e' && pend[6] == 'f' &&
1923                             pend[7] >= '0' && pend[7] <= '9')
1924                         {
1925                             i = pend[7] - '0';
1926                             sprintf(varbuf, "%0.4d", xvariable);
1927                             strncpy(pend+4, varbuf, 4);
1928                             xvariables[i] = xvariable;
1929                             xvariable = (xvariable + 1) % 10000;
1930                         }
1931                         else if (pend[4] == 'u' && pend[5] == 's' &&
1932                                  pend[6] == 'e' && pend[7] >= '0' &&
1933                                  pend[7] <= '9')
1934                         {
1935                             i = pend[7] - '0';
1936                             sprintf(varbuf, "%0.4d", xvariables[i]);
1937                             strncpy(pend+4, varbuf, 4);
1938                         }
1939                     }
1940 #endif
1941                 }
1942             }
1943         }
1944         while (--pend >= line && (*pend == ' ' || *pend == '\t' || *pend == '\r')) ;
1945         pend[1] = '\0';
1946         return (*line == '\0');
1947 }
1948
1949 /*ARGSUSED*/
1950 char *
1951 ReadLine(FILE *tmpfd, const char *tmpfname)
1952 {
1953         static boolean  initialized = FALSE;
1954         static char     *buf, *pline, *end;
1955         register char   *p1, *p2;
1956
1957         if (! initialized) {
1958 #ifdef WIN32
1959                 FILE *fp = tmpfd;
1960 #endif
1961                 int total_red;
1962                 struct stat st;
1963
1964                 /*
1965                  * Slurp it all up.
1966                  */
1967                 fseek(tmpfd, 0, 0);
1968                 if (fstat(fileno(tmpfd), &st) < 0)
1969                         LogFatal("cannot stat %s for size", tmpMakefile);
1970                 pline = buf = Emalloc((int)st.st_size+1);
1971                 total_red = fread(buf, 1, st.st_size, tmpfd);
1972                 if (total_red == 0 && st.st_size != 0)
1973                         LogFatal("cannot read %s", tmpMakefile);
1974                 end = buf + total_red;
1975                 *end = '\0';
1976                 fseek(tmpfd, 0, 0);
1977 #if defined(SYSV) || defined(WIN32) || defined(USE_FREOPEN)
1978                 tmpfd = freopen(tmpfname, "w+", tmpfd);
1979 # ifdef WIN32
1980                 if (! tmpfd) /* if failed try again */
1981                         tmpfd = freopen(tmpfname, "w+", fp);
1982 # endif
1983                 if (! tmpfd)
1984                         LogFatal("cannot reopen %s\n", tmpfname);
1985 #else   /* !SYSV */
1986                 ftruncate(fileno(tmpfd), (off_t) 0);
1987 #endif  /* !SYSV */
1988                 initialized = TRUE;
1989             fprintf (tmpfd, "# Makefile generated by imake - do not edit!\n");
1990         }
1991
1992         for (p1 = pline; p1 < end; p1++) {
1993                 if (*p1 == '@' && *(p1+1) == '@'
1994                     /* ignore ClearCase version-extended pathnames */
1995                     && !(p1 != pline && !isspace(*(p1-1)) && *(p1+2) == '/'))
1996                 { /* soft EOL */
1997                         *p1++ = '\0';
1998                         p1++; /* skip over second @ */
1999                         break;
2000                 }
2001                 else if (*p1 == '\n') { /* real EOL */
2002 #if defined CROSSCOMPILE || defined WIN32
2003 # if defined CROSSCOMPILE
2004                   if (sys == win32)
2005 # endif
2006                     {
2007                         if (p1 > pline && p1[-1] == '\r')
2008                                 p1[-1] = '\0';
2009                     }
2010 #endif
2011                         *p1++ = '\0';
2012                         break;
2013                 }
2014         }
2015
2016         /*
2017          * return NULL at the end of the file.
2018          */
2019         p2 = (pline == p1 ? NULL : pline);
2020         pline = p1;
2021         return(p2);
2022 }
2023
2024 void
2025 writetmpfile(FILE *fd, const char *buf, int cnt, const char *fname)
2026 {
2027         if (fwrite(buf, sizeof(char), cnt, fd) == -1)
2028                 LogFatal("Cannot write to %s.", fname);
2029 }
2030
2031 char *
2032 Emalloc(int size)
2033 {
2034         char    *p;
2035
2036         if ((p = malloc(size)) == NULL)
2037                 LogFatal("Cannot allocate %d bytes", size);
2038         return(p);
2039 }
2040
2041 #if defined CROSSCOMPILE || defined FIXUP_CPP_WHITESPACE
2042 void
2043 KludgeOutputLine(char **pline)
2044 {
2045         char    *p = *pline;
2046         char    quotechar = '\0';
2047
2048         switch (*p) {
2049             case '#':   /*Comment - ignore*/
2050                 break;
2051             case '\t':  /*Already tabbed - ignore it*/
2052                 break;
2053             case ' ':   /*May need a tab*/
2054             default:
2055 # ifdef CROSSCOMPILE
2056                 if (inline_syntax)
2057 # endif
2058 # if defined CROSSCOMPILE || defined INLINE_SYNTAX
2059                 {
2060                     if (*p == '<' && p[1] == '<') { /* inline file close */
2061                         InInline--;
2062                         InRule = TRUE;
2063                         break;
2064                     }
2065                 }
2066 # endif
2067                 /*
2068                  * The following cases should not be treated as beginning of
2069                  * rules:
2070                  * variable := name (GNU make)
2071                  * variable = .*:.* (':' should be allowed as value)
2072                  * sed 's:/a:/b:'   (: used in quoted values)
2073                  */
2074                 for (; *p; p++) {
2075                     if (quotechar) {
2076                         if (quotechar == '\\' ||
2077                             (*p == quotechar &&
2078 # if defined CROSSCOMPILE || defined WIN32
2079                              (
2080 #  if defined CROSSCOMPILE
2081                               (sys == win32) &&
2082 #  endif
2083                               quotechar != ')') &&
2084 # endif
2085                              p[-1] != '\\'))
2086                             quotechar = '\0';
2087                         continue;
2088                     }
2089                     switch (*p) {
2090                     case '\\':
2091                     case '"':
2092                     case '\'':
2093                         quotechar = *p;
2094                         break;
2095                     case '(':
2096                         quotechar = ')';
2097                         break;
2098                     case '{':
2099                         quotechar = '}';
2100                         break;
2101                     case '[':
2102                         quotechar = ']';
2103                         break;
2104                     case '=':
2105 # ifdef CROSSCOMPILE
2106                         if (remove_cpp_leadspace)
2107 # endif
2108 # if defined CROSSCOMPILE || defined REMOVE_CPP_LEADSPACE
2109                         {
2110                             if (!InRule && **pline == ' ') {
2111                                 while (**pline == ' ')
2112                                     (*pline)++;
2113                             }
2114                         }
2115 # endif
2116                         goto breakfor;
2117 # if defined CROSSCOMPILE || defined INLINE_SYNTAX
2118                     case '<':
2119                         if (inline_syntax) {
2120                             if (p[1] == '<') /* inline file start */
2121                                 InInline++;
2122                         }
2123                         break;
2124 # endif
2125                     case ':':
2126                         if (p[1] == '=')
2127                             goto breakfor;
2128                         while (**pline == ' ')
2129                             (*pline)++;
2130                         InRule = TRUE;
2131                         return;
2132                     }
2133                 }
2134 breakfor:
2135                 if (InRule && **pline == ' ')
2136                     **pline = '\t';
2137                 break;
2138         }
2139 }
2140
2141 void
2142 KludgeResetRule(void)
2143 {
2144         InRule = FALSE;
2145 }
2146 #endif
2147 char *
2148 Strdup(const char *cp)
2149 {
2150         char *new = Emalloc(strlen(cp) + 1);
2151
2152         strcpy(new, cp);
2153         return new;
2154 }
2155
2156 #ifdef CROSSCOMPILE
2157 char*
2158 CrossCompileCPP(void)
2159 {
2160     char *cpp, *c;
2161     int len ;
2162     if (crosscompile_use_cc_e)
2163         AddCppArg("-E");
2164
2165     cpp = strrchr(crosscompile_cpp,'/');
2166     if (!cpp)
2167         cpp = crosscompile_cpp;
2168     else
2169         cpp++;
2170
2171     len = strlen(cpp) + strlen(CrossCompileDir) + 2;
2172     c = Emalloc(len);
2173
2174     (void)snprintf(c, len,"%s/%s",CrossCompileDir,cpp);
2175
2176     return c;
2177 }
2178
2179 #endif
2180
2181 #ifdef CROSSCOMPILE
2182 static void
2183 get_cross_compile_dir(FILE *inFile)
2184 {
2185         fprintf(inFile, "#define CrossCompileDir %s\n",
2186                 CrossCompileDir);
2187         fprintf(inFile, "#define CrossCompiling YES\n");
2188 }
2189 #endif