[12414] | 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 | } |
---|