xref: /original-bsd/local/X11R5/mit/config/imake.c (revision 122f4730)
1 /* $XConsortium: imake.c,v 1.65 91/07/25 17:50:17 rws Exp $ */
2 
3 /*****************************************************************************\
4  *                                                                           *
5  *                                Porting Note                               *
6  *                                                                           *
7  * Add the value of BOOTSTRAPCFLAGS to the cpp_argv table so that it will be *
8  * passed to the template file.                                              *
9  *                                                                           *
10 \*****************************************************************************/
11 
12 /*
13  *
14  * Copyright 1985, 1986, 1987 by the Massachusetts Institute of Technology
15  *
16  * Permission to use, copy, modify, and distribute this
17  * software and its documentation for any purpose and without
18  * fee is hereby granted, provided that the above copyright
19  * notice appear in all copies and that both that copyright
20  * notice and this permission notice appear in supporting
21  * documentation, and that the name of M.I.T. not be used in
22  * advertising or publicity pertaining to distribution of the
23  * software without specific, written prior permission.
24  * M.I.T. makes no representations about the suitability of
25  * this software for any purpose.  It is provided "as is"
26  * without express or implied warranty.
27  *
28  * Original Author:
29  *	Todd Brunhoff
30  *	Tektronix, inc.
31  *	While a guest engineer at Project Athena, MIT
32  *
33  * imake: the include-make program.
34  *
35  * Usage: imake [-Idir] [-Ddefine] [-T] [-f imakefile ] [-s] [-e] [-v] [make flags]
36  *
37  * Imake takes a template makefile (Imake.tmpl) and runs cpp on it
38  * producing a temporary makefile in /tmp.  It then runs make on
39  * this pre-processed makefile.
40  * Options:
41  *		-D	define.  Same as cpp -D argument.
42  *		-I	Include directory.  Same as cpp -I argument.
43  *		-T	template.  Designate a template other
44  * 			than Imake.tmpl
45  *		-s[F]	show.  Show the produced makefile on the standard
46  *			output.  Make is not run is this case.  If a file
47  *			argument is provided, the output is placed there.
48  *              -e[F]   execute instead of show; optionally name Makefile F
49  *		-v	verbose.  Show the make command line executed.
50  *
51  * Environment variables:
52  *
53  *		IMAKEINCLUDE	Include directory to use in addition to "."
54  *		IMAKECPP	Cpp to use instead of /lib/cpp
55  *		IMAKEMAKE	make program to use other than what is
56  *				found by searching the $PATH variable.
57  * Other features:
58  *	imake reads the entire cpp output into memory and then scans it
59  *	for occurences of "@@".  If it encounters them, it replaces it with
60  *	a newline.  It also trims any trailing white space on output lines
61  *	(because make gets upset at them).  This helps when cpp expands
62  *	multi-line macros but you want them to appear on multiple lines.
63  *
64  *	The macros MAKEFILE and MAKE are provided as macros
65  *	to make.  MAKEFILE is set to imake's makefile (not the constructed,
66  *	preprocessed one) and MAKE is set to argv[0], i.e. the name of
67  *	the imake program.
68  *
69  * Theory of operation:
70  *   1. Determine the name of the imakefile from the command line (-f)
71  *	or from the content of the current directory (Imakefile or imakefile).
72  *	Call this <imakefile>.  This gets added to the arguments for
73  *	make as MAKEFILE=<imakefile>.
74  *   2. Determine the name of the template from the command line (-T)
75  *	or the default, Imake.tmpl.  Call this <template>
76  *   3. Start up cpp an provide it with three lines of input:
77  *		#define IMAKE_TEMPLATE		" <template> "
78  *		#define INCLUDE_IMAKEFILE	< <imakefile> >
79  *		#include IMAKE_TEMPLATE
80  *	Note that the define for INCLUDE_IMAKEFILE is intended for
81  *	use in the template file.  This implies that the imake is
82  *	useless unless the template file contains at least the line
83  *		#include INCLUDE_IMAKEFILE
84  *   4. Gather the output from cpp, and clean it up, expanding @@ to
85  *	newlines, stripping trailing white space, cpp control lines,
86  *	and extra blank lines.  This cleaned output is placed in a
87  *	temporary file.  Call this <makefile>.
88  *   5. Start up make specifying <makefile> as its input.
89  *
90  * The design of the template makefile should therefore be:
91  *	<set global macros like CFLAGS, etc.>
92  *	<include machine dependent additions>
93  *	#include INCLUDE_IMAKEFILE
94  *	<add any global targets like 'clean' and long dependencies>
95  */
96 #include <stdio.h>
97 #if (defined(SVR4) || defined(_IBMR2) || defined(SYSV386)) && __STDC__
98 FILE * fdopen();
99 #endif
100 #include <ctype.h>
101 #include "Xosdefs.h"
102 #ifndef X_NOT_POSIX
103 #define _POSIX_SOURCE
104 #endif
105 #include <sys/types.h>
106 #include <fcntl.h>
107 #ifdef X_NOT_POSIX
108 #include <sys/file.h>
109 #else
110 #ifdef hp9000
111 #undef _POSIX_SOURCE
112 #endif
113 #include <unistd.h>
114 #ifdef hp9000
115 #define _POSIX_SOURCE
116 #endif
117 #endif
118 #if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE)
119 #include <signal.h>
120 #else
121 #define _POSIX_SOURCE
122 #include <signal.h>
123 #undef _POSIX_SOURCE
124 #endif
125 #include <sys/stat.h>
126 #ifndef X_NOT_POSIX
127 #ifdef _POSIX_SOURCE
128 #include <sys/wait.h>
129 #else
130 #define _POSIX_SOURCE
131 #include <sys/wait.h>
132 #undef _POSIX_SOURCE
133 #endif
134 #define waitCode(w)	WEXITSTATUS(w)
135 #define waitSig(w)	WTERMSIG(w)
136 typedef int		waitType;
137 #else /* X_NOT_POSIX */
138 #ifdef SYSV
139 #define waitCode(w)	(((w) >> 8) & 0x7f)
140 #define waitSig(w)	((w) & 0xff)
141 typedef int		waitType;
142 #else /* SYSV */
143 #include <sys/wait.h>
144 #define waitCode(w)	((w).w_T.w_Retcode)
145 #define waitSig(w)	((w).w_T.w_Termsig)
146 typedef union wait	waitType;
147 #endif
148 #ifndef WIFSIGNALED
149 #define WIFSIGNALED(w) waitSig(w)
150 #endif
151 #ifndef WIFEXITED
152 #define WIFEXITED(w) waitCode(w)
153 #endif
154 #endif /* X_NOT_POSIX */
155 #ifndef X_NOT_STDC_ENV
156 #include <stdlib.h>
157 #else
158 char *malloc(), *realloc();
159 void exit();
160 #endif
161 #if defined(macII) && !defined(__STDC__)  /* stdlib.h fails to define these */
162 char *malloc(), *realloc();
163 #endif /* macII */
164 #ifdef X_NOT_STDC_ENV
165 extern char	*getenv();
166 #endif
167 #include <errno.h>
168 extern int	errno;
169 #include "imakemdep.h"
170 
171 
172 #define	TRUE		1
173 #define	FALSE		0
174 
175 #ifdef FIXUP_CPP_WHITESPACE
176 int	InRule = FALSE;
177 #endif
178 
179 /*
180  * Some versions of cpp reduce all tabs in macro expansion to a single
181  * space.  In addition, the escaped newline may be replaced with a
182  * space instead of being deleted.  Blech.
183  */
184 #ifndef FIXUP_CPP_WHITESPACE
185 #define KludgeOutputLine(arg)
186 #define KludgeResetRule()
187 #endif
188 
189 typedef	unsigned char	boolean;
190 
191 #ifndef DEFAULT_CPP
192 #ifdef USE_CC_E
193 #define DEFAULT_CPP "/bin/cc"
194 #else
195 #ifdef CPP_PROGRAM
196 #define DEFAULT_CPP CPP_PROGRAM
197 #else
198 #define DEFAULT_CPP "/lib/cpp"
199 #endif
200 #endif
201 #endif
202 
203 char *cpp = DEFAULT_CPP;
204 
205 char	*tmpMakefile    = "/tmp/Imf.XXXXXX";
206 char	*tmpImakefile    = "/tmp/IIf.XXXXXX";
207 char	*make_argv[ ARGUMENTS ] = { "make" };
208 
209 int	make_argindex;
210 int	cpp_argindex;
211 char	*make = NULL;
212 char	*Imakefile = NULL;
213 char	*Makefile = "Makefile";
214 char	*Template = "Imake.tmpl";
215 char	*program;
216 char	*FindImakefile();
217 char	*ReadLine();
218 char	*CleanCppInput();
219 char	*Strdup();
220 #if defined(__STDC__) || defined(__GNUC__)
221 char	*Emalloc(int);
222 #else
223 char	*Emalloc();
224 #endif
225 
226 boolean	verbose = FALSE;
227 boolean	show = TRUE;
228 
229 main(argc, argv)
230 	int	argc;
231 	char	**argv;
232 {
233 	FILE	*tmpfd;
234 	char	makeMacro[ BUFSIZ ];
235 	char	makefileMacro[ BUFSIZ ];
236 
237 	program = argv[0];
238 	init();
239 	SetOpts(argc, argv);
240 #ifdef USE_CC_E
241 	AddCppArg("-");
242 #endif
243 
244 	Imakefile = FindImakefile(Imakefile);
245 	if (Makefile)
246 		tmpMakefile = Makefile;
247 	else {
248 		tmpMakefile = Strdup(tmpMakefile);
249 		(void) mktemp(tmpMakefile);
250 	}
251 	AddMakeArg("-f");
252 	AddMakeArg( tmpMakefile );
253 	sprintf(makeMacro, "MAKE=%s", program);
254 	AddMakeArg( makeMacro );
255 	sprintf(makefileMacro, "MAKEFILE=%s", Imakefile);
256 	AddMakeArg( makefileMacro );
257 
258 	if ((tmpfd = fopen(tmpMakefile, "w+")) == NULL)
259 		LogFatal("Cannot create temporary file %s.", tmpMakefile);
260 
261 	cppit(Imakefile, Template, tmpfd, tmpMakefile);
262 
263 	if (show) {
264 		if (Makefile == NULL)
265 			showit(tmpfd);
266 	} else
267 		makeit();
268 	wrapup();
269 	exit(0);
270 }
271 
272 showit(fd)
273 	FILE	*fd;
274 {
275 	char	buf[ BUFSIZ ];
276 	int	red;
277 
278 	fseek(fd, 0, 0);
279 	while ((red = fread(buf, 1, BUFSIZ, fd)) > 0)
280 		fwrite(buf, red, 1, stdout);
281 	if (red < 0)
282 		LogFatal("Cannot write stdout.", "");
283 }
284 
285 wrapup()
286 {
287 	if (tmpMakefile != Makefile)
288 		unlink(tmpMakefile);
289 	unlink(tmpImakefile);
290 }
291 
292 #ifdef SIGNALRETURNSINT
293 int
294 #else
295 void
296 #endif
297 catch(sig)
298 	int	sig;
299 {
300 	errno = 0;
301 	LogFatalI("Signal %d.", sig);
302 }
303 
304 /*
305  * Initialize some variables.
306  */
307 init()
308 {
309 	char	*p;
310 
311 	make_argindex=0;
312 	while (make_argv[ make_argindex ] != NULL)
313 		make_argindex++;
314 	cpp_argindex = 0;
315 	while (cpp_argv[ cpp_argindex ] != NULL)
316 		cpp_argindex++;
317 
318 	/*
319 	 * See if the standard include directory is different than
320 	 * the default.  Or if cpp is not the default.  Or if the make
321 	 * found by the PATH variable is not the default.
322 	 */
323 	if (p = getenv("IMAKEINCLUDE")) {
324 		if (*p != '-' || *(p+1) != 'I')
325 			LogFatal("Environment var IMAKEINCLUDE %s\n",
326 				"must begin with -I");
327 		AddCppArg(p);
328 		for (; *p; p++)
329 			if (*p == ' ') {
330 				*p++ = '\0';
331 				AddCppArg(p);
332 			}
333 	}
334 	if (p = getenv("IMAKECPP"))
335 		cpp = p;
336 	if (p = getenv("IMAKEMAKE"))
337 		make = p;
338 
339 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
340 		signal(SIGINT, catch);
341 }
342 
343 AddMakeArg(arg)
344 	char	*arg;
345 {
346 	errno = 0;
347 	if (make_argindex >= ARGUMENTS-1)
348 		LogFatal("Out of internal storage.", "");
349 	make_argv[ make_argindex++ ] = arg;
350 	make_argv[ make_argindex ] = NULL;
351 }
352 
353 AddCppArg(arg)
354 	char	*arg;
355 {
356 	errno = 0;
357 	if (cpp_argindex >= ARGUMENTS-1)
358 		LogFatal("Out of internal storage.", "");
359 	cpp_argv[ cpp_argindex++ ] = arg;
360 	cpp_argv[ cpp_argindex ] = NULL;
361 }
362 
363 SetOpts(argc, argv)
364 	int	argc;
365 	char	**argv;
366 {
367 	errno = 0;
368 	/*
369 	 * Now gather the arguments for make
370 	 */
371 	for(argc--, argv++; argc; argc--, argv++) {
372 	    /*
373 	     * We intercept these flags.
374 	     */
375 	    if (argv[0][0] == '-') {
376 		if (argv[0][1] == 'D') {
377 		    AddCppArg(argv[0]);
378 		} else if (argv[0][1] == 'I') {
379 		    AddCppArg(argv[0]);
380 		} else if (argv[0][1] == 'f') {
381 		    if (argv[0][2])
382 			Imakefile = argv[0]+2;
383 		    else {
384 			argc--, argv++;
385 			if (! argc)
386 			    LogFatal("No description arg after -f flag\n", "");
387 			Imakefile = argv[0];
388 		    }
389 		} else if (argv[0][1] == 's') {
390 		    if (argv[0][2])
391 			Makefile = ((argv[0][2] == '-') && !argv[0][3]) ?
392 			    NULL : argv[0]+2;
393 		    else {
394 			argc--, argv++;
395 			if (!argc)
396 			    LogFatal("No description arg after -s flag\n", "");
397 			Makefile = ((argv[0][0] == '-') && !argv[0][1]) ?
398 			    NULL : argv[0];
399 		    }
400 		    show = TRUE;
401 		} else if (argv[0][1] == 'e') {
402 		   Makefile = (argv[0][2] ? argv[0]+2 : NULL);
403 		   show = FALSE;
404 		} else if (argv[0][1] == 'T') {
405 		    if (argv[0][2])
406 			Template = argv[0]+2;
407 		    else {
408 			argc--, argv++;
409 			if (! argc)
410 			    LogFatal("No description arg after -T flag\n", "");
411 			Template = argv[0];
412 		    }
413 		} else if (argv[0][1] == 'v') {
414 		    verbose = TRUE;
415 		} else
416 		    AddMakeArg(argv[0]);
417 	    } else
418 		AddMakeArg(argv[0]);
419 	}
420 }
421 
422 char *FindImakefile(Imakefile)
423 	char	*Imakefile;
424 {
425 	int	fd;
426 
427 	if (Imakefile) {
428 		if ((fd = open(Imakefile, O_RDONLY)) < 0)
429 			LogFatal("Cannot open %s.", Imakefile);
430 	} else {
431 		if ((fd = open("Imakefile", O_RDONLY)) < 0)
432 			if ((fd = open("imakefile", O_RDONLY)) < 0)
433 				LogFatal("No description file.", "");
434 			else
435 				Imakefile = "imakefile";
436 		else
437 			Imakefile = "Imakefile";
438 	}
439 	close (fd);
440 	return(Imakefile);
441 }
442 
443 LogFatalI(s, i)
444 	char *s;
445 	int i;
446 {
447 	/*NOSTRICT*/
448 	LogFatal(s, (char *)i);
449 }
450 
451 LogFatal(x0,x1)
452 	char *x0, *x1;
453 {
454 	extern char	*sys_errlist[];
455 	static boolean	entered = FALSE;
456 
457 	if (entered)
458 		return;
459 	entered = TRUE;
460 
461 	fprintf(stderr, "%s: ", program);
462 	if (errno)
463 		fprintf(stderr, "%s: ", sys_errlist[ errno ]);
464 	fprintf(stderr, x0,x1);
465 	fprintf(stderr, "  Stop.\n");
466 	wrapup();
467 	exit(1);
468 }
469 
470 showargs(argv)
471 	char	**argv;
472 {
473 	for (; *argv; argv++)
474 		fprintf(stderr, "%s ", *argv);
475 	fprintf(stderr, "\n");
476 }
477 
478 cppit(Imakefile, template, outfd, outfname)
479 	char	*Imakefile;
480 	char	*template;
481 	FILE	*outfd;
482 	char	*outfname;
483 {
484 	FILE	*pipeFile;
485 	int	pid, pipefd[2];
486 	waitType	status;
487 	char	*cleanedImakefile;
488 
489 	/*
490 	 * Get a pipe.
491 	 */
492 	if (pipe(pipefd) < 0)
493 		LogFatal("Cannot make a pipe.", "");
494 
495 	/*
496 	 * Fork and exec cpp
497 	 */
498 	pid = fork();
499 	if (pid < 0)
500 		LogFatal("Cannot fork.", "");
501 	if (pid) {	/* parent */
502 		close(pipefd[0]);
503 		cleanedImakefile = CleanCppInput(Imakefile);
504 		if ((pipeFile = fdopen(pipefd[1], "w")) == NULL)
505 			LogFatalI("Cannot fdopen fd %d for output.", pipefd[1]);
506 		fprintf(pipeFile, "#define IMAKE_TEMPLATE\t\"%s\"\n",
507 			template);
508 		fprintf(pipeFile, "#define INCLUDE_IMAKEFILE\t<%s>\n",
509 			cleanedImakefile);
510 		fprintf(pipeFile, "#include IMAKE_TEMPLATE\n");
511 		fclose(pipeFile);
512 		while (wait(&status) > 0) {
513 			errno = 0;
514 			if (WIFSIGNALED(status))
515 				LogFatalI("Signal %d.", waitSig(status));
516 			if (WIFEXITED(status) && waitCode(status))
517 				LogFatalI("Exit code %d.", waitCode(status));
518 		}
519 		CleanCppOutput(outfd, outfname);
520 	} else {	/* child... dup and exec cpp */
521 		if (verbose)
522 			showargs(cpp_argv);
523 		dup2(pipefd[0], 0);
524 		dup2(fileno(outfd), 1);
525 		close(pipefd[1]);
526 		execv(cpp, cpp_argv);
527 		LogFatal("Cannot exec %s.", cpp);
528 	}
529 }
530 
531 makeit()
532 {
533 	int	pid;
534 	waitType	status;
535 
536 	/*
537 	 * Fork and exec make
538 	 */
539 	pid = fork();
540 	if (pid < 0)
541 		LogFatal("Cannot fork.", "");
542 	if (pid) {	/* parent... simply wait */
543 		while (wait(&status) > 0) {
544 			errno = 0;
545 			if (WIFSIGNALED(status))
546 				LogFatalI("Signal %d.", waitSig(status));
547 			if (WIFEXITED(status) && waitCode(status))
548 				LogFatalI("Exit code %d.", waitCode(status));
549 		}
550 	} else {	/* child... dup and exec cpp */
551 		if (verbose)
552 			showargs(make_argv);
553 		if (make)
554 			execv(make, make_argv);
555 		else
556 			execvp("make", make_argv);
557 		LogFatal("Cannot exec %s.", make);
558 	}
559 }
560 
561 char *CleanCppInput(Imakefile)
562 	char	*Imakefile;
563 {
564 	FILE	*outFile = NULL;
565 	int	infd;
566 	char	*buf,		/* buffer for file content */
567 		*pbuf,		/* walking pointer to buf */
568 		*punwritten,	/* pointer to unwritten portion of buf */
569 		*cleanedImakefile = Imakefile,	/* return value */
570 		*ptoken,	/* pointer to # token */
571 		*pend,		/* pointer to end of # token */
572 		savec;		/* temporary character holder */
573 	struct stat	st;
574 
575 	/*
576 	 * grab the entire file.
577 	 */
578 	if ((infd = open(Imakefile, O_RDONLY)) < 0)
579 		LogFatal("Cannot open %s for input.", Imakefile);
580 	fstat(infd, &st);
581 	buf = Emalloc(st.st_size+1);
582 	if (read(infd, buf, st.st_size) != st.st_size)
583 		LogFatal("Cannot read all of %s:", Imakefile);
584 	close(infd);
585 	buf[ st.st_size ] = '\0';
586 
587 	punwritten = pbuf = buf;
588 	while (*pbuf) {
589 	    /* pad make comments for cpp */
590 	    if (*pbuf == '#' && (pbuf == buf || pbuf[-1] == '\n')) {
591 
592 		ptoken = pbuf+1;
593 		while (*ptoken == ' ' || *ptoken == '\t')
594 			ptoken++;
595 		pend = ptoken;
596 		while (*pend && *pend != ' ' && *pend != '\t' && *pend != '\n')
597 			pend++;
598 		savec = *pend;
599 		*pend = '\0';
600 		if (strcmp(ptoken, "include")
601 		 && strcmp(ptoken, "define")
602 		 && strcmp(ptoken, "undef")
603 		 && strcmp(ptoken, "ifdef")
604 		 && strcmp(ptoken, "ifndef")
605 		 && strcmp(ptoken, "else")
606 		 && strcmp(ptoken, "endif")
607 		 && strcmp(ptoken, "if")) {
608 		    if (outFile == NULL) {
609 			tmpImakefile = Strdup(tmpImakefile);
610 			(void) mktemp(tmpImakefile);
611 			cleanedImakefile = tmpImakefile;
612 			outFile = fopen(tmpImakefile, "w");
613 			if (outFile == NULL)
614 			    LogFatal("Cannot open %s for write.\n",
615 				tmpImakefile);
616 		    }
617 		    fwrite(punwritten, sizeof(char), pbuf-punwritten, outFile);
618 		    fputs("/**/", outFile);
619 		    punwritten = pbuf;
620 		}
621 		*pend = savec;
622 	    }
623 	    pbuf++;
624 	}
625 	if (outFile) {
626 	    fwrite(punwritten, sizeof(char), pbuf-punwritten, outFile);
627 	    fclose(outFile); /* also closes the pipe */
628 	}
629 
630 	return(cleanedImakefile);
631 }
632 
633 CleanCppOutput(tmpfd, tmpfname)
634 	FILE	*tmpfd;
635 	char	*tmpfname;
636 {
637 	char	*input;
638 	int	blankline = 0;
639 
640 	while(input = ReadLine(tmpfd, tmpfname)) {
641 		if (isempty(input)) {
642 			if (blankline++)
643 				continue;
644 			KludgeResetRule();
645 		} else {
646 			blankline = 0;
647 			KludgeOutputLine(&input);
648 			fputs(input, tmpfd);
649 		}
650 		putc('\n', tmpfd);
651 	}
652 	fflush(tmpfd);
653 #ifdef NFS_STDOUT_BUG
654 	/*
655 	 * On some systems, NFS seems to leave a large number of nulls at
656 	 * the end of the file.  Ralph Swick says that this kludge makes the
657 	 * problem go away.
658 	 */
659 	ftruncate (fileno(tmpfd), (off_t)ftell(tmpfd));
660 #endif
661 }
662 
663 /*
664  * Determine of a line has nothing in it.  As a side effect, we trim white
665  * space from the end of the line.  Cpp magic cookies are also thrown away.
666  */
667 isempty(line)
668 	char	*line;
669 {
670 	char	*pend;
671 
672 	/*
673 	 * Check for lines of the form
674 	 *	# n "...
675 	 * or
676 	 *	# line n "...
677 	 */
678 	if (*line == '#') {
679 		pend = line+1;
680 		if (*pend == ' ')
681 			pend++;
682 		if (strncmp(pend, "line ", 5) == 0)
683 			pend += 5;
684 		if (isdigit(*pend)) {
685 			while (isdigit(*pend))
686 				pend++;
687 			if (*pend++ == ' ' && *pend == '"')
688 				return(TRUE);
689 		}
690 	}
691 
692 	/*
693 	 * Find the end of the line and then walk back.
694 	 */
695 	for (pend=line; *pend; pend++) ;
696 
697 	pend--;
698 	while (pend >= line && (*pend == ' ' || *pend == '\t'))
699 		pend--;
700 	*++pend = '\0';
701 	return (*line == '\0');
702 }
703 
704 /*ARGSUSED*/
705 char *ReadLine(tmpfd, tmpfname)
706 	FILE	*tmpfd;
707 	char	*tmpfname;
708 {
709 	static boolean	initialized = FALSE;
710 	static char	*buf, *pline, *end;
711 	char	*p1, *p2;
712 
713 	if (! initialized) {
714 		int	total_red;
715 		struct stat	st;
716 
717 		/*
718 		 * Slurp it all up.
719 		 */
720 		fseek(tmpfd, 0, 0);
721 		fstat(fileno(tmpfd), &st);
722 		pline = buf = Emalloc(st.st_size+1);
723 		total_red = read(fileno(tmpfd), buf, st.st_size);
724 		if (total_red != st.st_size)
725 			LogFatal("cannot read %s\n", tmpMakefile);
726 		end = buf + st.st_size;
727 		*end = '\0';
728 		lseek(fileno(tmpfd), 0, 0);
729 #ifdef SYSV
730 		freopen(tmpfname, "w+", tmpfd);
731 #else	/* !SYSV */
732 		ftruncate(fileno(tmpfd), 0);
733 #endif	/* !SYSV */
734 		initialized = TRUE;
735 	    fprintf (tmpfd, "# Makefile generated by imake - do not edit!\n");
736 	    fprintf (tmpfd, "# %s\n",
737 		"$XConsortium: imake.c,v 1.65 91/07/25 17:50:17 rws Exp $");
738 
739 #ifdef FIXUP_CPP_WHITESPACE
740 	    {
741 		static char *cpp_warning[] = {
742 "#",
743 "# The cpp used on this machine replaces all newlines and multiple tabs and",
744 "# spaces in a macro expansion with a single space.  Imake tries to compensate",
745 "# for this, but is not always successful.",
746 "#",
747 NULL };
748 		char **cpp;
749 
750 		for (cpp = cpp_warning; *cpp; cpp++) {
751 		    fprintf (tmpfd, "%s\n", *cpp);
752 		}
753 	    }
754 #endif /* FIXUP_CPP_WHITESPACE */
755 	}
756 
757 	for (p1 = pline; p1 < end; p1++) {
758 		if (*p1 == '@' && *(p1+1) == '@') { /* soft EOL */
759 			*p1++ = '\0';
760 			p1++; /* skip over second @ */
761 			break;
762 		}
763 		else if (*p1 == '\n') { /* real EOL */
764 			*p1++ = '\0';
765 			break;
766 		}
767 	}
768 
769 	/*
770 	 * return NULL at the end of the file.
771 	 */
772 	p2 = (pline == p1 ? NULL : pline);
773 	pline = p1;
774 	return(p2);
775 }
776 
777 writetmpfile(fd, buf, cnt)
778 	FILE	*fd;
779 	int	cnt;
780 	char	*buf;
781 {
782 	errno = 0;
783 	if (fwrite(buf, cnt, 1, fd) != 1)
784 		LogFatal("Cannot write to %s.", tmpMakefile);
785 }
786 
787 char *Emalloc(size)
788 	int	size;
789 {
790 	char	*p;
791 
792 	if ((p = malloc(size)) == NULL)
793 		LogFatalI("Cannot allocate %d bytes\n", size);
794 	return(p);
795 }
796 
797 #ifdef FIXUP_CPP_WHITESPACE
798 KludgeOutputLine(pline)
799 	char	**pline;
800 {
801 	char	*p = *pline;
802 
803 	switch (*p) {
804 	    case '#':	/*Comment - ignore*/
805 		break;
806 	    case '\t':	/*Already tabbed - ignore it*/
807 	    	break;
808 	    case ' ':	/*May need a tab*/
809 	    default:
810 		for (; *p; p++) if (p[0] == ':' &&
811 				    p > *pline && p[-1] != '\\') {
812 		    if (**pline == ' ')
813 			(*pline)++;
814 		    InRule = TRUE;
815 		    break;
816 		}
817 		if (InRule && **pline == ' ')
818 		    **pline = '\t';
819 		break;
820 	}
821 }
822 
823 KludgeResetRule()
824 {
825 	InRule = FALSE;
826 }
827 #endif /* FIXUP_CPP_WHITESPACE */
828 
829 char *Strdup(cp)
830 	register char *cp;
831 {
832 	register char *new = Emalloc(strlen(cp) + 1);
833 
834 	strcpy(new, cp);
835 	return new;
836 }
837