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