]> git.sesse.net Git - rdpsrv/blob - Xserver/config/imake/imake.c
Support RDP5 logon packets.
[rdpsrv] / Xserver / config / imake / imake.c
1 /* $TOG: imake.c /main/97 1997/06/20 20:23:51 kaleb $ */
2
3 /***************************************************************************
4  *                                                                         *
5  *                                Porting Note                             *
6  *                                                                         *
7  * Add the value of BOOTSTRAPCFLAGS to the cpp_argv table so that it will  *
8  * be passed to the template file.                                         *
9  *                                                                         *
10  ***************************************************************************/
11 /* $XFree86: xc/config/imake/imake.c,v 3.13.2.16 1998/03/01 00:34:54 dawes Exp $ */
12
13 /*
14  * 
15 Copyright (c) 1985, 1986, 1987  X Consortium
16
17 Permission is hereby granted, free of charge, to any person obtaining a copy
18 of this software and associated documentation files (the "Software"), to deal
19 in the Software without restriction, including without limitation the rights
20 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21 copies of the Software, and to permit persons to whom the Software is
22 furnished to do so, subject to the following conditions:
23
24 The above copyright notice and this permission notice shall be included in
25 all copies or substantial portions of the Software.
26
27 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
30 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
31 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33
34 Except as contained in this notice, the name of the X Consortium shall not be
35 used in advertising or otherwise to promote the sale, use or other dealings
36 in this Software without prior written authorization from the X Consortium.
37  * 
38  * Original Author:
39  *      Todd Brunhoff
40  *      Tektronix, inc.
41  *      While a guest engineer at Project Athena, MIT
42  *
43  * imake: the include-make program.
44  *
45  * Usage: imake [-Idir] [-Ddefine] [-T template] [-f imakefile ] [-C Imakefile.c ] [-s] [-e] [-v] [make flags]
46  *
47  * Imake takes a template file (Imake.tmpl) and a prototype (Imakefile)
48  * and runs cpp on them producing a Makefile.  It then optionally runs make
49  * on the Makefile.
50  * Options:
51  *              -D      define.  Same as cpp -D argument.
52  *              -I      Include directory.  Same as cpp -I argument.
53  *              -T      template.  Designate a template other
54  *                      than Imake.tmpl
55  *              -f      specify the Imakefile file
56  *              -C      specify the name to use instead of Imakefile.c
57  *              -s[F]   show.  Show the produced makefile on the standard
58  *                      output.  Make is not run is this case.  If a file
59  *                      argument is provided, the output is placed there.
60  *              -e[F]   execute instead of show; optionally name Makefile F
61  *              -v      verbose.  Show the make command line executed.
62  *
63  * Environment variables:
64  *              
65  *              IMAKEINCLUDE    Include directory to use in addition to "."
66  *              IMAKECPP        Cpp to use instead of /lib/cpp
67  *              IMAKEMAKE       make program to use other than what is
68  *                              found by searching the $PATH variable.
69  * Other features:
70  *      imake reads the entire cpp output into memory and then scans it
71  *      for occurences of "@@".  If it encounters them, it replaces it with
72  *      a newline.  It also trims any trailing white space on output lines
73  *      (because make gets upset at them).  This helps when cpp expands
74  *      multi-line macros but you want them to appear on multiple lines.
75  *      It also changes occurences of "XCOMM" to "#", to avoid problems
76  *      with treating commands as invalid preprocessor commands.
77  *
78  *      The macros MAKEFILE and MAKE are provided as macros
79  *      to make.  MAKEFILE is set to imake's makefile (not the constructed,
80  *      preprocessed one) and MAKE is set to argv[0], i.e. the name of
81  *      the imake program.
82  *
83  * Theory of operation:
84  *   1. Determine the name of the imakefile from the command line (-f)
85  *      or from the content of the current directory (Imakefile or imakefile).
86  *      Call this <imakefile>.  This gets added to the arguments for
87  *      make as MAKEFILE=<imakefile>.
88  *   2. Determine the name of the template from the command line (-T)
89  *      or the default, Imake.tmpl.  Call this <template>
90  *   3. Determine the name of the imakeCfile from the command line (-C)
91  *      or the default, Imakefile.c.  Call this <imakeCfile>
92  *   4. Store lines of input into <imakeCfile>:
93  *      - A c-style comment header (see ImakefileCHeader below), used
94  *        to recognize temporary files generated by imake.
95  *      - If DEFAULT_OS_NAME is defined, format the utsname struct and
96  *        call the result <defaultOsName>.  Add:
97  *              #define DefaultOSName <defaultOsName>
98  *      - If DEFAULT_OS_MAJOR_REV is defined, format the utsname struct
99  *        and call the result <defaultOsMajorVersion>.  Add:
100  *              #define DefaultOSMajorVersion <defaultOsMajorVersion>
101  *      - If DEFAULT_OS_MINOR_REV is defined, format the utsname struct
102  *        and call the result <defaultOsMinorVersion>.  Add:
103  *              #define DefaultOSMinorVersion <defaultOsMinorVersion>
104  *      - If DEFAULT_OS_TEENY_REV is defined, format the utsname struct
105  *        and call the result <defaultOsTeenyVersion>.  Add:
106  *              #define DefaultOSTeenyVersion <defaultOsTeenyVersion>
107  *      - If DEFAULT_MACHINE_ARCITECTURE is defined, format the utsname struct
108  *        and define the corresponding macro. (For example on the amiga,
109  *        this will define amiga in addition to m68k).    
110  *      - If the file "localdefines" is readable in the current
111  *        directory, print a warning message to stderr and add: 
112  *              #define IMAKE_LOCAL_DEFINES     "localdefines"
113  *              #include IMAKE_LOCAL_DEFINES
114  *      - If the file "admindefines" is readable in the current
115  *        directory, print a warning message to stderr and add: 
116  *              #define IMAKE_ADMIN_DEFINES     "admindefines"
117  *              #include IMAKE_ADMIN_DEFINES
118  *      - The following lines:
119  *              #define INCLUDE_IMAKEFILE       < <imakefile> >
120  *              #define IMAKE_TEMPLATE          " <template> "
121  *              #include IMAKE_TEMPLATE
122  *      - If the file "adminmacros" is readable in the current
123  *        directory, print a warning message to stderr and add: 
124  *              #define IMAKE_ADMIN_MACROS      "adminmacros"
125  *              #include IMAKE_ADMIN_MACROS
126  *      - If the file "localmacros" is readable in the current
127  *        directory, print a warning message to stderr and add: 
128  *              #define IMAKE_LOCAL_MACROS      "localmacros"
129  *              #include IMAKE_LOCAL_MACROS
130  *   5. Start up cpp and provide it with this file.
131  *      Note that the define for INCLUDE_IMAKEFILE is intended for
132  *      use in the template file.  This implies that the imake is
133  *      useless unless the template file contains at least the line
134  *              #include INCLUDE_IMAKEFILE
135  *   6. Gather the output from cpp, and clean it up, expanding @@ to
136  *      newlines, stripping trailing white space, cpp control lines,
137  *      and extra blank lines, and changing XCOMM to #.  This cleaned
138  *      output is placed in a new file, default "Makefile", but can
139  *      be specified with -s or -e options.
140  *   7. Optionally start up make on the resulting file.
141  *
142  * The design of the template makefile should therefore be:
143  *      <set global macros like CFLAGS, etc.>
144  *      <include machine dependent additions>
145  *      #include INCLUDE_IMAKEFILE
146  *      <add any global targets like 'clean' and long dependencies>
147  */
148 #if defined(__FreeBSD__) || defined(__NetBSD__)
149 /* This needs to be before _POSIX_SOURCE gets defined */
150 # include <sys/param.h>
151 # include <sys/types.h>
152 # include <sys/sysctl.h>
153 #endif
154 #include <stdio.h>
155 #include "Xosdefs.h"
156 #ifndef X_NOT_STDC_ENV
157 #include <string.h>
158 #endif
159 #include <ctype.h>
160 #ifdef WIN32
161 # include "Xw32defs.h"
162 #endif
163 #ifndef X_NOT_POSIX
164 # ifndef _POSIX_SOURCE
165 #  define _POSIX_SOURCE
166 # endif
167 #endif
168 #include <sys/types.h>
169 #include <fcntl.h>
170 #ifdef X_NOT_POSIX
171 # ifndef WIN32
172 #  include <sys/file.h>
173 # endif
174 #else
175 # include <unistd.h>
176 #endif
177 #ifdef ISC
178 # include <unistd.h>
179 #endif
180 #if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE)
181 # include <signal.h>
182 #else
183 # define _POSIX_SOURCE
184 # include <signal.h>
185 # undef _POSIX_SOURCE
186 #endif
187 #if !defined(SIGCHLD) && defined(SIGCLD)
188 # define SIGCHLD                SIGCLD
189 #endif
190 #include <sys/stat.h>
191 #ifndef X_NOT_POSIX
192 # ifdef _POSIX_SOURCE
193 #  ifdef SCO325
194 #   include <sys/procset.h>
195 #   include <sys/siginfo.h>
196 #  endif
197 #  include <sys/wait.h>
198 # else
199 #  define _POSIX_SOURCE
200 #  include <sys/wait.h>
201 #  undef _POSIX_SOURCE
202 # endif
203 # define waitCode(w)    WEXITSTATUS(w)
204 # define waitSig(w)     WTERMSIG(w)
205 typedef int             waitType;
206 #else /* X_NOT_POSIX */
207 # ifdef SYSV
208 #  define waitCode(w)   (((w) >> 8) & 0x7f)
209 #  define waitSig(w)    ((w) & 0xff)
210 typedef int             waitType;
211 # else /* SYSV */
212 #  ifdef WIN32
213 #   include <process.h>
214 typedef int             waitType;
215 #  else
216 #   include <sys/wait.h>
217 #   define waitCode(w)  ((w).w_T.w_Retcode)
218 #   define waitSig(w)   ((w).w_T.w_Termsig)
219 typedef union wait      waitType;
220 #  endif
221 # endif
222 # ifndef WIFSIGNALED
223 #  define WIFSIGNALED(w) waitSig(w)
224 # endif
225 # ifndef WIFEXITED
226 #  define WIFEXITED(w) waitCode(w)
227 # endif
228 #endif /* X_NOT_POSIX */
229 #ifndef X_NOT_STDC_ENV
230 # include <stdlib.h>
231 #else
232 char *malloc(), *realloc();
233 void exit();
234 #endif
235 #if defined(macII) && !defined(__STDC__)  /* stdlib.h fails to define these */
236 char *malloc(), *realloc();
237 #endif /* macII */
238 #ifdef X_NOT_STDC_ENV
239 extern char     *getenv();
240 #endif
241 #include <errno.h>
242 #ifdef X_NOT_STDC_ENV
243 extern int      errno;
244 #endif
245 #ifdef __minix_vmd
246 #define USE_FREOPEN             1
247 #endif
248
249 #if !(defined(X_NOT_STDC_ENV) || (defined(sun) && !defined(SVR4)) || defined(macII))
250 #define USE_STRERROR            1
251 #endif
252 #ifdef __EMX__
253 #define USE_STRERROR            1
254 #endif
255 #ifndef WIN32
256 #include <sys/utsname.h>
257 #endif
258 #ifndef SYS_NMLN
259 # ifdef _SYS_NMLN
260 #  define SYS_NMLN _SYS_NMLN
261 # else
262 #  define SYS_NMLN 257
263 # endif
264 #endif
265 #ifdef linux
266 #include <limits.h>
267 #endif
268 /* 
269  * is strstr() in <strings.h> on X_NOT_STDC_ENV? 
270  * are there any X_NOT_STDC_ENV machines left in the world?
271  */
272 #include <string.h>
273 #include "imakemdep.h"
274
275 /*
276  * This define of strerror is copied from (and should be identical to)
277  * Xos.h, which we don't want to include here for bootstrapping reasons.
278  */
279 #ifndef USE_STRERROR
280 # ifndef strerror
281 extern char *sys_errlist[];
282 extern int sys_nerr;
283 #  define strerror(n) \
284     (((n) >= 0 && (n) < sys_nerr) ? sys_errlist[n] : "unknown error")
285 # endif
286 #endif
287
288 #define TRUE            1
289 #define FALSE           0
290
291 #ifdef FIXUP_CPP_WHITESPACE
292 int     InRule = FALSE;
293 # ifdef INLINE_SYNTAX
294 int     InInline = 0;
295 # endif
296 #endif
297 #ifdef MAGIC_MAKE_VARS
298 int xvariable = 0;
299 int xvariables[10];
300 #endif
301
302 /*
303  * Some versions of cpp reduce all tabs in macro expansion to a single
304  * space.  In addition, the escaped newline may be replaced with a
305  * space instead of being deleted.  Blech.
306  */
307 #ifdef FIXUP_CPP_WHITESPACE
308 void KludgeOutputLine(), KludgeResetRule();
309 #else
310 # define KludgeOutputLine(arg)
311 # define KludgeResetRule()
312 #endif
313
314 typedef unsigned char   boolean;
315
316 #ifdef USE_CC_E
317 # ifndef DEFAULT_CC
318 #  define DEFAULT_CC "cc"
319 # endif
320 #else
321 # ifndef DEFAULT_CPP
322 #  ifdef CPP_PROGRAM
323 #   define DEFAULT_CPP CPP_PROGRAM
324 #  else
325 #   define DEFAULT_CPP "/lib/cpp"
326 #  endif
327 # endif
328 #endif
329
330 char *cpp = NULL;
331
332 char    *tmpMakefile    = "/tmp/Imf.XXXXXX";
333 char    *tmpImakefile    = "/tmp/IIf.XXXXXX";
334 char    *make_argv[ ARGUMENTS ] = {
335 #ifdef WIN32
336     "nmake"
337 #else
338     "make"
339 #endif
340 };
341
342 int     make_argindex;
343 int     cpp_argindex;
344 char    *Imakefile = NULL;
345 char    *Makefile = "Makefile";
346 char    *Template = "Imake.tmpl";
347 char    *ImakefileC = "Imakefile.c";
348 boolean haveImakefileC = FALSE;
349 char    *cleanedImakefile = NULL;
350 char    *program;
351 char    *FindImakefile();
352 char    *ReadLine();
353 char    *CleanCppInput();
354 char    *Strdup();
355 char    *Emalloc();
356 void    LogFatalI(), LogFatal(), LogMsg();
357
358 void    showit();
359 void    wrapup();
360 void    init();
361 void    AddMakeArg();
362 void    AddCppArg();
363 void    SetOpts();
364 void    CheckImakefileC();
365 void    cppit();
366 void    makeit();
367 void    CleanCppOutput();
368 boolean isempty();
369 void    writetmpfile();
370
371 boolean verbose = FALSE;
372 boolean show = TRUE;
373
374 int
375 main(argc, argv)
376         int     argc;
377         char    **argv;
378 {
379         FILE    *tmpfd;
380         char    makeMacro[ BUFSIZ ];
381         char    makefileMacro[ BUFSIZ ];
382
383         program = argv[0];
384         init();
385         SetOpts(argc, argv);
386
387         Imakefile = FindImakefile(Imakefile);
388         CheckImakefileC(ImakefileC);
389         if (Makefile)
390                 tmpMakefile = Makefile;
391         else {
392                 tmpMakefile = Strdup(tmpMakefile);
393                 (void) mktemp(tmpMakefile);
394         }
395         AddMakeArg("-f");
396         AddMakeArg( tmpMakefile );
397         sprintf(makeMacro, "MAKE=%s", program);
398         AddMakeArg( makeMacro );
399         sprintf(makefileMacro, "MAKEFILE=%s", Imakefile);
400         AddMakeArg( makefileMacro );
401
402         if ((tmpfd = fopen(tmpMakefile, "w+")) == NULL)
403                 LogFatal("Cannot create temporary file %s.", tmpMakefile);
404
405         cleanedImakefile = CleanCppInput(Imakefile);
406         cppit(cleanedImakefile, Template, ImakefileC, tmpfd, tmpMakefile);
407
408         if (show) {
409                 if (Makefile == NULL)
410                         showit(tmpfd);
411         } else
412                 makeit();
413         wrapup();
414         exit(0);
415 }
416
417 void
418 showit(fd)
419         FILE    *fd;
420 {
421         char    buf[ BUFSIZ ];
422         int     red;
423
424         fseek(fd, 0, 0);
425         while ((red = fread(buf, 1, BUFSIZ, fd)) > 0)
426                 writetmpfile(stdout, buf, red, "stdout");
427         if (red < 0)
428             LogFatal("Cannot read %s.", tmpMakefile);
429 }
430
431 void
432 wrapup()
433 {
434         if (tmpMakefile != Makefile)
435                 unlink(tmpMakefile);
436         if (cleanedImakefile && cleanedImakefile != Imakefile)
437                 unlink(cleanedImakefile);
438         if (haveImakefileC)
439                 unlink(ImakefileC);
440 }
441
442 #ifdef SIGNALRETURNSINT
443 int
444 #else
445 void
446 #endif
447 catch(sig)
448         int     sig;
449 {
450         errno = 0;
451         LogFatalI("Signal %d.", sig);
452 }
453
454 /*
455  * Initialize some variables.
456  */
457 void
458 init()
459 {
460         register char   *p;
461
462         make_argindex=0;
463         while (make_argv[ make_argindex ] != NULL)
464                 make_argindex++;
465         cpp_argindex = 0;
466         while (cpp_argv[ cpp_argindex ] != NULL)
467                 cpp_argindex++;
468
469         /*
470          * See if the standard include directory is different than
471          * the default.  Or if cpp is not the default.  Or if the make
472          * found by the PATH variable is not the default.
473          */
474         if (p = getenv("IMAKEINCLUDE")) {
475                 if (*p != '-' || *(p+1) != 'I')
476                         LogFatal("Environment var IMAKEINCLUDE %s",
477                                 "must begin with -I");
478                 AddCppArg(p);
479                 for (; *p; p++)
480                         if (*p == ' ') {
481                                 *p++ = '\0';
482                                 AddCppArg(p);
483                         }
484         }
485         if (p = getenv("IMAKECPP"))
486                 cpp = p;
487         if (p = getenv("IMAKEMAKE"))
488                 make_argv[0] = p;
489
490         if (signal(SIGINT, SIG_IGN) != SIG_IGN)
491                 signal(SIGINT, catch);
492 #ifdef SIGCHLD
493         signal(SIGCHLD, SIG_DFL);
494 #endif
495 }
496
497 void
498 AddMakeArg(arg)
499         char    *arg;
500 {
501         errno = 0;
502         if (make_argindex >= ARGUMENTS-1)
503                 LogFatal("Out of internal storage.", "");
504         make_argv[ make_argindex++ ] = arg;
505         make_argv[ make_argindex ] = NULL;
506 }
507
508 void
509 AddCppArg(arg)
510         char    *arg;
511 {
512         errno = 0;
513         if (cpp_argindex >= ARGUMENTS-1)
514                 LogFatal("Out of internal storage.", "");
515         cpp_argv[ cpp_argindex++ ] = arg;
516         cpp_argv[ cpp_argindex ] = NULL;
517 }
518
519 void
520 SetOpts(argc, argv)
521         int     argc;
522         char    **argv;
523 {
524         errno = 0;
525         /*
526          * Now gather the arguments for make
527          */
528         for(argc--, argv++; argc; argc--, argv++) {
529             /*
530              * We intercept these flags.
531              */
532             if (argv[0][0] == '-') {
533                 if (argv[0][1] == 'D') {
534                     AddCppArg(argv[0]);
535                 } else if (argv[0][1] == 'I') {
536                     AddCppArg(argv[0]);
537                 } else if (argv[0][1] == 'f') {
538                     if (argv[0][2])
539                         Imakefile = argv[0]+2;
540                     else {
541                         argc--, argv++;
542                         if (! argc)
543                             LogFatal("No description arg after -f flag", "");
544                         Imakefile = argv[0];
545                     }
546                 } else if (argv[0][1] == 's') {
547                     if (argv[0][2])
548                         Makefile = ((argv[0][2] == '-') && !argv[0][3]) ?
549                             NULL : argv[0]+2;
550                     else {
551                         argc--, argv++;
552                         if (!argc)
553                             LogFatal("No description arg after -s flag", "");
554                         Makefile = ((argv[0][0] == '-') && !argv[0][1]) ?
555                             NULL : argv[0];
556                     }
557                     show = TRUE;
558                 } else if (argv[0][1] == 'e') {
559                    Makefile = (argv[0][2] ? argv[0]+2 : NULL);
560                    show = FALSE;
561                 } else if (argv[0][1] == 'T') {
562                     if (argv[0][2])
563                         Template = argv[0]+2;
564                     else {
565                         argc--, argv++;
566                         if (! argc)
567                             LogFatal("No description arg after -T flag", "");
568                         Template = argv[0];
569                     }
570                 } else if (argv[0][1] == 'C') {
571                     if (argv[0][2])
572                         ImakefileC = argv[0]+2;
573                     else {
574                         argc--, argv++;
575                         if (! argc)
576                             LogFatal("No imakeCfile arg after -C flag", "");
577                         ImakefileC = argv[0];
578                     }
579                 } else if (argv[0][1] == 'v') {
580                     verbose = TRUE;
581                 } else
582                     AddMakeArg(argv[0]);
583             } else
584                 AddMakeArg(argv[0]);
585         }
586 #ifdef USE_CC_E
587         if (!cpp)
588         {
589                 AddCppArg("-E");
590                 cpp = DEFAULT_CC;
591         }
592 #else
593         if (!cpp)
594                 cpp = DEFAULT_CPP;
595 #endif
596         cpp_argv[0] = cpp;
597         AddCppArg(ImakefileC);
598 }
599
600 char *
601 FindImakefile(Imakefile)
602         char    *Imakefile;
603 {
604         if (Imakefile) {
605                 if (access(Imakefile, R_OK) < 0)
606                         LogFatal("Cannot find %s.", Imakefile);
607         } else {
608                 if (access("Imakefile", R_OK) < 0)
609                         if (access("imakefile", R_OK) < 0)
610                                 LogFatal("No description file.", "");
611                         else
612                                 Imakefile = "imakefile";
613                 else
614                         Imakefile = "Imakefile";
615         }
616         return(Imakefile);
617 }
618
619 void
620 LogFatalI(s, i)
621         char *s;
622         int i;
623 {
624         /*NOSTRICT*/
625         LogFatal(s, (char *)(long)i);
626 }
627
628 void
629 LogFatal(x0,x1)
630         char *x0, *x1;
631 {
632         static boolean  entered = FALSE;
633
634         if (entered)
635                 return;
636         entered = TRUE;
637
638         LogMsg(x0, x1);
639         fprintf(stderr, "  Stop.\n");
640         wrapup();
641         exit(1);
642 }
643
644 void
645 LogMsg(x0,x1)
646         char *x0, *x1;
647 {
648         int error_number = errno;
649
650         if (error_number) {
651                 fprintf(stderr, "%s: ", program);
652                 fprintf(stderr, "%s\n", strerror(error_number));
653         }
654         fprintf(stderr, "%s: ", program);
655         fprintf(stderr, x0, x1);
656         fprintf(stderr, "\n");
657 }
658
659 void
660 showargs(argv)
661         char    **argv;
662 {
663         for (; *argv; argv++)
664                 fprintf(stderr, "%s ", *argv);
665         fprintf(stderr, "\n");
666 }
667
668 #define ImakefileCHeader "/* imake - temporary file */"
669
670 void
671 CheckImakefileC(masterc)
672         char *masterc;
673 {
674         char mkcbuf[1024];
675         FILE *inFile;
676
677         if (access(masterc, F_OK) == 0) {
678                 inFile = fopen(masterc, "r");
679                 if (inFile == NULL)
680                         LogFatal("Refuse to overwrite: %s", masterc);
681                 if ((fgets(mkcbuf, sizeof(mkcbuf), inFile) &&
682                      strncmp(mkcbuf, ImakefileCHeader, 
683                              sizeof(ImakefileCHeader)-1)))
684                 {
685                         fclose(inFile);
686                         LogFatal("Refuse to overwrite: %s", masterc);
687                 }
688                 fclose(inFile);
689         }
690 }
691
692 #define LocalDefineFmt  "#define %s \"%s\"\n"
693 #define IncludeFmt      "#include %s\n"
694 #define ImakeDefSym     "INCLUDE_IMAKEFILE"
695 #define ImakeTmplSym    "IMAKE_TEMPLATE"
696 #define OverrideWarning "Warning: local file \"%s\" overrides global macros."
697
698 boolean
699 optional_include(inFile, defsym, fname)
700         FILE    *inFile;
701         char    *defsym;
702         char    *fname;
703 {
704         errno = 0;
705         if (access(fname, R_OK) == 0) {
706                 LogMsg(OverrideWarning, fname);
707                 return (fprintf(inFile, LocalDefineFmt, defsym, fname) < 0 ||
708                         fprintf(inFile, IncludeFmt, defsym) < 0);
709         }
710         return FALSE;
711 }
712
713 void
714 doit(outfd, cmd, argv)
715         FILE    *outfd;
716         char    *cmd;
717         char    **argv;
718 {
719         int     pid;
720         waitType        status;
721
722         /*
723          * Fork and exec the command.
724          */
725 #ifdef WIN32
726         if (outfd)
727                 dup2(fileno(outfd), 1);
728         status = _spawnvp(_P_WAIT, cmd, argv);
729         if (status < 0)
730                 LogFatal("Cannot spawn %s.", cmd);
731         if (status > 0)
732                 LogFatalI("Exit code %d.", status);
733 #else
734         pid = fork();
735         if (pid < 0)
736                 LogFatal("Cannot fork.", "");
737         if (pid) {      /* parent... simply wait */
738                 while (wait(&status) > 0) {
739                         errno = 0;
740                         if (WIFSIGNALED(status))
741                                 LogFatalI("Signal %d.", waitSig(status));
742                         if (WIFEXITED(status) && waitCode(status))
743                                 LogFatalI("Exit code %d.", waitCode(status));
744                 }
745         }
746         else {  /* child... dup and exec cmd */
747                 if (verbose)
748                         showargs(argv);
749                 if (outfd)
750                         dup2(fileno(outfd), 1);
751                 execvp(cmd, argv);
752                 LogFatal("Cannot exec %s.", cmd);
753         }
754 #endif
755 }
756
757 #ifndef WIN32
758 static void
759 parse_utsname(name, fmt, result, msg)
760      struct utsname *name;
761      char *fmt;
762      char *result;
763      char *msg;
764 {
765   char buf[SYS_NMLN * 5 + 1];
766   char *ptr = buf;
767   int arg;
768
769   /* Assemble all the pieces into a buffer. */
770   for (arg = 0; fmt[arg] != ' '; arg++)
771     {
772       /* Our buffer is only guaranteed to hold 5 arguments. */
773       if (arg >= 5)
774         LogFatal(msg, fmt);
775
776       switch (fmt[arg])
777         {
778         case 's':
779           if (arg > 0)
780             *ptr++ = ' ';
781           strcpy(ptr, name->sysname);
782           ptr += strlen(ptr);
783           break;
784
785         case 'n':
786           if (arg > 0)
787             *ptr++ = ' ';
788           strcpy(ptr, name->nodename);
789           ptr += strlen(ptr);
790           break;
791
792         case 'r':
793           if (arg > 0)
794             *ptr++ = ' ';
795           strcpy(ptr, name->release);
796           ptr += strlen(ptr);
797           break;
798
799         case 'v':
800           if (arg > 0)
801             *ptr++ = ' ';
802           strcpy(ptr, name->version);
803           ptr += strlen(ptr);
804           break;
805
806         case 'm':
807           if (arg > 0)
808             *ptr++ = ' ';
809           strcpy(ptr, name->machine);
810           ptr += strlen(ptr);
811           break;
812
813         default:
814           LogFatal(msg, fmt);
815         }
816     }
817
818   /* Just in case... */
819   if (strlen(buf) >= sizeof(buf))
820     LogFatal("Buffer overflow parsing uname.", "");
821
822   /* Parse the buffer.  The sscanf() return value is rarely correct. */
823   *result = '\0';
824   (void) sscanf(buf, fmt + arg + 1, result);
825 }
826
827 /* Trim leading 0's and periods from version names.  The 0's cause
828    the number to be interpreted as octal numbers.  Some version strings
829    have the potential for different numbers of .'s in them.
830  */
831         
832 static char *
833 trim_version(p)
834         char *p;
835 {
836
837         if (p != 0 && *p != '\0')
838         {
839                 while ((*p == '0' || *p == '.') && *(p + 1) != '\0')
840                         ++p;
841         }
842         return (p);
843 }
844 #endif
845
846
847 #ifdef linux
848 const char *libc_c=
849 "#include <stdio.h>\n"
850 "#include <ctype.h>\n"
851 "\n"
852 "#if 0\n"
853 "#pragma weak gnu_get_libc_version\n"
854 "#pragma weak __libc_version\n"
855 "#pragma weak __linux_C_lib_version\n"
856 "#else\n"
857 "asm (\".weak gnu_get_libc_version\");\n"
858 "asm (\".weak __libc_version\");\n"
859 "asm (\".weak __linux_C_lib_version\");\n"
860 "#endif\n"
861 "\n"
862 "extern const char * gnu_get_libc_version (void);\n"
863 "extern const char * __linux_C_lib_version;\n"
864 "extern const char __libc_version [];\n"
865 "\n"
866 "int\n"
867 "main ()\n"
868 "{\n"
869 "  int libcmajor = 0, libcminor = 0, libcteeny = 0;\n"
870 "\n"
871 "  if (((&__linux_C_lib_version != 0)\n"
872 "       && ((&__libc_version != 0) || (gnu_get_libc_version != 0)))\n"
873 "      || (!(&__linux_C_lib_version != 0) && !(&__libc_version != 0)\n"
874 "         && !(gnu_get_libc_version != 0)))\n"
875 "  {\n"
876 "    libcmajor = 0;\n"
877 "    libcminor = 0;\n"
878 "    libcteeny = 0;\n"
879 "  }\n"
880 "  else\n"
881 "  {\n"
882 "    const char * ptr;\n"
883 "    int glibcmajor = 0;\n"
884 "\n"
885 "    if (gnu_get_libc_version != 0)\n"
886 "    {\n"
887 "      ptr = gnu_get_libc_version ();\n"
888 "      glibcmajor = 4;\n"
889 "    }\n"
890 "    else if (&__libc_version != 0)\n"
891 "    {\n"
892 "      ptr = __libc_version;\n"
893 "      glibcmajor = 4;\n"
894 "    }\n"
895 "    else\n"
896 "      ptr = __linux_C_lib_version;\n"
897 "\n"
898 "    while (!isdigit (*ptr))\n"
899 "      ptr++;\n"
900 "\n"
901 "    sscanf (ptr, \"%d.%d.%d\", &libcmajor, &libcminor, &libcteeny);\n"
902 "    libcmajor += glibcmajor;\n"
903 "  }\n"
904 "\n"
905 "  printf(\"#define DefaultLinuxCLibMajorVersion %d\\n\", libcmajor);\n"
906 "  printf(\"#define DefaultLinuxCLibMinorVersion %d\\n\", libcminor);\n"
907 "  printf(\"#define DefaultLinuxCLibTeenyVersion %d\\n\", libcteeny);\n"
908 "\n"
909 "  return 0;\n"
910 "}\n"
911 ;
912
913 static void get_libc_version(inFile)
914   FILE* inFile;
915 {
916   char *aout = tmpnam (NULL);
917   FILE *fp;
918   const char *format = "%s -o %s -x c -";
919   char *cc;
920   int len;
921   char *command;
922
923   cc = getenv ("CC");
924   if (cc == NULL)
925     cc = "gcc";
926   len = strlen (aout) + strlen (format) + strlen (cc);
927   if (len < 128) len = 128;
928   command = alloca (len);
929
930   if (snprintf (command , len, format, cc, aout) == len)
931     abort ();
932
933   fp = popen (command, "w");
934   if (fp == NULL || fprintf (fp, "%s\n", libc_c) < 0
935       || pclose (fp) != 0)
936     abort ();
937
938   fp = popen (aout, "r");
939   if (fp == NULL)
940     abort ();
941
942   while (fgets (command, len, fp))
943     fprintf (inFile, command);
944   
945   len = pclose (fp);
946   remove (aout);
947   if (len)
948     abort ();
949 }
950
951 static void get_ld_version(inFile)
952   FILE* inFile;
953 {
954   FILE* ldprog = popen ("ld -v", "r");
955   char c;
956   int ldmajor, ldminor;
957
958   if (ldprog) {
959     do {
960       c = fgetc (ldprog);
961     } while (c != EOF && !isdigit (c));
962     ungetc (c, ldprog);
963     (void) fscanf (ldprog, "%d.%d", &ldmajor, &ldminor);
964     fprintf(inFile, "#define DefaultLinuxBinUtilsMajorVersion %d\n", 
965             ldmajor * 10 + ldminor);    
966     pclose (ldprog);
967   }
968 }
969 #endif
970
971 #ifndef PATH_MAX
972 #define PATH_MAX 1024
973 #endif
974
975 #ifndef __EMX__
976 static void get_gcc_incdir(inFile)
977   FILE* inFile;
978 {
979   static char* gcc_path[] = {
980 #if defined(linux) || defined(__OpenBSD__)
981     "/usr/bin/cc",      /* for Linux PostIncDir */
982 #endif
983     "/usr/local/bin/gcc",
984     "/opt/gnu/bin/gcc"
985   };
986   struct stat sb;
987   int i;
988   FILE* gccproc;
989   char buf[PATH_MAX];
990   char cmd[PATH_MAX];
991   char* ptr;
992
993   buf[0] = '\0';
994   for (i = 0; i < sizeof gcc_path / sizeof gcc_path[0]; i++) {
995     if (lstat (gcc_path[i], &sb) == 0) {
996       strcpy (cmd, gcc_path[i]);
997       strcat (cmd, " --print-libgcc-file-name");
998       if ((gccproc = popen (cmd, "r")) != NULL) {
999         if (fgets (buf, PATH_MAX, gccproc) != NULL) {
1000           ptr = strstr (buf, "libgcc.a");
1001           if (ptr) strcpy (ptr, "include");
1002         }
1003         (void) pclose (gccproc);
1004         break;
1005       }
1006     }
1007   }
1008   if (buf[0])
1009     fprintf (inFile, "#define DefaultGccIncludeDir %s\n", buf);
1010 }
1011 #endif
1012
1013 boolean
1014 define_os_defaults(inFile)
1015         FILE    *inFile;
1016 {
1017 #if !defined(WIN32) && !defined(__EMX__)
1018 #if (defined(DEFAULT_OS_NAME) || defined(DEFAULT_OS_MAJOR_REV) || \
1019      defined(DEFAULT_OS_MINOR_REV) || defined(DEFAUL_OS_TEENY_REV))
1020         struct utsname name;
1021         char buf[SYS_NMLN * 5 + 1];
1022
1023         /* Obtain the system information. */
1024         if (uname(&name) < 0)
1025                 LogFatal("Cannot invoke uname", "");
1026
1027 # ifdef DEFAULT_OS_NAME
1028         parse_utsname(&name, DEFAULT_OS_NAME, buf, 
1029                       "Bad DEFAULT_OS_NAME syntax %s");
1030 #  ifdef DEFAULT_OS_NAME_FROB
1031         DEFAULT_OS_NAME_FROB(buf, sizeof buf);
1032 #  endif
1033         if (buf[0] != '\0')
1034                 fprintf(inFile, "#define DefaultOSName %s\n", buf);
1035 # endif
1036
1037 # ifdef DEFAULT_OS_MAJOR_REV
1038         parse_utsname(&name, DEFAULT_OS_MAJOR_REV, buf,
1039                       "Bad DEFAULT_OS_MAJOR_REV syntax %s");
1040 #  ifdef DEFAULT_OS_MAJOR_REV_FROB
1041         DEFAULT_OS_MAJOR_REV_FROB(buf, sizeof buf);
1042 #  endif
1043         fprintf(inFile, "#define DefaultOSMajorVersion %s\n",
1044                 *buf ? trim_version(buf) : "0");
1045 # endif
1046
1047 # ifdef DEFAULT_OS_MINOR_REV
1048         parse_utsname(&name, DEFAULT_OS_MINOR_REV, buf,
1049                       "Bad DEFAULT_OS_MINOR_REV syntax %s");
1050 #  ifdef DEFAULT_OS_MINOR_REV_FROB
1051         DEFAULT_OS_MINOR_REV_FROB(buf, sizeof buf);
1052 #  endif
1053         fprintf(inFile, "#define DefaultOSMinorVersion %s\n",
1054                 *buf ? trim_version(buf) : "0");
1055 # endif
1056
1057 # ifdef DEFAULT_OS_TEENY_REV
1058         parse_utsname(&name, DEFAULT_OS_TEENY_REV, buf,
1059                       "Bad DEFAULT_OS_TEENY_REV syntax %s");
1060 #  ifdef DEFAULT_OS_TEENY_REV_FROB
1061         DEFAULT_OS_TEENY_REV_FROB(buf, sizeof buf);
1062 #  endif
1063         fprintf(inFile, "#define DefaultOSTeenyVersion %s\n",
1064                 *buf ? trim_version(buf) : "0");
1065 # endif
1066 # ifdef DEFAULT_MACHINE_ARCHITECTURE
1067         parse_utsname(&name, DEFAULT_MACHINE_ARCHITECTURE, buf, 
1068                       "Bad DEFAULT_MACHINE_ARCHITECTURE %s");
1069         fprintf(inFile, "#ifndef %s\n# define %s\n#endif\n", buf, buf);
1070 # endif
1071 #endif
1072 #ifdef linux
1073     get_libc_version (inFile);
1074     get_ld_version(inFile);
1075 #endif
1076     get_gcc_incdir(inFile);
1077 #endif /* WIN32 */
1078         return FALSE;
1079 }
1080
1081 void
1082 cppit(imakefile, template, masterc, outfd, outfname)
1083         char    *imakefile;
1084         char    *template;
1085         char    *masterc;
1086         FILE    *outfd;
1087         char    *outfname;
1088 {
1089         FILE    *inFile;
1090
1091         haveImakefileC = TRUE;
1092         inFile = fopen(masterc, "w");
1093         if (inFile == NULL)
1094                 LogFatal("Cannot open %s for output.", masterc);
1095         if (fprintf(inFile, "%s\n", ImakefileCHeader) < 0 ||
1096             define_os_defaults(inFile) ||
1097             optional_include(inFile, "IMAKE_LOCAL_DEFINES", "localdefines") ||
1098             optional_include(inFile, "IMAKE_ADMIN_DEFINES", "admindefines") ||
1099             fprintf(inFile, "#define %s <%s>\n", ImakeDefSym, imakefile) < 0 ||
1100             fprintf(inFile, LocalDefineFmt, ImakeTmplSym, template) < 0 ||
1101             fprintf(inFile, IncludeFmt, ImakeTmplSym) < 0 ||
1102             optional_include(inFile, "IMAKE_ADMIN_MACROS", "adminmacros") ||
1103             optional_include(inFile, "IMAKE_LOCAL_MACROS", "localmacros") ||
1104             fflush(inFile) || 
1105             fclose(inFile))
1106                 LogFatal("Cannot write to %s.", masterc);
1107         /*
1108          * Fork and exec cpp
1109          */
1110         doit(outfd, cpp, cpp_argv);
1111         CleanCppOutput(outfd, outfname);
1112 }
1113
1114 void
1115 makeit()
1116 {
1117         doit(NULL, make_argv[0], make_argv);
1118 }
1119
1120 char *
1121 CleanCppInput(imakefile)
1122         char    *imakefile;
1123 {
1124         FILE    *outFile = NULL;
1125         FILE    *inFile;
1126         char    *buf,           /* buffer for file content */
1127                 *pbuf,          /* walking pointer to buf */
1128                 *punwritten,    /* pointer to unwritten portion of buf */
1129                 *ptoken,        /* pointer to # token */
1130                 *pend,          /* pointer to end of # token */
1131                 savec;          /* temporary character holder */
1132         int     count;
1133         struct stat     st;
1134
1135         /*
1136          * grab the entire file.
1137          */
1138         if (!(inFile = fopen(imakefile, "r")))
1139                 LogFatal("Cannot open %s for input.", imakefile);
1140         if (fstat(fileno(inFile), &st) < 0)
1141                 LogFatal("Cannot stat %s for size.", imakefile);
1142         buf = Emalloc((int)st.st_size+3);
1143         count = fread(buf + 2, 1, st.st_size, inFile);
1144         if (count == 0  &&  st.st_size != 0)
1145                 LogFatal("Cannot read %s:", imakefile);
1146         fclose(inFile);
1147         buf[0] = '\n';
1148         buf[1] = '\n';
1149         buf[count + 2] = '\0';
1150
1151         punwritten = pbuf = buf + 2;
1152         while (*pbuf) {
1153             /* for compatibility, replace make comments for cpp */
1154             if (*pbuf == '#' && pbuf[-1] == '\n' && pbuf[-2] != '\\') {
1155                 ptoken = pbuf+1;
1156                 while (*ptoken == ' ' || *ptoken == '\t')
1157                         ptoken++;
1158                 pend = ptoken;
1159                 while (*pend && *pend != ' ' && *pend != '\t' && *pend != '\n')
1160                         pend++;
1161                 savec = *pend;
1162                 *pend = '\0';
1163                 if (strcmp(ptoken, "define") &&
1164                     strcmp(ptoken, "if") &&
1165                     strcmp(ptoken, "ifdef") &&
1166                     strcmp(ptoken, "ifndef") &&
1167                     strcmp(ptoken, "include") &&
1168                     strcmp(ptoken, "line") &&
1169                     strcmp(ptoken, "else") &&
1170                     strcmp(ptoken, "elif") &&
1171                     strcmp(ptoken, "endif") &&
1172                     strcmp(ptoken, "error") &&
1173                     strcmp(ptoken, "pragma") &&
1174                     strcmp(ptoken, "undef")) {
1175                     if (outFile == NULL) {
1176                         tmpImakefile = Strdup(tmpImakefile);
1177                         (void) mktemp(tmpImakefile);
1178                         outFile = fopen(tmpImakefile, "w");
1179                         if (outFile == NULL)
1180                             LogFatal("Cannot open %s for write.",
1181                                 tmpImakefile);
1182                     }
1183                     writetmpfile(outFile, punwritten, pbuf-punwritten,
1184                                  tmpImakefile);
1185                     if (ptoken > pbuf + 1)
1186                         writetmpfile(outFile, "XCOMM", 5, tmpImakefile);
1187                     else
1188                         writetmpfile(outFile, "XCOMM ", 6, tmpImakefile);
1189                     punwritten = pbuf + 1;
1190                 }
1191                 *pend = savec;
1192             }
1193             pbuf++;
1194         }
1195         if (outFile) {
1196             writetmpfile(outFile, punwritten, pbuf-punwritten, tmpImakefile);
1197             fclose(outFile);
1198             return tmpImakefile;
1199         }
1200
1201         return(imakefile);
1202 }
1203
1204 void
1205 CleanCppOutput(tmpfd, tmpfname)
1206         FILE    *tmpfd;
1207         char    *tmpfname;
1208 {
1209         char    *input;
1210         int     blankline = 0;
1211
1212         while(input = ReadLine(tmpfd, tmpfname)) {
1213                 if (isempty(input)) {
1214                         if (blankline++)
1215                                 continue;
1216                         KludgeResetRule();
1217                 } else {
1218                         blankline = 0;
1219                         KludgeOutputLine(&input);
1220                         writetmpfile(tmpfd, input, strlen(input), tmpfname);
1221                 }
1222                 writetmpfile(tmpfd, "\n", 1, tmpfname);
1223         }
1224         fflush(tmpfd);
1225 #ifdef NFS_STDOUT_BUG
1226         /*
1227          * On some systems, NFS seems to leave a large number of nulls at
1228          * the end of the file.  Ralph Swick says that this kludge makes the
1229          * problem go away.
1230          */
1231         ftruncate (fileno(tmpfd), (off_t)ftell(tmpfd));
1232 #endif
1233 }
1234
1235 /*
1236  * Determine if a line has nothing in it.  As a side effect, we trim white
1237  * space from the end of the line.  Cpp magic cookies are also thrown away.
1238  * "XCOMM" token is transformed to "#".
1239  */
1240 boolean
1241 isempty(line)
1242         register char   *line;
1243 {
1244         register char   *pend;
1245
1246         /*
1247          * Check for lines of the form
1248          *      # n "...
1249          * or
1250          *      # line n "...
1251          */
1252         if (*line == '#') {
1253                 pend = line+1;
1254                 if (*pend == ' ')
1255                         pend++;
1256                 if (*pend == 'l' && pend[1] == 'i' && pend[2] == 'n' &&
1257                     pend[3] == 'e' && pend[4] == ' ')
1258                         pend += 5;
1259                 if (isdigit(*pend)) {
1260                         do {
1261                             pend++;
1262                         } while (isdigit(*pend));
1263                         if (*pend == '\n' || *pend == '\0')
1264                                 return(TRUE);
1265                         if (*pend++ == ' ' && *pend == '"')
1266                                 return(TRUE);
1267                 }
1268                 while (*pend)
1269                     pend++;
1270         } else {
1271             for (pend = line; *pend; pend++) {
1272                 if (*pend == 'X' && pend[1] == 'C' && pend[2] == 'O' &&
1273                     pend[3] == 'M' && pend[4] == 'M' &&
1274                     (pend == line || pend[-1] == ' ' || pend[-1] == '\t') &&
1275                     (pend[5] == ' ' || pend[5] == '\t' || pend[5] == '\0'))
1276                 {
1277                     *pend = '#';
1278                     strcpy(pend+1, pend+5);
1279                 }
1280 #ifdef MAGIC_MAKE_VARS
1281                 if (*pend == 'X' && pend[1] == 'V' && pend[2] == 'A' &&
1282                     pend[3] == 'R')
1283                 {
1284                     char varbuf[5];
1285                     int i;
1286
1287                     if (pend[4] == 'd' && pend[5] == 'e' && pend[6] == 'f' &&
1288                         pend[7] >= '0' && pend[7] <= '9')
1289                     {
1290                         i = pend[7] - '0';
1291                         sprintf(varbuf, "%0.4d", xvariable);
1292                         strncpy(pend+4, varbuf, 4);
1293                         xvariables[i] = xvariable;
1294                         xvariable = (xvariable + 1) % 10000;
1295                     }
1296                     else if (pend[4] == 'u' && pend[5] == 's' &&
1297                              pend[6] == 'e' && pend[7] >= '0' &&
1298                              pend[7] <= '9')
1299                     {
1300                         i = pend[7] - '0';
1301                         sprintf(varbuf, "%0.4d", xvariables[i]);
1302                         strncpy(pend+4, varbuf, 4);
1303                     }
1304                 }
1305 #endif
1306             }
1307         }
1308         while (--pend >= line && (*pend == ' ' || *pend == '\t')) ;
1309         pend[1] = '\0';
1310         return (*line == '\0');
1311 }
1312
1313 /*ARGSUSED*/
1314 char *
1315 ReadLine(tmpfd, tmpfname)
1316         FILE    *tmpfd;
1317         char    *tmpfname;
1318 {
1319         static boolean  initialized = FALSE;
1320         static char     *buf, *pline, *end;
1321         register char   *p1, *p2;
1322
1323         if (! initialized) {
1324 #ifdef WIN32
1325                 FILE *fp = tmpfd;
1326 #endif
1327                 int     total_red;
1328                 struct stat     st;
1329
1330                 /*
1331                  * Slurp it all up.
1332                  */
1333                 fseek(tmpfd, 0, 0);
1334                 if (fstat(fileno(tmpfd), &st) < 0)
1335                         LogFatal("cannot stat %s for size", tmpMakefile);
1336                 pline = buf = Emalloc((int)st.st_size+1);
1337                 total_red = fread(buf, 1, st.st_size, tmpfd);
1338                 if (total_red == 0  &&  st.st_size != 0)
1339                         LogFatal("cannot read %s", tmpMakefile);
1340                 end = buf + total_red;
1341                 *end = '\0';
1342                 fseek(tmpfd, 0, 0);
1343 #if defined(SYSV) || defined(WIN32) || defined(USE_FREOPEN)
1344                 tmpfd = freopen(tmpfname, "w+", tmpfd);
1345 #ifdef WIN32
1346                 if (! tmpfd) /* if failed try again */
1347                         tmpfd = freopen(tmpfname, "w+", fp);
1348 #endif
1349                 if (! tmpfd)
1350                         LogFatal("cannot reopen %s\n", tmpfname);
1351 #else   /* !SYSV */
1352                 ftruncate(fileno(tmpfd), (off_t) 0);
1353 #endif  /* !SYSV */
1354                 initialized = TRUE;
1355             fprintf (tmpfd, "# Makefile generated by imake - do not edit!\n");
1356             fprintf (tmpfd, "# %s\n",
1357                 "$TOG: imake.c /main/97 1997/06/20 20:23:51 kaleb $");
1358         }
1359
1360         for (p1 = pline; p1 < end; p1++) {
1361                 if (*p1 == '@' && *(p1+1) == '@'
1362                     /* ignore ClearCase version-extended pathnames */
1363                     && !(p1 != pline && !isspace(*(p1-1)) && *(p1+2) == '/'))
1364                 { /* soft EOL */
1365                         *p1++ = '\0';
1366                         p1++; /* skip over second @ */
1367                         break;
1368                 }
1369                 else if (*p1 == '\n') { /* real EOL */
1370 #ifdef WIN32
1371                         if (p1 > pline && p1[-1] == '\r')
1372                                 p1[-1] = '\0';
1373 #endif
1374                         *p1++ = '\0';
1375                         break;
1376                 }
1377         }
1378
1379         /*
1380          * return NULL at the end of the file.
1381          */
1382         p2 = (pline == p1 ? NULL : pline);
1383         pline = p1;
1384         return(p2);
1385 }
1386
1387 void
1388 writetmpfile(fd, buf, cnt, fname)
1389         FILE    *fd;
1390         int     cnt;
1391         char    *buf;
1392         char    *fname;
1393 {
1394         if (fwrite(buf, sizeof(char), cnt, fd) == -1)
1395                 LogFatal("Cannot write to %s.", fname);
1396 }
1397
1398 char *
1399 Emalloc(size)
1400         int     size;
1401 {
1402         char    *p;
1403
1404         if ((p = malloc(size)) == NULL)
1405                 LogFatalI("Cannot allocate %d bytes", size);
1406         return(p);
1407 }
1408
1409 #ifdef FIXUP_CPP_WHITESPACE
1410 void
1411 KludgeOutputLine(pline)
1412         char    **pline;
1413 {
1414         char    *p = *pline;
1415         char    quotechar = '\0';
1416
1417         switch (*p) {
1418             case '#':   /*Comment - ignore*/
1419                 break;
1420             case '\t':  /*Already tabbed - ignore it*/
1421                 break;
1422             case ' ':   /*May need a tab*/
1423             default:
1424 # ifdef INLINE_SYNTAX
1425                 if (*p == '<' && p[1] == '<') { /* inline file close */
1426                     InInline--;
1427                     InRule = TRUE;
1428                     break;
1429                 }
1430 # endif
1431                 /*
1432                  * The following cases should not be treated as beginning of 
1433                  * rules:
1434                  * variable := name     (GNU make)
1435                  * variable = .*:.*     (':' should be allowed as value)
1436                  *      sed 's:/a:/b:'  (: used in quoted values)
1437                  */
1438                 for (; *p; p++) {
1439                     if (quotechar) {
1440                         if (quotechar == '\\' ||
1441                             (*p == quotechar &&
1442 # ifdef WIN32
1443                              quotechar != ')' &&
1444 # endif
1445                              p[-1] != '\\'))
1446                             quotechar = '\0';
1447                         continue;
1448                     }
1449                     switch (*p) {
1450                     case '\\':
1451                     case '"':
1452                     case '\'':
1453                         quotechar = *p;
1454                         break;
1455                     case '(':
1456                         quotechar = ')';
1457                         break;
1458                     case '{':
1459                         quotechar = '}';
1460                         break;
1461                     case '[':
1462                         quotechar = ']';
1463                         break;
1464                     case '=':
1465 # ifdef REMOVE_CPP_LEADSPACE
1466                         if (!InRule && **pline == ' ') {
1467                             while (**pline == ' ')
1468                                 (*pline)++;
1469                         }
1470 # endif
1471                         goto breakfor;
1472 # ifdef INLINE_SYNTAX
1473                     case '<':
1474                         if (p[1] == '<') /* inline file start */
1475                             InInline++;
1476                         break;
1477 # endif
1478                     case ':':
1479                         if (p[1] == '=')
1480                             goto breakfor;
1481                         while (**pline == ' ')
1482                             (*pline)++;
1483                         InRule = TRUE;
1484                         return;
1485                     }
1486                 }
1487 breakfor:
1488                 if (InRule && **pline == ' ')
1489                     **pline = '\t';
1490                 break;
1491         }
1492 }
1493
1494 void
1495 KludgeResetRule()
1496 {
1497         InRule = FALSE;
1498 }
1499 #endif /* FIXUP_CPP_WHITESPACE */
1500
1501 char *
1502 Strdup(cp)
1503         register char *cp;
1504 {
1505         register char *new = Emalloc(strlen(cp) + 1);
1506
1507         strcpy(new, cp);
1508         return new;
1509 }