xref: /csrg-svn/local/X11R5/mit/config/imake.c (revision 60923)
160552Selan /* $XConsortium: imake.c,v 1.65 91/07/25 17:50:17 rws Exp $ */
260552Selan 
360552Selan /*****************************************************************************\
460552Selan  *                                                                           *
560552Selan  *                                Porting Note                               *
660552Selan  *                                                                           *
760552Selan  * Add the value of BOOTSTRAPCFLAGS to the cpp_argv table so that it will be *
860552Selan  * passed to the template file.                                              *
960552Selan  *                                                                           *
1060552Selan \*****************************************************************************/
1160552Selan 
1260552Selan /*
1360552Selan  *
1460552Selan  * Copyright 1985, 1986, 1987 by the Massachusetts Institute of Technology
1560552Selan  *
1660552Selan  * Permission to use, copy, modify, and distribute this
1760552Selan  * software and its documentation for any purpose and without
1860552Selan  * fee is hereby granted, provided that the above copyright
1960552Selan  * notice appear in all copies and that both that copyright
2060552Selan  * notice and this permission notice appear in supporting
2160552Selan  * documentation, and that the name of M.I.T. not be used in
2260552Selan  * advertising or publicity pertaining to distribution of the
2360552Selan  * software without specific, written prior permission.
2460552Selan  * M.I.T. makes no representations about the suitability of
2560552Selan  * this software for any purpose.  It is provided "as is"
2660552Selan  * without express or implied warranty.
2760552Selan  *
2860552Selan  * Original Author:
2960552Selan  *	Todd Brunhoff
3060552Selan  *	Tektronix, inc.
3160552Selan  *	While a guest engineer at Project Athena, MIT
3260552Selan  *
3360552Selan  * imake: the include-make program.
3460552Selan  *
3560552Selan  * Usage: imake [-Idir] [-Ddefine] [-T] [-f imakefile ] [-s] [-e] [-v] [make flags]
3660552Selan  *
3760552Selan  * Imake takes a template makefile (Imake.tmpl) and runs cpp on it
3860552Selan  * producing a temporary makefile in /tmp.  It then runs make on
3960552Selan  * this pre-processed makefile.
4060552Selan  * Options:
4160552Selan  *		-D	define.  Same as cpp -D argument.
4260552Selan  *		-I	Include directory.  Same as cpp -I argument.
4360552Selan  *		-T	template.  Designate a template other
4460552Selan  * 			than Imake.tmpl
4560552Selan  *		-s[F]	show.  Show the produced makefile on the standard
4660552Selan  *			output.  Make is not run is this case.  If a file
4760552Selan  *			argument is provided, the output is placed there.
4860552Selan  *              -e[F]   execute instead of show; optionally name Makefile F
4960552Selan  *		-v	verbose.  Show the make command line executed.
5060552Selan  *
5160552Selan  * Environment variables:
5260552Selan  *
5360552Selan  *		IMAKEINCLUDE	Include directory to use in addition to "."
5460552Selan  *		IMAKECPP	Cpp to use instead of /lib/cpp
5560552Selan  *		IMAKEMAKE	make program to use other than what is
5660552Selan  *				found by searching the $PATH variable.
5760552Selan  * Other features:
5860552Selan  *	imake reads the entire cpp output into memory and then scans it
5960552Selan  *	for occurences of "@@".  If it encounters them, it replaces it with
6060552Selan  *	a newline.  It also trims any trailing white space on output lines
6160552Selan  *	(because make gets upset at them).  This helps when cpp expands
6260552Selan  *	multi-line macros but you want them to appear on multiple lines.
6360552Selan  *
6460552Selan  *	The macros MAKEFILE and MAKE are provided as macros
6560552Selan  *	to make.  MAKEFILE is set to imake's makefile (not the constructed,
6660552Selan  *	preprocessed one) and MAKE is set to argv[0], i.e. the name of
6760552Selan  *	the imake program.
6860552Selan  *
6960552Selan  * Theory of operation:
7060552Selan  *   1. Determine the name of the imakefile from the command line (-f)
7160552Selan  *	or from the content of the current directory (Imakefile or imakefile).
7260552Selan  *	Call this <imakefile>.  This gets added to the arguments for
7360552Selan  *	make as MAKEFILE=<imakefile>.
7460552Selan  *   2. Determine the name of the template from the command line (-T)
7560552Selan  *	or the default, Imake.tmpl.  Call this <template>
7660552Selan  *   3. Start up cpp an provide it with three lines of input:
7760552Selan  *		#define IMAKE_TEMPLATE		" <template> "
7860552Selan  *		#define INCLUDE_IMAKEFILE	< <imakefile> >
7960552Selan  *		#include IMAKE_TEMPLATE
8060552Selan  *	Note that the define for INCLUDE_IMAKEFILE is intended for
8160552Selan  *	use in the template file.  This implies that the imake is
8260552Selan  *	useless unless the template file contains at least the line
8360552Selan  *		#include INCLUDE_IMAKEFILE
8460552Selan  *   4. Gather the output from cpp, and clean it up, expanding @@ to
8560552Selan  *	newlines, stripping trailing white space, cpp control lines,
8660552Selan  *	and extra blank lines.  This cleaned output is placed in a
8760552Selan  *	temporary file.  Call this <makefile>.
8860552Selan  *   5. Start up make specifying <makefile> as its input.
8960552Selan  *
9060552Selan  * The design of the template makefile should therefore be:
9160552Selan  *	<set global macros like CFLAGS, etc.>
9260552Selan  *	<include machine dependent additions>
9360552Selan  *	#include INCLUDE_IMAKEFILE
9460552Selan  *	<add any global targets like 'clean' and long dependencies>
9560552Selan  */
9660552Selan #include <stdio.h>
9760552Selan #if (defined(SVR4) || defined(_IBMR2) || defined(SYSV386)) && __STDC__
9860552Selan FILE * fdopen();
9960552Selan #endif
10060552Selan #include <ctype.h>
10160552Selan #include "Xosdefs.h"
10260552Selan #ifndef X_NOT_POSIX
10360552Selan #define _POSIX_SOURCE
10460552Selan #endif
10560552Selan #include <sys/types.h>
10660552Selan #include <fcntl.h>
10760552Selan #ifdef X_NOT_POSIX
10860552Selan #include <sys/file.h>
10960552Selan #else
11060552Selan #ifdef hp9000
11160552Selan #undef _POSIX_SOURCE
11260552Selan #endif
11360552Selan #include <unistd.h>
11460552Selan #ifdef hp9000
11560552Selan #define _POSIX_SOURCE
11660552Selan #endif
11760552Selan #endif
11860552Selan #if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE)
11960552Selan #include <signal.h>
12060552Selan #else
12160552Selan #define _POSIX_SOURCE
12260552Selan #include <signal.h>
12360552Selan #undef _POSIX_SOURCE
12460552Selan #endif
12560552Selan #include <sys/stat.h>
12660552Selan #ifndef X_NOT_POSIX
12760552Selan #ifdef _POSIX_SOURCE
12860552Selan #include <sys/wait.h>
12960552Selan #else
13060552Selan #define _POSIX_SOURCE
13160552Selan #include <sys/wait.h>
13260552Selan #undef _POSIX_SOURCE
13360552Selan #endif
13460552Selan #define waitCode(w)	WEXITSTATUS(w)
13560552Selan #define waitSig(w)	WTERMSIG(w)
13660552Selan typedef int		waitType;
13760552Selan #else /* X_NOT_POSIX */
13860552Selan #ifdef SYSV
13960552Selan #define waitCode(w)	(((w) >> 8) & 0x7f)
14060552Selan #define waitSig(w)	((w) & 0xff)
14160552Selan typedef int		waitType;
14260552Selan #else /* SYSV */
14360552Selan #include <sys/wait.h>
14460552Selan #define waitCode(w)	((w).w_T.w_Retcode)
14560552Selan #define waitSig(w)	((w).w_T.w_Termsig)
14660552Selan typedef union wait	waitType;
14760552Selan #endif
14860552Selan #ifndef WIFSIGNALED
14960552Selan #define WIFSIGNALED(w) waitSig(w)
15060552Selan #endif
15160552Selan #ifndef WIFEXITED
15260552Selan #define WIFEXITED(w) waitCode(w)
15360552Selan #endif
15460552Selan #endif /* X_NOT_POSIX */
15560552Selan #ifndef X_NOT_STDC_ENV
15660552Selan #include <stdlib.h>
15760552Selan #else
15860552Selan char *malloc(), *realloc();
15960552Selan void exit();
16060552Selan #endif
16160552Selan #if defined(macII) && !defined(__STDC__)  /* stdlib.h fails to define these */
16260552Selan char *malloc(), *realloc();
16360552Selan #endif /* macII */
16460552Selan #ifdef X_NOT_STDC_ENV
16560552Selan extern char	*getenv();
16660552Selan #endif
16760552Selan #include <errno.h>
16860552Selan extern int	errno;
16960552Selan #include "imakemdep.h"
17060552Selan 
17160552Selan 
17260552Selan #define	TRUE		1
17360552Selan #define	FALSE		0
17460552Selan 
17560552Selan #ifdef FIXUP_CPP_WHITESPACE
17660552Selan int	InRule = FALSE;
17760552Selan #endif
17860552Selan 
17960552Selan /*
18060552Selan  * Some versions of cpp reduce all tabs in macro expansion to a single
18160552Selan  * space.  In addition, the escaped newline may be replaced with a
18260552Selan  * space instead of being deleted.  Blech.
18360552Selan  */
18460552Selan #ifndef FIXUP_CPP_WHITESPACE
18560552Selan #define KludgeOutputLine(arg)
18660552Selan #define KludgeResetRule()
18760552Selan #endif
18860552Selan 
18960552Selan typedef	unsigned char	boolean;
19060552Selan 
19160552Selan #ifndef DEFAULT_CPP
19260552Selan #ifdef USE_CC_E
19360552Selan #define DEFAULT_CPP "/bin/cc"
19460552Selan #else
19560552Selan #ifdef CPP_PROGRAM
19660552Selan #define DEFAULT_CPP CPP_PROGRAM
19760552Selan #else
19860552Selan #define DEFAULT_CPP "/lib/cpp"
19960552Selan #endif
20060552Selan #endif
20160552Selan #endif
20260552Selan 
20360552Selan char *cpp = DEFAULT_CPP;
20460552Selan 
20560552Selan char	*tmpMakefile    = "/tmp/Imf.XXXXXX";
20660552Selan char	*tmpImakefile    = "/tmp/IIf.XXXXXX";
20760552Selan char	*make_argv[ ARGUMENTS ] = { "make" };
20860552Selan 
20960552Selan int	make_argindex;
21060552Selan int	cpp_argindex;
21160552Selan char	*make = NULL;
21260552Selan char	*Imakefile = NULL;
21360552Selan char	*Makefile = "Makefile";
21460552Selan char	*Template = "Imake.tmpl";
21560552Selan char	*program;
21660552Selan char	*FindImakefile();
21760552Selan char	*ReadLine();
21860552Selan char	*CleanCppInput();
21960552Selan char	*Strdup();
22060552Selan #if defined(__STDC__) || defined(__GNUC__)
22160552Selan char	*Emalloc(int);
22260552Selan #else
22360552Selan char	*Emalloc();
22460552Selan #endif
22560552Selan 
22660552Selan boolean	verbose = FALSE;
22760552Selan boolean	show = TRUE;
22860552Selan 
main(argc,argv)22960552Selan main(argc, argv)
23060552Selan 	int	argc;
23160552Selan 	char	**argv;
23260552Selan {
23360552Selan 	FILE	*tmpfd;
23460552Selan 	char	makeMacro[ BUFSIZ ];
23560552Selan 	char	makefileMacro[ BUFSIZ ];
23660552Selan 
23760552Selan 	program = argv[0];
23860552Selan 	init();
23960552Selan 	SetOpts(argc, argv);
24060552Selan #ifdef USE_CC_E
24160552Selan 	AddCppArg("-");
24260552Selan #endif
24360552Selan 
24460552Selan 	Imakefile = FindImakefile(Imakefile);
24560552Selan 	if (Makefile)
24660552Selan 		tmpMakefile = Makefile;
24760552Selan 	else {
24860552Selan 		tmpMakefile = Strdup(tmpMakefile);
24960552Selan 		(void) mktemp(tmpMakefile);
25060552Selan 	}
25160552Selan 	AddMakeArg("-f");
25260552Selan 	AddMakeArg( tmpMakefile );
25360552Selan 	sprintf(makeMacro, "MAKE=%s", program);
25460552Selan 	AddMakeArg( makeMacro );
25560552Selan 	sprintf(makefileMacro, "MAKEFILE=%s", Imakefile);
25660552Selan 	AddMakeArg( makefileMacro );
25760552Selan 
25860552Selan 	if ((tmpfd = fopen(tmpMakefile, "w+")) == NULL)
25960552Selan 		LogFatal("Cannot create temporary file %s.", tmpMakefile);
26060552Selan 
26160552Selan 	cppit(Imakefile, Template, tmpfd, tmpMakefile);
26260552Selan 
26360552Selan 	if (show) {
26460552Selan 		if (Makefile == NULL)
26560552Selan 			showit(tmpfd);
26660552Selan 	} else
26760552Selan 		makeit();
26860552Selan 	wrapup();
26960552Selan 	exit(0);
27060552Selan }
27160552Selan 
showit(fd)27260552Selan showit(fd)
27360552Selan 	FILE	*fd;
27460552Selan {
27560552Selan 	char	buf[ BUFSIZ ];
27660552Selan 	int	red;
27760552Selan 
27860552Selan 	fseek(fd, 0, 0);
27960552Selan 	while ((red = fread(buf, 1, BUFSIZ, fd)) > 0)
28060552Selan 		fwrite(buf, red, 1, stdout);
28160552Selan 	if (red < 0)
28260552Selan 		LogFatal("Cannot write stdout.", "");
28360552Selan }
28460552Selan 
wrapup()28560552Selan wrapup()
28660552Selan {
28760552Selan 	if (tmpMakefile != Makefile)
28860552Selan 		unlink(tmpMakefile);
28960552Selan 	unlink(tmpImakefile);
29060552Selan }
29160552Selan 
29260552Selan #ifdef SIGNALRETURNSINT
29360552Selan int
29460552Selan #else
29560552Selan void
29660552Selan #endif
catch(sig)29760552Selan catch(sig)
29860552Selan 	int	sig;
29960552Selan {
30060552Selan 	errno = 0;
30160552Selan 	LogFatalI("Signal %d.", sig);
30260552Selan }
30360552Selan 
30460552Selan /*
30560552Selan  * Initialize some variables.
30660552Selan  */
init()30760552Selan init()
30860552Selan {
30960552Selan 	char	*p;
31060552Selan 
31160552Selan 	make_argindex=0;
31260552Selan 	while (make_argv[ make_argindex ] != NULL)
31360552Selan 		make_argindex++;
31460552Selan 	cpp_argindex = 0;
31560552Selan 	while (cpp_argv[ cpp_argindex ] != NULL)
31660552Selan 		cpp_argindex++;
31760552Selan 
31860552Selan 	/*
31960552Selan 	 * See if the standard include directory is different than
32060552Selan 	 * the default.  Or if cpp is not the default.  Or if the make
32160552Selan 	 * found by the PATH variable is not the default.
32260552Selan 	 */
32360552Selan 	if (p = getenv("IMAKEINCLUDE")) {
32460552Selan 		if (*p != '-' || *(p+1) != 'I')
32560552Selan 			LogFatal("Environment var IMAKEINCLUDE %s\n",
32660552Selan 				"must begin with -I");
32760552Selan 		AddCppArg(p);
32860552Selan 		for (; *p; p++)
32960552Selan 			if (*p == ' ') {
33060552Selan 				*p++ = '\0';
33160552Selan 				AddCppArg(p);
33260552Selan 			}
33360552Selan 	}
33460552Selan 	if (p = getenv("IMAKECPP"))
33560552Selan 		cpp = p;
33660552Selan 	if (p = getenv("IMAKEMAKE"))
33760552Selan 		make = p;
33860552Selan 
33960552Selan 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
34060552Selan 		signal(SIGINT, catch);
34160552Selan }
34260552Selan 
AddMakeArg(arg)34360552Selan AddMakeArg(arg)
34460552Selan 	char	*arg;
34560552Selan {
34660552Selan 	errno = 0;
34760552Selan 	if (make_argindex >= ARGUMENTS-1)
34860552Selan 		LogFatal("Out of internal storage.", "");
34960552Selan 	make_argv[ make_argindex++ ] = arg;
35060552Selan 	make_argv[ make_argindex ] = NULL;
35160552Selan }
35260552Selan 
AddCppArg(arg)35360552Selan AddCppArg(arg)
35460552Selan 	char	*arg;
35560552Selan {
35660552Selan 	errno = 0;
35760552Selan 	if (cpp_argindex >= ARGUMENTS-1)
35860552Selan 		LogFatal("Out of internal storage.", "");
35960552Selan 	cpp_argv[ cpp_argindex++ ] = arg;
36060552Selan 	cpp_argv[ cpp_argindex ] = NULL;
36160552Selan }
36260552Selan 
SetOpts(argc,argv)36360552Selan SetOpts(argc, argv)
36460552Selan 	int	argc;
36560552Selan 	char	**argv;
36660552Selan {
36760552Selan 	errno = 0;
36860552Selan 	/*
36960552Selan 	 * Now gather the arguments for make
37060552Selan 	 */
37160552Selan 	for(argc--, argv++; argc; argc--, argv++) {
37260552Selan 	    /*
37360552Selan 	     * We intercept these flags.
37460552Selan 	     */
37560552Selan 	    if (argv[0][0] == '-') {
37660552Selan 		if (argv[0][1] == 'D') {
37760552Selan 		    AddCppArg(argv[0]);
37860552Selan 		} else if (argv[0][1] == 'I') {
37960552Selan 		    AddCppArg(argv[0]);
38060552Selan 		} else if (argv[0][1] == 'f') {
38160552Selan 		    if (argv[0][2])
38260552Selan 			Imakefile = argv[0]+2;
38360552Selan 		    else {
38460552Selan 			argc--, argv++;
38560552Selan 			if (! argc)
38660552Selan 			    LogFatal("No description arg after -f flag\n", "");
38760552Selan 			Imakefile = argv[0];
38860552Selan 		    }
38960552Selan 		} else if (argv[0][1] == 's') {
39060552Selan 		    if (argv[0][2])
39160552Selan 			Makefile = ((argv[0][2] == '-') && !argv[0][3]) ?
39260552Selan 			    NULL : argv[0]+2;
39360552Selan 		    else {
39460552Selan 			argc--, argv++;
39560552Selan 			if (!argc)
39660552Selan 			    LogFatal("No description arg after -s flag\n", "");
39760552Selan 			Makefile = ((argv[0][0] == '-') && !argv[0][1]) ?
39860552Selan 			    NULL : argv[0];
39960552Selan 		    }
40060552Selan 		    show = TRUE;
40160552Selan 		} else if (argv[0][1] == 'e') {
40260552Selan 		   Makefile = (argv[0][2] ? argv[0]+2 : NULL);
40360552Selan 		   show = FALSE;
40460552Selan 		} else if (argv[0][1] == 'T') {
40560552Selan 		    if (argv[0][2])
40660552Selan 			Template = argv[0]+2;
40760552Selan 		    else {
40860552Selan 			argc--, argv++;
40960552Selan 			if (! argc)
41060552Selan 			    LogFatal("No description arg after -T flag\n", "");
41160552Selan 			Template = argv[0];
41260552Selan 		    }
41360552Selan 		} else if (argv[0][1] == 'v') {
41460552Selan 		    verbose = TRUE;
41560552Selan 		} else
41660552Selan 		    AddMakeArg(argv[0]);
41760552Selan 	    } else
41860552Selan 		AddMakeArg(argv[0]);
41960552Selan 	}
42060552Selan }
42160552Selan 
FindImakefile(Imakefile)42260552Selan char *FindImakefile(Imakefile)
42360552Selan 	char	*Imakefile;
42460552Selan {
42560552Selan 	int	fd;
42660552Selan 
42760552Selan 	if (Imakefile) {
42860552Selan 		if ((fd = open(Imakefile, O_RDONLY)) < 0)
42960552Selan 			LogFatal("Cannot open %s.", Imakefile);
43060552Selan 	} else {
43160552Selan 		if ((fd = open("Imakefile", O_RDONLY)) < 0)
43260552Selan 			if ((fd = open("imakefile", O_RDONLY)) < 0)
43360552Selan 				LogFatal("No description file.", "");
43460552Selan 			else
43560552Selan 				Imakefile = "imakefile";
43660552Selan 		else
43760552Selan 			Imakefile = "Imakefile";
43860552Selan 	}
43960552Selan 	close (fd);
44060552Selan 	return(Imakefile);
44160552Selan }
44260552Selan 
LogFatalI(s,i)44360552Selan LogFatalI(s, i)
44460552Selan 	char *s;
44560552Selan 	int i;
44660552Selan {
44760552Selan 	/*NOSTRICT*/
44860552Selan 	LogFatal(s, (char *)i);
44960552Selan }
45060552Selan 
LogFatal(x0,x1)45160552Selan LogFatal(x0,x1)
45260552Selan 	char *x0, *x1;
45360552Selan {
45460552Selan 	extern char	*sys_errlist[];
45560552Selan 	static boolean	entered = FALSE;
45660552Selan 
45760552Selan 	if (entered)
45860552Selan 		return;
45960552Selan 	entered = TRUE;
46060552Selan 
46160552Selan 	fprintf(stderr, "%s: ", program);
46260552Selan 	if (errno)
46360552Selan 		fprintf(stderr, "%s: ", sys_errlist[ errno ]);
46460552Selan 	fprintf(stderr, x0,x1);
46560552Selan 	fprintf(stderr, "  Stop.\n");
46660552Selan 	wrapup();
46760552Selan 	exit(1);
46860552Selan }
46960552Selan 
showargs(argv)47060552Selan showargs(argv)
47160552Selan 	char	**argv;
47260552Selan {
47360552Selan 	for (; *argv; argv++)
47460552Selan 		fprintf(stderr, "%s ", *argv);
47560552Selan 	fprintf(stderr, "\n");
47660552Selan }
47760552Selan 
cppit(Imakefile,template,outfd,outfname)47860552Selan cppit(Imakefile, template, outfd, outfname)
47960552Selan 	char	*Imakefile;
48060552Selan 	char	*template;
48160552Selan 	FILE	*outfd;
48260552Selan 	char	*outfname;
48360552Selan {
48460552Selan 	FILE	*pipeFile;
48560552Selan 	int	pid, pipefd[2];
48660552Selan 	waitType	status;
48760552Selan 	char	*cleanedImakefile;
48860552Selan 
48960552Selan 	/*
49060552Selan 	 * Get a pipe.
49160552Selan 	 */
49260552Selan 	if (pipe(pipefd) < 0)
49360552Selan 		LogFatal("Cannot make a pipe.", "");
49460552Selan 
49560552Selan 	/*
49660552Selan 	 * Fork and exec cpp
49760552Selan 	 */
49860552Selan 	pid = fork();
49960552Selan 	if (pid < 0)
50060552Selan 		LogFatal("Cannot fork.", "");
50160552Selan 	if (pid) {	/* parent */
50260552Selan 		close(pipefd[0]);
50360552Selan 		cleanedImakefile = CleanCppInput(Imakefile);
50460552Selan 		if ((pipeFile = fdopen(pipefd[1], "w")) == NULL)
50560552Selan 			LogFatalI("Cannot fdopen fd %d for output.", pipefd[1]);
50660552Selan 		fprintf(pipeFile, "#define IMAKE_TEMPLATE\t\"%s\"\n",
50760552Selan 			template);
50860552Selan 		fprintf(pipeFile, "#define INCLUDE_IMAKEFILE\t<%s>\n",
50960552Selan 			cleanedImakefile);
51060552Selan 		fprintf(pipeFile, "#include IMAKE_TEMPLATE\n");
51160552Selan 		fclose(pipeFile);
51260552Selan 		while (wait(&status) > 0) {
51360552Selan 			errno = 0;
51460552Selan 			if (WIFSIGNALED(status))
51560552Selan 				LogFatalI("Signal %d.", waitSig(status));
51660552Selan 			if (WIFEXITED(status) && waitCode(status))
51760552Selan 				LogFatalI("Exit code %d.", waitCode(status));
51860552Selan 		}
51960552Selan 		CleanCppOutput(outfd, outfname);
52060552Selan 	} else {	/* child... dup and exec cpp */
52160552Selan 		if (verbose)
52260552Selan 			showargs(cpp_argv);
52360552Selan 		dup2(pipefd[0], 0);
52460552Selan 		dup2(fileno(outfd), 1);
52560552Selan 		close(pipefd[1]);
52660552Selan 		execv(cpp, cpp_argv);
52760552Selan 		LogFatal("Cannot exec %s.", cpp);
52860552Selan 	}
52960552Selan }
53060552Selan 
makeit()53160552Selan makeit()
53260552Selan {
53360552Selan 	int	pid;
53460552Selan 	waitType	status;
53560552Selan 
53660552Selan 	/*
53760552Selan 	 * Fork and exec make
53860552Selan 	 */
53960552Selan 	pid = fork();
54060552Selan 	if (pid < 0)
54160552Selan 		LogFatal("Cannot fork.", "");
54260552Selan 	if (pid) {	/* parent... simply wait */
54360552Selan 		while (wait(&status) > 0) {
54460552Selan 			errno = 0;
54560552Selan 			if (WIFSIGNALED(status))
54660552Selan 				LogFatalI("Signal %d.", waitSig(status));
54760552Selan 			if (WIFEXITED(status) && waitCode(status))
54860552Selan 				LogFatalI("Exit code %d.", waitCode(status));
54960552Selan 		}
55060552Selan 	} else {	/* child... dup and exec cpp */
55160552Selan 		if (verbose)
55260552Selan 			showargs(make_argv);
55360552Selan 		if (make)
55460552Selan 			execv(make, make_argv);
55560552Selan 		else
55660552Selan 			execvp("make", make_argv);
55760552Selan 		LogFatal("Cannot exec %s.", make);
55860552Selan 	}
55960552Selan }
56060552Selan 
CleanCppInput(Imakefile)56160552Selan char *CleanCppInput(Imakefile)
56260552Selan 	char	*Imakefile;
56360552Selan {
56460552Selan 	FILE	*outFile = NULL;
56560552Selan 	int	infd;
56660552Selan 	char	*buf,		/* buffer for file content */
56760552Selan 		*pbuf,		/* walking pointer to buf */
56860552Selan 		*punwritten,	/* pointer to unwritten portion of buf */
56960552Selan 		*cleanedImakefile = Imakefile,	/* return value */
57060552Selan 		*ptoken,	/* pointer to # token */
57160552Selan 		*pend,		/* pointer to end of # token */
57260552Selan 		savec;		/* temporary character holder */
57360552Selan 	struct stat	st;
57460552Selan 
57560552Selan 	/*
57660552Selan 	 * grab the entire file.
57760552Selan 	 */
57860552Selan 	if ((infd = open(Imakefile, O_RDONLY)) < 0)
57960552Selan 		LogFatal("Cannot open %s for input.", Imakefile);
58060552Selan 	fstat(infd, &st);
58160552Selan 	buf = Emalloc(st.st_size+1);
582*60923Selan 	if (read(infd, buf, (size_t) st.st_size) != st.st_size)
58360552Selan 		LogFatal("Cannot read all of %s:", Imakefile);
58460552Selan 	close(infd);
58560552Selan 	buf[ st.st_size ] = '\0';
58660552Selan 
58760552Selan 	punwritten = pbuf = buf;
58860552Selan 	while (*pbuf) {
58960552Selan 	    /* pad make comments for cpp */
59060552Selan 	    if (*pbuf == '#' && (pbuf == buf || pbuf[-1] == '\n')) {
59160552Selan 
59260552Selan 		ptoken = pbuf+1;
59360552Selan 		while (*ptoken == ' ' || *ptoken == '\t')
59460552Selan 			ptoken++;
59560552Selan 		pend = ptoken;
59660552Selan 		while (*pend && *pend != ' ' && *pend != '\t' && *pend != '\n')
59760552Selan 			pend++;
59860552Selan 		savec = *pend;
59960552Selan 		*pend = '\0';
60060552Selan 		if (strcmp(ptoken, "include")
60160552Selan 		 && strcmp(ptoken, "define")
60260552Selan 		 && strcmp(ptoken, "undef")
60360552Selan 		 && strcmp(ptoken, "ifdef")
60460552Selan 		 && strcmp(ptoken, "ifndef")
60560552Selan 		 && strcmp(ptoken, "else")
60660552Selan 		 && strcmp(ptoken, "endif")
60760552Selan 		 && strcmp(ptoken, "if")) {
60860552Selan 		    if (outFile == NULL) {
60960552Selan 			tmpImakefile = Strdup(tmpImakefile);
61060552Selan 			(void) mktemp(tmpImakefile);
61160552Selan 			cleanedImakefile = tmpImakefile;
61260552Selan 			outFile = fopen(tmpImakefile, "w");
61360552Selan 			if (outFile == NULL)
61460552Selan 			    LogFatal("Cannot open %s for write.\n",
61560552Selan 				tmpImakefile);
61660552Selan 		    }
61760552Selan 		    fwrite(punwritten, sizeof(char), pbuf-punwritten, outFile);
61860552Selan 		    fputs("/**/", outFile);
61960552Selan 		    punwritten = pbuf;
62060552Selan 		}
62160552Selan 		*pend = savec;
62260552Selan 	    }
62360552Selan 	    pbuf++;
62460552Selan 	}
62560552Selan 	if (outFile) {
62660552Selan 	    fwrite(punwritten, sizeof(char), pbuf-punwritten, outFile);
62760552Selan 	    fclose(outFile); /* also closes the pipe */
62860552Selan 	}
62960552Selan 
63060552Selan 	return(cleanedImakefile);
63160552Selan }
63260552Selan 
CleanCppOutput(tmpfd,tmpfname)63360552Selan CleanCppOutput(tmpfd, tmpfname)
63460552Selan 	FILE	*tmpfd;
63560552Selan 	char	*tmpfname;
63660552Selan {
63760552Selan 	char	*input;
63860552Selan 	int	blankline = 0;
63960552Selan 
64060552Selan 	while(input = ReadLine(tmpfd, tmpfname)) {
64160552Selan 		if (isempty(input)) {
64260552Selan 			if (blankline++)
64360552Selan 				continue;
64460552Selan 			KludgeResetRule();
64560552Selan 		} else {
64660552Selan 			blankline = 0;
64760552Selan 			KludgeOutputLine(&input);
64860552Selan 			fputs(input, tmpfd);
64960552Selan 		}
65060552Selan 		putc('\n', tmpfd);
65160552Selan 	}
65260552Selan 	fflush(tmpfd);
65360552Selan #ifdef NFS_STDOUT_BUG
65460552Selan 	/*
65560552Selan 	 * On some systems, NFS seems to leave a large number of nulls at
65660552Selan 	 * the end of the file.  Ralph Swick says that this kludge makes the
65760552Selan 	 * problem go away.
65860552Selan 	 */
65960552Selan 	ftruncate (fileno(tmpfd), (off_t)ftell(tmpfd));
66060552Selan #endif
66160552Selan }
66260552Selan 
66360552Selan /*
66460552Selan  * Determine of a line has nothing in it.  As a side effect, we trim white
66560552Selan  * space from the end of the line.  Cpp magic cookies are also thrown away.
66660552Selan  */
isempty(line)66760552Selan isempty(line)
66860552Selan 	char	*line;
66960552Selan {
67060552Selan 	char	*pend;
67160552Selan 
67260552Selan 	/*
67360552Selan 	 * Check for lines of the form
67460552Selan 	 *	# n "...
67560552Selan 	 * or
67660552Selan 	 *	# line n "...
67760552Selan 	 */
67860552Selan 	if (*line == '#') {
67960552Selan 		pend = line+1;
68060552Selan 		if (*pend == ' ')
68160552Selan 			pend++;
68260552Selan 		if (strncmp(pend, "line ", 5) == 0)
68360552Selan 			pend += 5;
68460552Selan 		if (isdigit(*pend)) {
68560552Selan 			while (isdigit(*pend))
68660552Selan 				pend++;
68760552Selan 			if (*pend++ == ' ' && *pend == '"')
68860552Selan 				return(TRUE);
68960552Selan 		}
69060552Selan 	}
69160552Selan 
69260552Selan 	/*
69360552Selan 	 * Find the end of the line and then walk back.
69460552Selan 	 */
69560552Selan 	for (pend=line; *pend; pend++) ;
69660552Selan 
69760552Selan 	pend--;
69860552Selan 	while (pend >= line && (*pend == ' ' || *pend == '\t'))
69960552Selan 		pend--;
70060552Selan 	*++pend = '\0';
70160552Selan 	return (*line == '\0');
70260552Selan }
70360552Selan 
70460552Selan /*ARGSUSED*/
ReadLine(tmpfd,tmpfname)70560552Selan char *ReadLine(tmpfd, tmpfname)
70660552Selan 	FILE	*tmpfd;
70760552Selan 	char	*tmpfname;
70860552Selan {
70960552Selan 	static boolean	initialized = FALSE;
71060552Selan 	static char	*buf, *pline, *end;
71160552Selan 	char	*p1, *p2;
71260552Selan 
71360552Selan 	if (! initialized) {
71460552Selan 		int	total_red;
71560552Selan 		struct stat	st;
71660552Selan 
71760552Selan 		/*
71860552Selan 		 * Slurp it all up.
71960552Selan 		 */
72060552Selan 		fseek(tmpfd, 0, 0);
72160552Selan 		fstat(fileno(tmpfd), &st);
72260552Selan 		pline = buf = Emalloc(st.st_size+1);
72360552Selan 		total_red = read(fileno(tmpfd), buf, st.st_size);
72460552Selan 		if (total_red != st.st_size)
72560552Selan 			LogFatal("cannot read %s\n", tmpMakefile);
72660552Selan 		end = buf + st.st_size;
72760552Selan 		*end = '\0';
72860552Selan 		lseek(fileno(tmpfd), 0, 0);
72960552Selan #ifdef SYSV
73060552Selan 		freopen(tmpfname, "w+", tmpfd);
73160552Selan #else	/* !SYSV */
73260552Selan 		ftruncate(fileno(tmpfd), 0);
73360552Selan #endif	/* !SYSV */
73460552Selan 		initialized = TRUE;
73560552Selan 	    fprintf (tmpfd, "# Makefile generated by imake - do not edit!\n");
73660552Selan 	    fprintf (tmpfd, "# %s\n",
73760552Selan 		"$XConsortium: imake.c,v 1.65 91/07/25 17:50:17 rws Exp $");
73860552Selan 
73960552Selan #ifdef FIXUP_CPP_WHITESPACE
74060552Selan 	    {
74160552Selan 		static char *cpp_warning[] = {
74260552Selan "#",
74360552Selan "# The cpp used on this machine replaces all newlines and multiple tabs and",
74460552Selan "# spaces in a macro expansion with a single space.  Imake tries to compensate",
74560552Selan "# for this, but is not always successful.",
74660552Selan "#",
74760552Selan NULL };
74860552Selan 		char **cpp;
74960552Selan 
75060552Selan 		for (cpp = cpp_warning; *cpp; cpp++) {
75160552Selan 		    fprintf (tmpfd, "%s\n", *cpp);
75260552Selan 		}
75360552Selan 	    }
75460552Selan #endif /* FIXUP_CPP_WHITESPACE */
75560552Selan 	}
75660552Selan 
75760552Selan 	for (p1 = pline; p1 < end; p1++) {
75860552Selan 		if (*p1 == '@' && *(p1+1) == '@') { /* soft EOL */
75960552Selan 			*p1++ = '\0';
76060552Selan 			p1++; /* skip over second @ */
76160552Selan 			break;
76260552Selan 		}
76360552Selan 		else if (*p1 == '\n') { /* real EOL */
76460552Selan 			*p1++ = '\0';
76560552Selan 			break;
76660552Selan 		}
76760552Selan 	}
76860552Selan 
76960552Selan 	/*
77060552Selan 	 * return NULL at the end of the file.
77160552Selan 	 */
77260552Selan 	p2 = (pline == p1 ? NULL : pline);
77360552Selan 	pline = p1;
77460552Selan 	return(p2);
77560552Selan }
77660552Selan 
writetmpfile(fd,buf,cnt)77760552Selan writetmpfile(fd, buf, cnt)
77860552Selan 	FILE	*fd;
77960552Selan 	int	cnt;
78060552Selan 	char	*buf;
78160552Selan {
78260552Selan 	errno = 0;
78360552Selan 	if (fwrite(buf, cnt, 1, fd) != 1)
78460552Selan 		LogFatal("Cannot write to %s.", tmpMakefile);
78560552Selan }
78660552Selan 
Emalloc(size)78760552Selan char *Emalloc(size)
78860552Selan 	int	size;
78960552Selan {
79060552Selan 	char	*p;
79160552Selan 
79260552Selan 	if ((p = malloc(size)) == NULL)
79360552Selan 		LogFatalI("Cannot allocate %d bytes\n", size);
79460552Selan 	return(p);
79560552Selan }
79660552Selan 
79760552Selan #ifdef FIXUP_CPP_WHITESPACE
KludgeOutputLine(pline)79860552Selan KludgeOutputLine(pline)
79960552Selan 	char	**pline;
80060552Selan {
80160552Selan 	char	*p = *pline;
80260552Selan 
80360552Selan 	switch (*p) {
80460552Selan 	    case '#':	/*Comment - ignore*/
80560552Selan 		break;
80660552Selan 	    case '\t':	/*Already tabbed - ignore it*/
80760552Selan 	    	break;
80860552Selan 	    case ' ':	/*May need a tab*/
80960552Selan 	    default:
81060552Selan 		for (; *p; p++) if (p[0] == ':' &&
81160552Selan 				    p > *pline && p[-1] != '\\') {
81260552Selan 		    if (**pline == ' ')
81360552Selan 			(*pline)++;
81460552Selan 		    InRule = TRUE;
81560552Selan 		    break;
81660552Selan 		}
81760552Selan 		if (InRule && **pline == ' ')
81860552Selan 		    **pline = '\t';
81960552Selan 		break;
82060552Selan 	}
82160552Selan }
82260552Selan 
KludgeResetRule()82360552Selan KludgeResetRule()
82460552Selan {
82560552Selan 	InRule = FALSE;
82660552Selan }
82760552Selan #endif /* FIXUP_CPP_WHITESPACE */
82860552Selan 
Strdup(cp)82960552Selan char *Strdup(cp)
83060552Selan 	register char *cp;
83160552Selan {
83260552Selan 	register char *new = Emalloc(strlen(cp) + 1);
83360552Selan 
83460552Selan 	strcpy(new, cp);
83560552Selan 	return new;
83660552Selan }
837