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 *
12Copyright (c) 1985, 1986, 1987, 1998 The Open Group
13
14Permission to use, copy, modify, distribute, and sell this software and its
15documentation for any purpose is hereby granted without fee, provided that
16the above copyright notice appear in all copies and that both that
17copyright notice and this permission notice appear in supporting
18documentation.
19
20The above copyright notice and this permission notice shall be included in
21all copies or substantial portions of the Software.
22
23THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
26OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
27AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
28CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
30Except as contained in this notice, the name of The Open Group shall not be
31used in advertising or otherwise to promote the sale, use or other dealings
32in 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)
202typedef int		waitType;
203#else /* X_NOT_POSIX */
204# ifdef SYSV
205#  define waitCode(w)	(((w) >> 8) & 0x7f)
206#  define waitSig(w)	((w) & 0xff)
207typedef int		waitType;
208# else /* SYSV */
209#  ifdef WIN32
210#   include <process.h>
211typedef 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)
216typedef 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
256typedef 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
266int InRule = FALSE;
267#endif
268#if defined CROSSCOMPILE || defined INLINE_SYNTAX
269int InInline = 0;
270#endif
271#if defined CROSSCOMPILE || defined MAGIC_MAKE_VARS
272int xvariable = 0;
273int 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 */
285void 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
303const char *cpp = NULL;
304
305const char	*tmpMakefile;
306const char	*tmpMakefileTemplate = "/tmp/Imf.XXXXXX";
307const char	*tmpImakefile;
308const char	*tmpImakefileTemplate = "/tmp/IIf.XXXXXX";
309const char	*make_argv[ ARGUMENTS ] = {
310#ifdef WIN32
311    "nmake"
312#else
313    "make"
314#endif
315};
316
317int	make_argindex;
318int	cpp_argindex;
319const char	*Imakefile = NULL;
320const char	*Makefile = "Makefile";
321const char	*Template = "Imake.tmpl";
322const char	*ImakefileC = "Imakefile.c";
323boolean haveImakefileC = FALSE;
324const char	*cleanedImakefile = NULL;
325const char	*program;
326const char	*FindImakefile(const char *Imakefile);
327char	*ReadLine(FILE *tmpfd, const char *tmpfname);
328const char	*CleanCppInput(const char *imakefile);
329char	*Strdup(const char *cp);
330char	*Emalloc(size_t size);
331void	LogFatal(const char *x0, ...) _X_ATTRIBUTE_PRINTF(1, 2);
332void	LogMsg(const char *x0, ...) _X_ATTRIBUTE_PRINTF(1, 2);
333
334void	showit(FILE *fd);
335void	wrapup(void);
336void	init(void);
337void	AddMakeArg(const char *arg);
338void	AddCppArg(const char *arg);
339#ifdef CROSSCOMPILE
340char	*CrossCompileCPP(void);
341#endif
342void	SetOpts(int argc, char **argv);
343void	CheckImakefileC(const char *masterc);
344void	cppit(const char *imakefile, const char *template, const char *masterc,
345	      FILE *outfd, const char *outfname);
346void	makeit(void);
347void	CleanCppOutput(FILE *tmpfd, const char *tmpfname);
348boolean isempty(char *line);
349void	writetmpfile(FILE *fd, const char *buf, size_t cnt, const char *fname);
350void	catch(int sig);
351void	showargs(const char **argv);
352boolean optional_include(FILE *inFile, const char *defsym, const char *fname);
353void	  doit(FILE *outfd, const char *cmd, const char **argv);
354boolean define_os_defaults(FILE *inFile);
355#ifdef CROSSCOMPILE
356static void get_cross_compile_dir(FILE *inFile);
357#endif
358#ifdef CROSSCOMPILEDIR
359const char *CrossCompileDir = CROSSCOMPILEDIR;
360#else
361const char *CrossCompileDir = "";
362#endif
363boolean CrossCompiling = FALSE;
364
365
366
367boolean verbose = FALSE;
368boolean show = TRUE;
369
370int
371main(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
436void
437showit(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
449void
450wrapup(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
460void
461catch(int sig)
462{
463	errno = 0;
464	LogFatal("Signal %d.", sig);
465}
466
467/*
468 * Initialize some variables.
469 */
470void
471init(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
537void
538AddMakeArg(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
547void
548AddCppArg(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
557void
558SetOpts(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
652const char *
653FindImakefile(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
670static void _X_ATTRIBUTE_PRINTF(1, 0)
671vLogMsg(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
684void
685LogFatal(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
702void
703LogMsg(const char *fmt, ...)
704{
705	va_list args;
706
707	va_start(args, fmt);
708	vLogMsg(fmt, args);
709	va_end(args);
710}
711
712void
713showargs(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
722void
723CheckImakefileC(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
750boolean
751optional_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
762void
763doit(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
804static void
805parse_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
877static char *
878trim_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__)
891const 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
948static void
949get_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__)
1009static void
1010get_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__)
1036static void
1037get_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
1091static void
1092get_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__
1130static void
1131get_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 */
1174static int
1175ask_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 */
1225static void
1226get_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__
1296static void
1297get_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
1328static boolean
1329get_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
1382static void
1383get_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
1407boolean
1408define_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
1680void
1681cppit(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
1712void
1713makeit(void)
1714{
1715	doit(NULL, make_argv[0], make_argv);
1716}
1717
1718const char *
1719CleanCppInput(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
1819void
1820CleanCppOutput(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 */
1863boolean
1864isempty(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*/
1941char *
1942ReadLine(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
2015void
2016writetmpfile(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
2022char *
2023Emalloc(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
2033void
2034KludgeOutputLine(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		}
2125breakfor:
2126		if (InRule && **pline == ' ')
2127		    **pline = '\t';
2128		break;
2129	}
2130}
2131
2132void
2133KludgeResetRule(void)
2134{
2135	InRule = FALSE;
2136}
2137#endif
2138char *
2139Strdup(const char *cp)
2140{
2141	char *new = Emalloc(strlen(cp) + 1);
2142
2143	strcpy(new, cp);
2144	return new;
2145}
2146
2147#ifdef CROSSCOMPILE
2148char*
2149CrossCompileCPP(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
2173static void
2174get_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