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 | #include <unistd.h> |
---|
111 | #endif |
---|
112 | #if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE) |
---|
113 | #include <signal.h> |
---|
114 | #else |
---|
115 | #define _POSIX_SOURCE |
---|
116 | #include <signal.h> |
---|
117 | #undef _POSIX_SOURCE |
---|
118 | #endif |
---|
119 | #include <sys/stat.h> |
---|
120 | #ifndef X_NOT_POSIX |
---|
121 | #ifdef _POSIX_SOURCE |
---|
122 | #include <sys/wait.h> |
---|
123 | #else |
---|
124 | #define _POSIX_SOURCE |
---|
125 | #include <sys/wait.h> |
---|
126 | #undef _POSIX_SOURCE |
---|
127 | #endif |
---|
128 | #define waitCode(w) WEXITSTATUS(w) |
---|
129 | #define waitSig(w) WTERMSIG(w) |
---|
130 | typedef int waitType; |
---|
131 | #else /* X_NOT_POSIX */ |
---|
132 | #ifdef SYSV |
---|
133 | #define waitCode(w) (((w) >> 8) & 0x7f) |
---|
134 | #define waitSig(w) ((w) & 0xff) |
---|
135 | typedef int waitType; |
---|
136 | #else /* SYSV */ |
---|
137 | #include <sys/wait.h> |
---|
138 | #define waitCode(w) ((w).w_T.w_Retcode) |
---|
139 | #define waitSig(w) ((w).w_T.w_Termsig) |
---|
140 | typedef union wait waitType; |
---|
141 | #endif |
---|
142 | #ifndef WIFSIGNALED |
---|
143 | #define WIFSIGNALED(w) waitSig(w) |
---|
144 | #endif |
---|
145 | #ifndef WIFEXITED |
---|
146 | #define WIFEXITED(w) waitCode(w) |
---|
147 | #endif |
---|
148 | #endif /* X_NOT_POSIX */ |
---|
149 | #ifndef X_NOT_STDC_ENV |
---|
150 | #include <stdlib.h> |
---|
151 | #else |
---|
152 | char *malloc(), *realloc(); |
---|
153 | void exit(); |
---|
154 | #endif |
---|
155 | #if defined(macII) && !defined(__STDC__) /* stdlib.h fails to define these */ |
---|
156 | char *malloc(), *realloc(); |
---|
157 | #endif /* macII */ |
---|
158 | #ifdef X_NOT_STDC_ENV |
---|
159 | extern char *getenv(); |
---|
160 | #endif |
---|
161 | #include <errno.h> |
---|
162 | extern int errno; |
---|
163 | #include "imakemdep.h" |
---|
164 | |
---|
165 | |
---|
166 | #define TRUE 1 |
---|
167 | #define FALSE 0 |
---|
168 | |
---|
169 | #ifdef FIXUP_CPP_WHITESPACE |
---|
170 | int InRule = FALSE; |
---|
171 | #endif |
---|
172 | |
---|
173 | /* |
---|
174 | * Some versions of cpp reduce all tabs in macro expansion to a single |
---|
175 | * space. In addition, the escaped newline may be replaced with a |
---|
176 | * space instead of being deleted. Blech. |
---|
177 | */ |
---|
178 | #ifndef FIXUP_CPP_WHITESPACE |
---|
179 | #define KludgeOutputLine(arg) |
---|
180 | #define KludgeResetRule() |
---|
181 | #endif |
---|
182 | |
---|
183 | typedef unsigned char boolean; |
---|
184 | |
---|
185 | #ifndef DEFAULT_CPP |
---|
186 | #ifdef USE_CC_E |
---|
187 | #define DEFAULT_CPP "/bin/cc" |
---|
188 | #else |
---|
189 | #ifdef CPP_PROGRAM |
---|
190 | #define DEFAULT_CPP CPP_PROGRAM |
---|
191 | #else |
---|
192 | #define DEFAULT_CPP "/lib/cpp" |
---|
193 | #endif |
---|
194 | #endif |
---|
195 | #endif |
---|
196 | |
---|
197 | char *cpp = DEFAULT_CPP; |
---|
198 | |
---|
199 | char *tmpMakefile = "/tmp/Imf.XXXXXX"; |
---|
200 | char *tmpImakefile = "/tmp/IIf.XXXXXX"; |
---|
201 | char *make_argv[ ARGUMENTS ] = { "make" }; |
---|
202 | |
---|
203 | int make_argindex; |
---|
204 | int cpp_argindex; |
---|
205 | char *make = NULL; |
---|
206 | char *Imakefile = NULL; |
---|
207 | char *Makefile = "Makefile"; |
---|
208 | char *Template = "Imake.tmpl"; |
---|
209 | char *program; |
---|
210 | char *FindImakefile(); |
---|
211 | char *ReadLine(); |
---|
212 | char *CleanCppInput(); |
---|
213 | char *Strdup(); |
---|
214 | char *Emalloc(); |
---|
215 | |
---|
216 | boolean verbose = FALSE; |
---|
217 | boolean show = TRUE; |
---|
218 | |
---|
219 | main(argc, argv) |
---|
220 | int argc; |
---|
221 | char **argv; |
---|
222 | { |
---|
223 | FILE *tmpfd; |
---|
224 | char makeMacro[ BUFSIZ ]; |
---|
225 | char makefileMacro[ BUFSIZ ]; |
---|
226 | |
---|
227 | program = argv[0]; |
---|
228 | init(); |
---|
229 | SetOpts(argc, argv); |
---|
230 | #ifdef USE_CC_E |
---|
231 | AddCppArg("-"); |
---|
232 | #endif |
---|
233 | |
---|
234 | Imakefile = FindImakefile(Imakefile); |
---|
235 | if (Makefile) |
---|
236 | tmpMakefile = Makefile; |
---|
237 | else { |
---|
238 | tmpMakefile = Strdup(tmpMakefile); |
---|
239 | (void) mktemp(tmpMakefile); |
---|
240 | } |
---|
241 | AddMakeArg("-f"); |
---|
242 | AddMakeArg( tmpMakefile ); |
---|
243 | sprintf(makeMacro, "MAKE=%s", program); |
---|
244 | AddMakeArg( makeMacro ); |
---|
245 | sprintf(makefileMacro, "MAKEFILE=%s", Imakefile); |
---|
246 | AddMakeArg( makefileMacro ); |
---|
247 | |
---|
248 | if ((tmpfd = fopen(tmpMakefile, "w+")) == NULL) |
---|
249 | LogFatal("Cannot create temporary file %s.", tmpMakefile); |
---|
250 | |
---|
251 | cppit(Imakefile, Template, tmpfd, tmpMakefile); |
---|
252 | |
---|
253 | if (show) { |
---|
254 | if (Makefile == NULL) |
---|
255 | showit(tmpfd); |
---|
256 | } else |
---|
257 | makeit(); |
---|
258 | wrapup(); |
---|
259 | exit(0); |
---|
260 | } |
---|
261 | |
---|
262 | showit(fd) |
---|
263 | FILE *fd; |
---|
264 | { |
---|
265 | char buf[ BUFSIZ ]; |
---|
266 | int red; |
---|
267 | |
---|
268 | fseek(fd, 0, 0); |
---|
269 | while ((red = fread(buf, 1, BUFSIZ, fd)) > 0) |
---|
270 | fwrite(buf, red, 1, stdout); |
---|
271 | if (red < 0) |
---|
272 | LogFatal("Cannot write stdout.", ""); |
---|
273 | } |
---|
274 | |
---|
275 | wrapup() |
---|
276 | { |
---|
277 | if (tmpMakefile != Makefile) |
---|
278 | unlink(tmpMakefile); |
---|
279 | unlink(tmpImakefile); |
---|
280 | } |
---|
281 | |
---|
282 | #ifdef SIGNALRETURNSINT |
---|
283 | int |
---|
284 | #else |
---|
285 | void |
---|
286 | #endif |
---|
287 | catch(sig) |
---|
288 | int sig; |
---|
289 | { |
---|
290 | errno = 0; |
---|
291 | LogFatalI("Signal %d.", sig); |
---|
292 | } |
---|
293 | |
---|
294 | /* |
---|
295 | * Initialize some variables. |
---|
296 | */ |
---|
297 | init() |
---|
298 | { |
---|
299 | char *p; |
---|
300 | |
---|
301 | make_argindex=0; |
---|
302 | while (make_argv[ make_argindex ] != NULL) |
---|
303 | make_argindex++; |
---|
304 | cpp_argindex = 0; |
---|
305 | while (cpp_argv[ cpp_argindex ] != NULL) |
---|
306 | cpp_argindex++; |
---|
307 | |
---|
308 | /* |
---|
309 | * See if the standard include directory is different than |
---|
310 | * the default. Or if cpp is not the default. Or if the make |
---|
311 | * found by the PATH variable is not the default. |
---|
312 | */ |
---|
313 | if (p = getenv("IMAKEINCLUDE")) { |
---|
314 | if (*p != '-' || *(p+1) != 'I') |
---|
315 | LogFatal("Environment var IMAKEINCLUDE %s\n", |
---|
316 | "must begin with -I"); |
---|
317 | AddCppArg(p); |
---|
318 | for (; *p; p++) |
---|
319 | if (*p == ' ') { |
---|
320 | *p++ = '\0'; |
---|
321 | AddCppArg(p); |
---|
322 | } |
---|
323 | } |
---|
324 | if (p = getenv("IMAKECPP")) |
---|
325 | cpp = p; |
---|
326 | if (p = getenv("IMAKEMAKE")) |
---|
327 | make = p; |
---|
328 | |
---|
329 | if (signal(SIGINT, SIG_IGN) != SIG_IGN) |
---|
330 | signal(SIGINT, catch); |
---|
331 | } |
---|
332 | |
---|
333 | AddMakeArg(arg) |
---|
334 | char *arg; |
---|
335 | { |
---|
336 | errno = 0; |
---|
337 | if (make_argindex >= ARGUMENTS-1) |
---|
338 | LogFatal("Out of internal storage.", ""); |
---|
339 | make_argv[ make_argindex++ ] = arg; |
---|
340 | make_argv[ make_argindex ] = NULL; |
---|
341 | } |
---|
342 | |
---|
343 | AddCppArg(arg) |
---|
344 | char *arg; |
---|
345 | { |
---|
346 | errno = 0; |
---|
347 | if (cpp_argindex >= ARGUMENTS-1) |
---|
348 | LogFatal("Out of internal storage.", ""); |
---|
349 | cpp_argv[ cpp_argindex++ ] = arg; |
---|
350 | cpp_argv[ cpp_argindex ] = NULL; |
---|
351 | } |
---|
352 | |
---|
353 | SetOpts(argc, argv) |
---|
354 | int argc; |
---|
355 | char **argv; |
---|
356 | { |
---|
357 | errno = 0; |
---|
358 | /* |
---|
359 | * Now gather the arguments for make |
---|
360 | */ |
---|
361 | for(argc--, argv++; argc; argc--, argv++) { |
---|
362 | /* |
---|
363 | * We intercept these flags. |
---|
364 | */ |
---|
365 | if (argv[0][0] == '-') { |
---|
366 | if (argv[0][1] == 'D') { |
---|
367 | AddCppArg(argv[0]); |
---|
368 | } else if (argv[0][1] == 'I') { |
---|
369 | AddCppArg(argv[0]); |
---|
370 | } else if (argv[0][1] == 'f') { |
---|
371 | if (argv[0][2]) |
---|
372 | Imakefile = argv[0]+2; |
---|
373 | else { |
---|
374 | argc--, argv++; |
---|
375 | if (! argc) |
---|
376 | LogFatal("No description arg after -f flag\n", ""); |
---|
377 | Imakefile = argv[0]; |
---|
378 | } |
---|
379 | } else if (argv[0][1] == 's') { |
---|
380 | if (argv[0][2]) |
---|
381 | Makefile = ((argv[0][2] == '-') && !argv[0][3]) ? |
---|
382 | NULL : argv[0]+2; |
---|
383 | else { |
---|
384 | argc--, argv++; |
---|
385 | if (!argc) |
---|
386 | LogFatal("No description arg after -s flag\n", ""); |
---|
387 | Makefile = ((argv[0][0] == '-') && !argv[0][1]) ? |
---|
388 | NULL : argv[0]; |
---|
389 | } |
---|
390 | show = TRUE; |
---|
391 | } else if (argv[0][1] == 'e') { |
---|
392 | Makefile = (argv[0][2] ? argv[0]+2 : NULL); |
---|
393 | show = FALSE; |
---|
394 | } else if (argv[0][1] == 'T') { |
---|
395 | if (argv[0][2]) |
---|
396 | Template = argv[0]+2; |
---|
397 | else { |
---|
398 | argc--, argv++; |
---|
399 | if (! argc) |
---|
400 | LogFatal("No description arg after -T flag\n", ""); |
---|
401 | Template = argv[0]; |
---|
402 | } |
---|
403 | } else if (argv[0][1] == 'v') { |
---|
404 | verbose = TRUE; |
---|
405 | } else |
---|
406 | AddMakeArg(argv[0]); |
---|
407 | } else |
---|
408 | AddMakeArg(argv[0]); |
---|
409 | } |
---|
410 | } |
---|
411 | |
---|
412 | char *FindImakefile(Imakefile) |
---|
413 | char *Imakefile; |
---|
414 | { |
---|
415 | int fd; |
---|
416 | |
---|
417 | if (Imakefile) { |
---|
418 | if ((fd = open(Imakefile, O_RDONLY)) < 0) |
---|
419 | LogFatal("Cannot open %s.", Imakefile); |
---|
420 | } else { |
---|
421 | if ((fd = open("Imakefile", O_RDONLY)) < 0) |
---|
422 | if ((fd = open("imakefile", O_RDONLY)) < 0) |
---|
423 | LogFatal("No description file.", ""); |
---|
424 | else |
---|
425 | Imakefile = "imakefile"; |
---|
426 | else |
---|
427 | Imakefile = "Imakefile"; |
---|
428 | } |
---|
429 | close (fd); |
---|
430 | return(Imakefile); |
---|
431 | } |
---|
432 | |
---|
433 | LogFatalI(s, i) |
---|
434 | char *s; |
---|
435 | int i; |
---|
436 | { |
---|
437 | /*NOSTRICT*/ |
---|
438 | LogFatal(s, (char *)i); |
---|
439 | } |
---|
440 | |
---|
441 | LogFatal(x0,x1) |
---|
442 | char *x0, *x1; |
---|
443 | { |
---|
444 | extern char *sys_errlist[]; |
---|
445 | static boolean entered = FALSE; |
---|
446 | |
---|
447 | if (entered) |
---|
448 | return; |
---|
449 | entered = TRUE; |
---|
450 | |
---|
451 | fprintf(stderr, "%s: ", program); |
---|
452 | if (errno) |
---|
453 | fprintf(stderr, "%s: ", sys_errlist[ errno ]); |
---|
454 | fprintf(stderr, x0,x1); |
---|
455 | fprintf(stderr, " Stop.\n"); |
---|
456 | wrapup(); |
---|
457 | exit(1); |
---|
458 | } |
---|
459 | |
---|
460 | showargs(argv) |
---|
461 | char **argv; |
---|
462 | { |
---|
463 | for (; *argv; argv++) |
---|
464 | fprintf(stderr, "%s ", *argv); |
---|
465 | fprintf(stderr, "\n"); |
---|
466 | } |
---|
467 | |
---|
468 | cppit(Imakefile, template, outfd, outfname) |
---|
469 | char *Imakefile; |
---|
470 | char *template; |
---|
471 | FILE *outfd; |
---|
472 | char *outfname; |
---|
473 | { |
---|
474 | FILE *pipeFile; |
---|
475 | int pid, pipefd[2]; |
---|
476 | waitType status; |
---|
477 | char *cleanedImakefile; |
---|
478 | |
---|
479 | /* |
---|
480 | * Get a pipe. |
---|
481 | */ |
---|
482 | if (pipe(pipefd) < 0) |
---|
483 | LogFatal("Cannot make a pipe.", ""); |
---|
484 | |
---|
485 | /* |
---|
486 | * Fork and exec cpp |
---|
487 | */ |
---|
488 | pid = fork(); |
---|
489 | if (pid < 0) |
---|
490 | LogFatal("Cannot fork.", ""); |
---|
491 | if (pid) { /* parent */ |
---|
492 | close(pipefd[0]); |
---|
493 | cleanedImakefile = CleanCppInput(Imakefile); |
---|
494 | if ((pipeFile = fdopen(pipefd[1], "w")) == NULL) |
---|
495 | LogFatalI("Cannot fdopen fd %d for output.", pipefd[1]); |
---|
496 | fprintf(pipeFile, "#define IMAKE_TEMPLATE\t\"%s\"\n", |
---|
497 | template); |
---|
498 | fprintf(pipeFile, "#define INCLUDE_IMAKEFILE\t<%s>\n", |
---|
499 | cleanedImakefile); |
---|
500 | fprintf(pipeFile, "#include IMAKE_TEMPLATE\n"); |
---|
501 | fclose(pipeFile); |
---|
502 | while (wait(&status) > 0) { |
---|
503 | errno = 0; |
---|
504 | if (WIFSIGNALED(status)) |
---|
505 | LogFatalI("Signal %d.", waitSig(status)); |
---|
506 | if (WIFEXITED(status) && waitCode(status)) |
---|
507 | LogFatalI("Exit code %d.", waitCode(status)); |
---|
508 | } |
---|
509 | CleanCppOutput(outfd, outfname); |
---|
510 | } else { /* child... dup and exec cpp */ |
---|
511 | if (verbose) |
---|
512 | showargs(cpp_argv); |
---|
513 | dup2(pipefd[0], 0); |
---|
514 | dup2(fileno(outfd), 1); |
---|
515 | close(pipefd[1]); |
---|
516 | execv(cpp, cpp_argv); |
---|
517 | LogFatal("Cannot exec %s.", cpp); |
---|
518 | } |
---|
519 | } |
---|
520 | |
---|
521 | makeit() |
---|
522 | { |
---|
523 | int pid; |
---|
524 | waitType status; |
---|
525 | |
---|
526 | /* |
---|
527 | * Fork and exec make |
---|
528 | */ |
---|
529 | pid = fork(); |
---|
530 | if (pid < 0) |
---|
531 | LogFatal("Cannot fork.", ""); |
---|
532 | if (pid) { /* parent... simply wait */ |
---|
533 | while (wait(&status) > 0) { |
---|
534 | errno = 0; |
---|
535 | if (WIFSIGNALED(status)) |
---|
536 | LogFatalI("Signal %d.", waitSig(status)); |
---|
537 | if (WIFEXITED(status) && waitCode(status)) |
---|
538 | LogFatalI("Exit code %d.", waitCode(status)); |
---|
539 | } |
---|
540 | } else { /* child... dup and exec cpp */ |
---|
541 | if (verbose) |
---|
542 | showargs(make_argv); |
---|
543 | if (make) |
---|
544 | execv(make, make_argv); |
---|
545 | else |
---|
546 | execvp("make", make_argv); |
---|
547 | LogFatal("Cannot exec %s.", make); |
---|
548 | } |
---|
549 | } |
---|
550 | |
---|
551 | char *CleanCppInput(Imakefile) |
---|
552 | char *Imakefile; |
---|
553 | { |
---|
554 | FILE *outFile = NULL; |
---|
555 | int infd; |
---|
556 | char *buf, /* buffer for file content */ |
---|
557 | *pbuf, /* walking pointer to buf */ |
---|
558 | *punwritten, /* pointer to unwritten portion of buf */ |
---|
559 | *cleanedImakefile = Imakefile, /* return value */ |
---|
560 | *ptoken, /* pointer to # token */ |
---|
561 | *pend, /* pointer to end of # token */ |
---|
562 | savec; /* temporary character holder */ |
---|
563 | struct stat st; |
---|
564 | |
---|
565 | /* |
---|
566 | * grab the entire file. |
---|
567 | */ |
---|
568 | if ((infd = open(Imakefile, O_RDONLY)) < 0) |
---|
569 | LogFatal("Cannot open %s for input.", Imakefile); |
---|
570 | fstat(infd, &st); |
---|
571 | buf = Emalloc(st.st_size+1); |
---|
572 | if (read(infd, buf, st.st_size) != st.st_size) |
---|
573 | LogFatal("Cannot read all of %s:", Imakefile); |
---|
574 | close(infd); |
---|
575 | buf[ st.st_size ] = '\0'; |
---|
576 | |
---|
577 | punwritten = pbuf = buf; |
---|
578 | while (*pbuf) { |
---|
579 | /* pad make comments for cpp */ |
---|
580 | if (*pbuf == '#' && (pbuf == buf || pbuf[-1] == '\n')) { |
---|
581 | |
---|
582 | ptoken = pbuf+1; |
---|
583 | while (*ptoken == ' ' || *ptoken == '\t') |
---|
584 | ptoken++; |
---|
585 | pend = ptoken; |
---|
586 | while (*pend && *pend != ' ' && *pend != '\t' && *pend != '\n') |
---|
587 | pend++; |
---|
588 | savec = *pend; |
---|
589 | *pend = '\0'; |
---|
590 | if (strcmp(ptoken, "include") |
---|
591 | && strcmp(ptoken, "define") |
---|
592 | && strcmp(ptoken, "undef") |
---|
593 | && strcmp(ptoken, "ifdef") |
---|
594 | && strcmp(ptoken, "ifndef") |
---|
595 | && strcmp(ptoken, "else") |
---|
596 | && strcmp(ptoken, "endif") |
---|
597 | && strcmp(ptoken, "if")) { |
---|
598 | if (outFile == NULL) { |
---|
599 | tmpImakefile = Strdup(tmpImakefile); |
---|
600 | (void) mktemp(tmpImakefile); |
---|
601 | cleanedImakefile = tmpImakefile; |
---|
602 | outFile = fopen(tmpImakefile, "w"); |
---|
603 | if (outFile == NULL) |
---|
604 | LogFatal("Cannot open %s for write.\n", |
---|
605 | tmpImakefile); |
---|
606 | } |
---|
607 | fwrite(punwritten, sizeof(char), pbuf-punwritten, outFile); |
---|
608 | fputs("/**/", outFile); |
---|
609 | punwritten = pbuf; |
---|
610 | } |
---|
611 | *pend = savec; |
---|
612 | } |
---|
613 | pbuf++; |
---|
614 | } |
---|
615 | if (outFile) { |
---|
616 | fwrite(punwritten, sizeof(char), pbuf-punwritten, outFile); |
---|
617 | fclose(outFile); /* also closes the pipe */ |
---|
618 | } |
---|
619 | |
---|
620 | return(cleanedImakefile); |
---|
621 | } |
---|
622 | |
---|
623 | CleanCppOutput(tmpfd, tmpfname) |
---|
624 | FILE *tmpfd; |
---|
625 | char *tmpfname; |
---|
626 | { |
---|
627 | char *input; |
---|
628 | int blankline = 0; |
---|
629 | |
---|
630 | while(input = ReadLine(tmpfd, tmpfname)) { |
---|
631 | if (isempty(input)) { |
---|
632 | if (blankline++) |
---|
633 | continue; |
---|
634 | KludgeResetRule(); |
---|
635 | } else { |
---|
636 | blankline = 0; |
---|
637 | KludgeOutputLine(&input); |
---|
638 | fputs(input, tmpfd); |
---|
639 | } |
---|
640 | putc('\n', tmpfd); |
---|
641 | } |
---|
642 | fflush(tmpfd); |
---|
643 | #ifdef NFS_STDOUT_BUG |
---|
644 | /* |
---|
645 | * On some systems, NFS seems to leave a large number of nulls at |
---|
646 | * the end of the file. Ralph Swick says that this kludge makes the |
---|
647 | * problem go away. |
---|
648 | */ |
---|
649 | ftruncate (fileno(tmpfd), (off_t)ftell(tmpfd)); |
---|
650 | #endif |
---|
651 | } |
---|
652 | |
---|
653 | /* |
---|
654 | * Determine of a line has nothing in it. As a side effect, we trim white |
---|
655 | * space from the end of the line. Cpp magic cookies are also thrown away. |
---|
656 | */ |
---|
657 | isempty(line) |
---|
658 | char *line; |
---|
659 | { |
---|
660 | char *pend; |
---|
661 | |
---|
662 | /* |
---|
663 | * Check for lines of the form |
---|
664 | * # n "... |
---|
665 | * or |
---|
666 | * # line n "... |
---|
667 | */ |
---|
668 | if (*line == '#') { |
---|
669 | pend = line+1; |
---|
670 | if (*pend == ' ') |
---|
671 | pend++; |
---|
672 | if (strncmp(pend, "line ", 5) == 0) |
---|
673 | pend += 5; |
---|
674 | if (isdigit(*pend)) { |
---|
675 | while (isdigit(*pend)) |
---|
676 | pend++; |
---|
677 | if (*pend++ == ' ' && *pend == '"') |
---|
678 | return(TRUE); |
---|
679 | } |
---|
680 | } |
---|
681 | |
---|
682 | /* |
---|
683 | * Find the end of the line and then walk back. |
---|
684 | */ |
---|
685 | for (pend=line; *pend; pend++) ; |
---|
686 | |
---|
687 | pend--; |
---|
688 | while (pend >= line && (*pend == ' ' || *pend == '\t')) |
---|
689 | pend--; |
---|
690 | *++pend = '\0'; |
---|
691 | return (*line == '\0'); |
---|
692 | } |
---|
693 | |
---|
694 | /*ARGSUSED*/ |
---|
695 | char *ReadLine(tmpfd, tmpfname) |
---|
696 | FILE *tmpfd; |
---|
697 | char *tmpfname; |
---|
698 | { |
---|
699 | static boolean initialized = FALSE; |
---|
700 | static char *buf, *pline, *end; |
---|
701 | char *p1, *p2; |
---|
702 | |
---|
703 | if (! initialized) { |
---|
704 | int total_red; |
---|
705 | struct stat st; |
---|
706 | |
---|
707 | /* |
---|
708 | * Slurp it all up. |
---|
709 | */ |
---|
710 | fseek(tmpfd, 0, 0); |
---|
711 | fstat(fileno(tmpfd), &st); |
---|
712 | pline = buf = Emalloc(st.st_size+1); |
---|
713 | total_red = read(fileno(tmpfd), buf, st.st_size); |
---|
714 | if (total_red != st.st_size) |
---|
715 | LogFatal("cannot read %s\n", tmpMakefile); |
---|
716 | end = buf + st.st_size; |
---|
717 | *end = '\0'; |
---|
718 | lseek(fileno(tmpfd), 0, 0); |
---|
719 | #ifdef SYSV |
---|
720 | freopen(tmpfname, "w+", tmpfd); |
---|
721 | #else /* !SYSV */ |
---|
722 | ftruncate(fileno(tmpfd), 0); |
---|
723 | #endif /* !SYSV */ |
---|
724 | initialized = TRUE; |
---|
725 | fprintf (tmpfd, "# Makefile generated by imake - do not edit!\n"); |
---|
726 | fprintf (tmpfd, "# %s\n", |
---|
727 | "$XConsortium: imake.c,v 1.65 91/07/25 17:50:17 rws Exp $"); |
---|
728 | |
---|
729 | #ifdef FIXUP_CPP_WHITESPACE |
---|
730 | { |
---|
731 | static char *cpp_warning[] = { |
---|
732 | "#", |
---|
733 | "# The cpp used on this machine replaces all newlines and multiple tabs and", |
---|
734 | "# spaces in a macro expansion with a single space. Imake tries to compensate", |
---|
735 | "# for this, but is not always successful.", |
---|
736 | "#", |
---|
737 | NULL }; |
---|
738 | char **cpp; |
---|
739 | |
---|
740 | for (cpp = cpp_warning; *cpp; cpp++) { |
---|
741 | fprintf (tmpfd, "%s\n", *cpp); |
---|
742 | } |
---|
743 | } |
---|
744 | #endif /* FIXUP_CPP_WHITESPACE */ |
---|
745 | } |
---|
746 | |
---|
747 | for (p1 = pline; p1 < end; p1++) { |
---|
748 | if (*p1 == '@' && *(p1+1) == '@') { /* soft EOL */ |
---|
749 | *p1++ = '\0'; |
---|
750 | p1++; /* skip over second @ */ |
---|
751 | break; |
---|
752 | } |
---|
753 | else if (*p1 == '\n') { /* real EOL */ |
---|
754 | *p1++ = '\0'; |
---|
755 | break; |
---|
756 | } |
---|
757 | } |
---|
758 | |
---|
759 | /* |
---|
760 | * return NULL at the end of the file. |
---|
761 | */ |
---|
762 | p2 = (pline == p1 ? NULL : pline); |
---|
763 | pline = p1; |
---|
764 | return(p2); |
---|
765 | } |
---|
766 | |
---|
767 | writetmpfile(fd, buf, cnt) |
---|
768 | FILE *fd; |
---|
769 | int cnt; |
---|
770 | char *buf; |
---|
771 | { |
---|
772 | errno = 0; |
---|
773 | if (fwrite(buf, cnt, 1, fd) != 1) |
---|
774 | LogFatal("Cannot write to %s.", tmpMakefile); |
---|
775 | } |
---|
776 | |
---|
777 | char *Emalloc(size) |
---|
778 | int size; |
---|
779 | { |
---|
780 | char *p; |
---|
781 | |
---|
782 | if ((p = malloc(size)) == NULL) |
---|
783 | LogFatalI("Cannot allocate %d bytes\n", size); |
---|
784 | return(p); |
---|
785 | } |
---|
786 | |
---|
787 | #ifdef FIXUP_CPP_WHITESPACE |
---|
788 | KludgeOutputLine(pline) |
---|
789 | char **pline; |
---|
790 | { |
---|
791 | char *p = *pline; |
---|
792 | |
---|
793 | switch (*p) { |
---|
794 | case '#': /*Comment - ignore*/ |
---|
795 | break; |
---|
796 | case '\t': /*Already tabbed - ignore it*/ |
---|
797 | break; |
---|
798 | case ' ': /*May need a tab*/ |
---|
799 | default: |
---|
800 | for (; *p; p++) if (p[0] == ':' && |
---|
801 | p > *pline && p[-1] != '\\') { |
---|
802 | if (**pline == ' ') |
---|
803 | (*pline)++; |
---|
804 | InRule = TRUE; |
---|
805 | break; |
---|
806 | } |
---|
807 | if (InRule && **pline == ' ') |
---|
808 | **pline = '\t'; |
---|
809 | break; |
---|
810 | } |
---|
811 | } |
---|
812 | |
---|
813 | KludgeResetRule() |
---|
814 | { |
---|
815 | InRule = FALSE; |
---|
816 | } |
---|
817 | #endif /* FIXUP_CPP_WHITESPACE */ |
---|
818 | |
---|
819 | char *Strdup(cp) |
---|
820 | register char *cp; |
---|
821 | { |
---|
822 | register char *new = Emalloc(strlen(cp) + 1); |
---|
823 | |
---|
824 | strcpy(new, cp); |
---|
825 | return new; |
---|
826 | } |
---|