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