diff options
Diffstat (limited to 'imake.c')
-rw-r--r-- | imake.c | 2214 |
1 files changed, 2214 insertions, 0 deletions
@@ -0,0 +1,2214 @@ + +/*************************************************************************** + * * + * Porting Note * + * * + * Add the value of BOOTSTRAPCFLAGS to the cpp_argv table so that it will * + * be passed to the template file. * + * * + ***************************************************************************/ +/* $XFree86: xc/config/imake/imake.c,v 3.63tsi Exp $ */ + +/* + * +Copyright (c) 1985, 1986, 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + * + * Original Author: + * Todd Brunhoff + * Tektronix, inc. + * While a guest engineer at Project Athena, MIT + * + * imake: the include-make program. + * + * Usage: imake [-Idir] [-Ddefine] [-T template] [-f imakefile ] [-C Imakefile.c ] [-s] [-e] [-v] [make flags] + * + * Imake takes a template file (Imake.tmpl) and a prototype (Imakefile) + * and runs cpp on them producing a Makefile. It then optionally runs make + * on the Makefile. + * Options: + * -D define. Same as cpp -D argument. + * -U undefine. Same as cpp -U argument. + * -W warning. Same as cpp -W argument. + * -I Include directory. Same as cpp -I argument. + * -T template. Designate a template other + * than Imake.tmpl + * -f specify the Imakefile file + * -C specify the name to use instead of Imakefile.c + * -s[F] show. Show the produced makefile on the standard + * output. Make is not run is this case. If a file + * argument is provided, the output is placed there. + * -e[F] execute instead of show; optionally name Makefile F + * -v verbose. Show the make command line executed. + * + * Environment variables: + * + * IMAKEINCLUDE Include directory to use in addition to "." + * IMAKECPP Cpp to use instead of /lib/cpp + * IMAKEMAKE make program to use other than what is + * found by searching the $PATH variable. + * Other features: + * imake reads the entire cpp output into memory and then scans it + * for occurences of "@@". If it encounters them, it replaces it with + * a newline. It also trims any trailing white space on output lines + * (because make gets upset at them). This helps when cpp expands + * multi-line macros but you want them to appear on multiple lines. + * It also changes occurences of "XCOMM" to "#", to avoid problems + * with treating commands as invalid preprocessor commands. + * + * The macros MAKEFILE and MAKE are provided as macros + * to make. MAKEFILE is set to imake's makefile (not the constructed, + * preprocessed one) and MAKE is set to argv[0], i.e. the name of + * the imake program. + * + * Theory of operation: + * 1. Determine the name of the imakefile from the command line (-f) + * or from the content of the current directory (Imakefile or imakefile). + * Call this <imakefile>. This gets added to the arguments for + * make as MAKEFILE=<imakefile>. + * 2. Determine the name of the template from the command line (-T) + * or the default, Imake.tmpl. Call this <template> + * 3. Determine the name of the imakeCfile from the command line (-C) + * or the default, Imakefile.c. Call this <imakeCfile> + * 4. Store lines of input into <imakeCfile>: + * - A c-style comment header (see ImakefileCHeader below), used + * to recognize temporary files generated by imake. + * - If DEFAULT_OS_NAME is defined, format the utsname struct and + * call the result <defaultOsName>. Add: + * #define DefaultOSName <defaultOsName> + * - If DEFAULT_OS_MAJOR_REV is defined, format the utsname struct + * and call the result <defaultOsMajorVersion>. Add: + * #define DefaultOSMajorVersion <defaultOsMajorVersion> + * - If DEFAULT_OS_MINOR_REV is defined, format the utsname struct + * and call the result <defaultOsMinorVersion>. Add: + * #define DefaultOSMinorVersion <defaultOsMinorVersion> + * - If DEFAULT_OS_TEENY_REV is defined, format the utsname struct + * and call the result <defaultOsTeenyVersion>. Add: + * #define DefaultOSTeenyVersion <defaultOsTeenyVersion> + * - If DEFAULT_MACHINE_ARCITECTURE is defined, format the utsname struct + * and define the corresponding macro. (For example on the amiga, + * this will define amiga in addition to m68k). + * - If the file "localdefines" is readable in the current + * directory, print a warning message to stderr and add: + * #define IMAKE_LOCAL_DEFINES "localdefines" + * #include IMAKE_LOCAL_DEFINES + * - If the file "admindefines" is readable in the current + * directory, print a warning message to stderr and add: + * #define IMAKE_ADMIN_DEFINES "admindefines" + * #include IMAKE_ADMIN_DEFINES + * - The following lines: + * #define INCLUDE_IMAKEFILE < <imakefile> > + * #define IMAKE_TEMPLATE " <template> " + * #include IMAKE_TEMPLATE + * - If the file "adminmacros" is readable in the current + * directory, print a warning message to stderr and add: + * #define IMAKE_ADMIN_MACROS "adminmacros" + * #include IMAKE_ADMIN_MACROS + * - If the file "localmacros" is readable in the current + * directory, print a warning message to stderr and add: + * #define IMAKE_LOCAL_MACROS "localmacros" + * #include IMAKE_LOCAL_MACROS + * 5. Start up cpp and provide it with this file. + * Note that the define for INCLUDE_IMAKEFILE is intended for + * use in the template file. This implies that the imake is + * useless unless the template file contains at least the line + * #include INCLUDE_IMAKEFILE + * 6. Gather the output from cpp, and clean it up, expanding @@ to + * newlines, stripping trailing white space, cpp control lines, + * and extra blank lines, and changing XCOMM to #. This cleaned + * output is placed in a new file, default "Makefile", but can + * be specified with -s or -e options. + * 7. Optionally start up make on the resulting file. + * + * The design of the template makefile should therefore be: + * <set global macros like CFLAGS, etc.> + * <include machine dependent additions> + * #include INCLUDE_IMAKEFILE + * <add any global targets like 'clean' and long dependencies> + */ +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) +/* This needs to be before _POSIX_SOURCE gets defined */ +# include <sys/param.h> +# include <sys/types.h> +# include <sys/sysctl.h> +#endif +#include <stdlib.h> +#include <stdio.h> +#ifdef MONOLITH +# include "Xosdefs.h" +#else +# include <X11/Xosdefs.h> +#endif +#include <string.h> +#include <ctype.h> +#ifdef WIN32 +# include "Xw32defs.h" +#endif +#if 0 +#ifndef X_NOT_POSIX +# ifndef _POSIX_SOURCE +# define _POSIX_SOURCE +# endif +#endif +#endif +#include <sys/types.h> +#include <fcntl.h> +#ifdef X_NOT_POSIX +# ifndef WIN32 +# include <sys/file.h> +# endif +#else +# include <unistd.h> +#endif +#ifdef ISC +# include <unistd.h> +#endif +#if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE) +# include <signal.h> +#else +# define _POSIX_SOURCE +# include <signal.h> +# undef _POSIX_SOURCE +#endif +#if !defined(SIGCHLD) && defined(SIGCLD) +# define SIGCHLD SIGCLD +#endif +#include <sys/stat.h> +#ifndef X_NOT_POSIX +# ifdef _POSIX_SOURCE +# ifdef __SCO__ +# include <sys/procset.h> +# include <sys/siginfo.h> +# endif +# include <sys/wait.h> +# else +# define _POSIX_SOURCE +# include <sys/wait.h> +# undef _POSIX_SOURCE +# endif +# define waitCode(w) WEXITSTATUS(w) +# define waitSig(w) WTERMSIG(w) +typedef int waitType; +#else /* X_NOT_POSIX */ +# ifdef SYSV +# define waitCode(w) (((w) >> 8) & 0x7f) +# define waitSig(w) ((w) & 0xff) +typedef int waitType; +# else /* SYSV */ +# ifdef WIN32 +# include <process.h> +typedef int waitType; +# else +# include <sys/wait.h> +# define waitCode(w) ((w).w_T.w_Retcode) +# define waitSig(w) ((w).w_T.w_Termsig) +typedef union wait waitType; +# endif +# endif +# ifndef WIFSIGNALED +# define WIFSIGNALED(w) waitSig(w) +# endif +# ifndef WIFEXITED +# define WIFEXITED(w) waitCode(w) +# endif +#endif /* X_NOT_POSIX */ +# include <stdlib.h> +#if defined(macII) && !defined(__STDC__) /* stdlib.h fails to define these */ +char *malloc(), *realloc(); +#endif /* macII */ +#include <errno.h> +#ifdef __minix_vmd +#define USE_FREOPEN 1 +#endif + +#if !((defined(sun) && !defined(SVR4)) || defined(macII)) +#define USE_STRERROR 1 +#endif +#ifndef WIN32 +#include <sys/utsname.h> +#else +#include <windows.h> +#endif +#ifndef SYS_NMLN +# ifdef _SYS_NMLN +# define SYS_NMLN _SYS_NMLN +# else +# define SYS_NMLN 257 +# endif +#endif +#if defined(linux) || defined(__GNU__) || defined(__GLIBC__) +#include <limits.h> +#include <stdio.h> +#endif +#ifdef __QNX__ +#include <unix.h> +#endif + +/* + * This define of strerror is copied from (and should be identical to) + * Xos.h, which we don't want to include here for bootstrapping reasons. + */ +#ifndef USE_STRERROR +# ifndef strerror +extern char *sys_errlist[]; +extern int sys_nerr; +# define strerror(n) \ + (((n) >= 0 && (n) < sys_nerr) ? sys_errlist[n] : "unknown error") +# endif +#endif + +#if defined(__NetBSD__) /* see code clock in init() below */ +#include <sys/utsname.h> +#endif + +#if !(defined(Lynx) || defined(__Lynx__) || (defined(SVR4) && !defined(sun))) && !defined (__CYGWIN__) +#define HAS_MKSTEMP +#endif + +typedef unsigned char boolean; +#define TRUE 1 +#define FALSE 0 + +# include "imakemdep.h" +#ifdef CROSSCOMPILE +# include "imakemdep_cpp.h" +#endif + +#if defined CROSSCOMPILE || defined FIXUP_CPP_WHITESPACE +int InRule = FALSE; +#endif +#if defined CROSSCOMPILE || defined INLINE_SYNTAX +int InInline = 0; +#endif +#if defined CROSSCOMPILE || defined MAGIC_MAKE_VARS +int xvariable = 0; +int xvariables[10]; +#endif + +#ifndef PATH_MAX +#define PATH_MAX 1024 +#endif + +/* + * Some versions of cpp reduce all tabs in macro expansion to a single + * space. In addition, the escaped newline may be replaced with a + * space instead of being deleted. Blech. + */ +void KludgeOutputLine(char **), KludgeResetRule(void); + +#ifndef CROSSCOMPILE +# ifdef USE_CC_E +# ifndef DEFAULT_CC +# define DEFAULT_CC "cc" +# endif +# else +# ifndef DEFAULT_CPP +# ifdef CPP_PROGRAM +# define DEFAULT_CPP CPP_PROGRAM +# else +# define DEFAULT_CPP "/lib/cpp" +# endif +# endif +# endif +#endif + +char *cpp = NULL; + +char *tmpMakefile = "/tmp/Imf.XXXXXX"; +char *tmpImakefile = "/tmp/IIf.XXXXXX"; +char *make_argv[ ARGUMENTS ] = { +#ifdef WIN32 + "nmake" +#else + "make" +#endif +}; + +int make_argindex; +int cpp_argindex; +char *Imakefile = NULL; +char *Makefile = "Makefile"; +char *Template = "Imake.tmpl"; +char *ImakefileC = "Imakefile.c"; +boolean haveImakefileC = FALSE; +char *cleanedImakefile = NULL; +char *program; +char *FindImakefile(char *Imakefile); +char *ReadLine(FILE *tmpfd, char *tmpfname); +char *CleanCppInput(char *imakefile); +char *Strdup(char *cp); +char *Emalloc(int size); +void LogFatalI(char *s, int i), LogFatal(char *x0, char *x1), + LogMsg(char *x0, char *x1); + +void showit(FILE *fd); +void wrapup(void); +void init(void); +void AddMakeArg(char *arg); +void AddCppArg(char *arg); +#ifdef CROSSCOMPILE +char *CrossCompileCPP(void); +#endif +void SetOpts(int argc, char **argv); +void CheckImakefileC(char *masterc); +void cppit(char *imakefile, char *template, char *masterc, + FILE *outfd, char *outfname); +void makeit(void); +void CleanCppOutput(FILE *tmpfd, char *tmpfname); +boolean isempty(char *line); +void writetmpfile(FILE *fd, char *buf, int cnt, char *fname); +#ifdef SIGNALRETURNSINT +int catch(int sig); +#else +void catch(int sig); +#endif +void showargs(char **argv); +boolean optional_include(FILE *inFile, char *defsym, char *fname); +void doit(FILE *outfd, char *cmd, char **argv); +boolean define_os_defaults(FILE *inFile); +#ifdef CROSSCOMPILE +static void get_cross_compile_dir(FILE *inFile); +#endif +#ifdef CROSSCOMPILEDIR +char *CrossCompileDir = CROSSCOMPILEDIR; +#else +char *CrossCompileDir = ""; +#endif +boolean CrossCompiling = FALSE; + + + +boolean verbose = FALSE; +boolean show = TRUE; + +int +main(int argc, char *argv[]) +{ + FILE *tmpfd = NULL; + char makeMacro[ BUFSIZ ]; + char makefileMacro[ BUFSIZ ]; + int lenCrossCompileDir = 0; + + program = argv[0]; + init(); + + lenCrossCompileDir = strlen(CrossCompileDir); + if (lenCrossCompileDir) { + if (lenCrossCompileDir > (PATH_MAX - 20)) + LogFatal("Cross compile directory path too long %s\n", + CrossCompileDir); + else + CrossCompiling = TRUE; + } + + SetOpts(argc, argv); + Imakefile = FindImakefile(Imakefile); + CheckImakefileC(ImakefileC); + if (Makefile) { + tmpMakefile = Makefile; + if ((tmpfd = fopen(tmpMakefile, "w+")) == NULL) + LogFatal("Cannot create temporary file %s.", tmpMakefile); + } else { +#ifdef HAS_MKSTEMP + int fd; +#endif + tmpMakefile = Strdup(tmpMakefile); +#ifndef HAS_MKSTEMP + if (mktemp(tmpMakefile) == NULL || + (tmpfd = fopen(tmpMakefile, "w+")) == NULL) { + LogFatal("Cannot create temporary file %s.", tmpMakefile); + } +#else + fd = mkstemp(tmpMakefile); + if (fd == -1 || (tmpfd = fdopen(fd, "w+")) == NULL) { + if (fd != -1) { + unlink(tmpMakefile); close(fd); + } + LogFatal("Cannot create temporary file %s.", tmpMakefile); + } +#endif + } + AddMakeArg("-f"); + AddMakeArg( tmpMakefile ); + sprintf(makeMacro, "MAKE=%s", program); + AddMakeArg( makeMacro ); + sprintf(makefileMacro, "MAKEFILE=%s", Imakefile); + AddMakeArg( makefileMacro ); + + cleanedImakefile = CleanCppInput(Imakefile); + cppit(cleanedImakefile, Template, ImakefileC, tmpfd, tmpMakefile); + + if (show) { + if (Makefile == NULL) + showit(tmpfd); + } else + makeit(); + wrapup(); + exit(0); +} + +void +showit(FILE *fd) +{ + char buf[ BUFSIZ ]; + int red; + + fseek(fd, 0, 0); + while ((red = fread(buf, 1, BUFSIZ, fd)) > 0) + writetmpfile(stdout, buf, red, "stdout"); + if (red < 0) + LogFatal("Cannot read %s.", tmpMakefile); +} + +void +wrapup(void) +{ + if (tmpMakefile != Makefile) + unlink(tmpMakefile); + if (cleanedImakefile && cleanedImakefile != Imakefile) + unlink(cleanedImakefile); + if (haveImakefileC) + unlink(ImakefileC); +} + +#ifdef SIGNALRETURNSINT +int +#else +void +#endif +catch(int sig) +{ + errno = 0; + LogFatalI("Signal %d.", sig); +} + +/* + * Initialize some variables. + */ +void +init(void) +{ + register char *p; + + make_argindex=0; + while (make_argv[ make_argindex ] != NULL) + make_argindex++; + cpp_argindex = 0; + while (cpp_argv[ cpp_argindex ] != NULL) + cpp_argindex++; + +#if defined CROSSCOMPILE + if (sys == netBSD) + if (CrossCompiling) { + LogFatal("fix imake to do crosscompiling for NetBSD\n",""); + } else +#endif +#if defined(__NetBSD__) || defined CROSSCOMPILE + { + struct utsname uts; + static char argument[512]; + + /* + * Sharable imake configurations require a + * machine identifier. + */ + if (uname(&uts) != 0) + LogFatal("uname(3) failed; can't tell what %s", + "kind of machine you have."); + + memset(argument, 0, sizeof(argument)); + (void)snprintf(argument, sizeof(argument) - 1, + "-D__%s__", uts.machine); + + AddCppArg(argument); + } +#endif /* __NetBSD__ */ + + /* + * See if the standard include directory is different than + * the default. Or if cpp is not the default. Or if the make + * found by the PATH variable is not the default. + */ + if ((p = getenv("IMAKEINCLUDE"))) { + if (*p != '-' || *(p+1) != 'I') + LogFatal("Environment var IMAKEINCLUDE %s", + "must begin with -I"); + AddCppArg(p); + for (; *p; p++) + if (*p == ' ') { + *p++ = '\0'; + AddCppArg(p); + } + } + if ((p = getenv("IMAKECPP"))) + cpp = p; + if ((p = getenv("IMAKEMAKE"))) + make_argv[0] = p; + + if (signal(SIGINT, SIG_IGN) != SIG_IGN) + signal(SIGINT, catch); +#ifdef SIGCHLD + signal(SIGCHLD, SIG_DFL); +#endif +} + +void +AddMakeArg(char *arg) +{ + errno = 0; + if (make_argindex >= ARGUMENTS-1) + LogFatal("Out of internal storage.", ""); + make_argv[ make_argindex++ ] = arg; + make_argv[ make_argindex ] = NULL; +} + +void +AddCppArg(char *arg) +{ + errno = 0; + if (cpp_argindex >= ARGUMENTS-1) + LogFatal("Out of internal storage.", ""); + cpp_argv[ cpp_argindex++ ] = arg; + cpp_argv[ cpp_argindex ] = NULL; +} + +void +SetOpts(int argc, char **argv) +{ + + errno = 0; + /* + * Now gather the arguments for make + */ + for(argc--, argv++; argc; argc--, argv++) { + /* + * We intercept these flags. + */ + if (argv[0][0] == '-') { + if (argv[0][1] == 'D') { + AddCppArg(argv[0]); + } else if (argv[0][1] == 'I') { + AddCppArg(argv[0]); + } else if (argv[0][1] == 'U') { + AddCppArg(argv[0]); + } else if (argv[0][1] == 'W') { + AddCppArg(argv[0]); + } else if (argv[0][1] == 'f') { + if (argv[0][2]) + Imakefile = argv[0]+2; + else { + argc--, argv++; + if (! argc) + LogFatal("No description arg after -f flag", ""); + Imakefile = argv[0]; + } + } else if (argv[0][1] == 's') { + if (argv[0][2]) + Makefile = ((argv[0][2] == '-') && !argv[0][3]) ? + NULL : argv[0]+2; + else { + argc--, argv++; + if (!argc) + LogFatal("No description arg after -s flag", ""); + Makefile = ((argv[0][0] == '-') && !argv[0][1]) ? + NULL : argv[0]; + } + show = TRUE; + } else if (argv[0][1] == 'e') { + Makefile = (argv[0][2] ? argv[0]+2 : NULL); + show = FALSE; + } else if (argv[0][1] == 'T') { + if (argv[0][2]) + Template = argv[0]+2; + else { + argc--, argv++; + if (! argc) + LogFatal("No description arg after -T flag", ""); + Template = argv[0]; + } + } else if (argv[0][1] == 'C') { + if (argv[0][2]) + ImakefileC = argv[0]+2; + else { + argc--, argv++; + if (! argc) + LogFatal("No imakeCfile arg after -C flag", ""); + ImakefileC = argv[0]; + } + } else if (argv[0][1] == 'v') { + verbose = TRUE; + } else + AddMakeArg(argv[0]); + } else + AddMakeArg(argv[0]); + } + +#ifndef CROSSCOMPILE +# ifdef USE_CC_E + if (!cpp) + { + AddCppArg("-E"); +#ifdef __GNUC__ + if (verbose) + AddCppArg("-v"); +#endif + cpp = DEFAULT_CC; + } +# else + if (!cpp) + cpp = DEFAULT_CPP; +# endif +#else + if (!cpp) + cpp = CrossCompileCPP(); +#endif + + cpp_argv[0] = cpp; + AddCppArg(ImakefileC); +} + +char * +FindImakefile(char *Imakefile) +{ + if (Imakefile) { + if (access(Imakefile, R_OK) < 0) + LogFatal("Cannot find %s.", Imakefile); + } else { + if (access("Imakefile", R_OK) < 0) { + if (access("imakefile", R_OK) < 0) + LogFatal("No description file.", ""); + else + Imakefile = "imakefile"; + } else + Imakefile = "Imakefile"; + } + return(Imakefile); +} + +void +LogFatalI(char *s, int i) +{ + /*NOSTRICT*/ + LogFatal(s, (char *)(long)i); +} + +void +LogFatal(char *x0, char *x1) +{ + static boolean entered = FALSE; + + if (entered) + return; + entered = TRUE; + + LogMsg(x0, x1); + fprintf(stderr, " Stop.\n"); + wrapup(); + exit(1); +} + +void +LogMsg(char *x0, char *x1) +{ + int error_number = errno; + + if (error_number) { + fprintf(stderr, "%s: ", program); + fprintf(stderr, "%s\n", strerror(error_number)); + } + fprintf(stderr, "%s: ", program); + fprintf(stderr, x0, x1); + fprintf(stderr, "\n"); +} + +void +showargs(char **argv) +{ + for (; *argv; argv++) + fprintf(stderr, "%s ", *argv); + fprintf(stderr, "\n"); +} + +#define ImakefileCHeader "/* imake - temporary file */" + +void +CheckImakefileC(char *masterc) +{ + char mkcbuf[1024]; + FILE *inFile; + + if (access(masterc, F_OK) == 0) { + inFile = fopen(masterc, "r"); + if (inFile == NULL) + LogFatal("Refuse to overwrite: %s", masterc); + if ((fgets(mkcbuf, sizeof(mkcbuf), inFile) && + strncmp(mkcbuf, ImakefileCHeader, + sizeof(ImakefileCHeader)-1))) + { + fclose(inFile); + LogFatal("Refuse to overwrite: %s", masterc); + } + fclose(inFile); + } +} + +#define LocalDefineFmt "#define %s \"%s\"\n" +#define IncludeFmt "#include %s\n" +#define ImakeDefSym "INCLUDE_IMAKEFILE" +#define ImakeTmplSym "IMAKE_TEMPLATE" +#define OverrideWarning "Warning: local file \"%s\" overrides global macros." + +boolean +optional_include(FILE *inFile, char *defsym, char *fname) +{ + errno = 0; + if (access(fname, R_OK) == 0) { + LogMsg(OverrideWarning, fname); + return (fprintf(inFile, LocalDefineFmt, defsym, fname) < 0 || + fprintf(inFile, IncludeFmt, defsym) < 0); + } + return FALSE; +} + +void +doit(FILE *outfd, char *cmd, char **argv) +{ + int pid; + waitType status; + + /* + * Fork and exec the command. + */ +#ifdef WIN32 + if (outfd) + dup2(fileno(outfd), 1); + status = _spawnvp(_P_WAIT, cmd, argv); + if (status < 0) + LogFatal("Cannot spawn %s.", cmd); + if (status > 0) + LogFatalI("Exit code %d.", status); +#else + pid = fork(); + if (pid < 0) + LogFatal("Cannot fork.", ""); + if (pid) { /* parent... simply wait */ + while (wait(&status) > 0) { + errno = 0; + if (WIFSIGNALED(status)) + LogFatalI("Signal %d.", waitSig(status)); + if (WIFEXITED(status) && waitCode(status)) + LogFatalI("Exit code %d.", waitCode(status)); + } + } + else { /* child... dup and exec cmd */ + if (verbose) + showargs(argv); + if (outfd) + dup2(fileno(outfd), 1); + execvp(cmd, argv); + LogFatal("Cannot exec %s.", cmd); + } +#endif +} + +#if !defined WIN32 +static void +parse_utsname(struct utsname *name, char *fmt, char *result, char *msg) +{ + char buf[SYS_NMLN * 5 + 1]; + char *ptr = buf; + int arg; + + if (!name) + LogFatal(msg,fmt); + + /* Assemble all the pieces into a buffer. */ + for (arg = 0; fmt[arg] != ' '; arg++) + { + /* Our buffer is only guaranteed to hold 5 arguments. */ + if (arg >= 5) + LogFatal(msg, fmt); + + switch (fmt[arg]) + { + case 's': + if (arg > 0) + *ptr++ = ' '; + strcpy(ptr, name->sysname); + ptr += strlen(ptr); + break; + + case 'n': + if (arg > 0) + *ptr++ = ' '; + strcpy(ptr, name->nodename); + ptr += strlen(ptr); + break; + + case 'r': + if (arg > 0) + *ptr++ = ' '; + strcpy(ptr, name->release); + ptr += strlen(ptr); + break; + + case 'v': + if (arg > 0) + *ptr++ = ' '; + strcpy(ptr, name->version); + ptr += strlen(ptr); + break; + + case 'm': + if (arg > 0) + *ptr++ = ' '; + strcpy(ptr, name->machine); + ptr += strlen(ptr); + break; + + default: + LogFatal(msg, fmt); + } + } + + /* Just in case... */ + if (strlen(buf) >= sizeof(buf)) + LogFatal("Buffer overflow parsing uname.", ""); + + /* Parse the buffer. The sscanf() return value is rarely correct. */ + *result = '\0'; + (void) sscanf(buf, fmt + arg + 1, result); +} + +/* Trim leading 0's and periods from version names. The 0's cause + the number to be interpreted as octal numbers. Some version strings + have the potential for different numbers of .'s in them. + */ + +static char * +trim_version(char *p) +{ + + if (p != 0 && *p != '\0') + { + while ((*p == '0' || *p == '.') && *(p + 1) != '\0') + ++p; + } + return (p); +} +#endif + +#if defined(linux) || defined(__GLIBC__) +const char *libc_c= +"#include <stdio.h>\n" +"#include <ctype.h>\n" +"\n" +"#if 1\n" +"#pragma weak gnu_get_libc_version\n" +"#pragma weak __libc_version\n" +"#pragma weak __linux_C_lib_version\n" +"#endif\n" +"\n" +"extern const char * gnu_get_libc_version (void);\n" +"extern const char * __linux_C_lib_version;\n" +"extern const char __libc_version [];\n" +"\n" +"int\n" +"main ()\n" +"{\n" +" int libcmajor = 0, libcminor = 0, libcteeny = 0;\n" +" const char * ptr = NULL;\n" +" int glibcmajor = 0;\n" +"\n" +" if (gnu_get_libc_version != 0)\n" +" {\n" +" ptr = gnu_get_libc_version ();\n" +" glibcmajor = 4;\n" +" }\n" +" else if (&__libc_version != 0)\n" +" {\n" +" ptr = __libc_version;\n" +" glibcmajor = 4;\n" +" }\n" +" else if (&__linux_C_lib_version != 0)\n" +" {\n" +" ptr = __linux_C_lib_version;\n" +" }\n" +" else\n" +" {\n" +" libcmajor = 0; libcminor = 0; libcteeny = 0;\n" +" }\n" +"\n" +" if (ptr)\n" +" {\n" +" while (!isdigit (*ptr))\n" +" ptr++;\n" +"\n" +" sscanf (ptr, \"%d.%d.%d\", &libcmajor, &libcminor, &libcteeny);\n" +" libcmajor += glibcmajor;\n" +" }\n" +"\n" +" printf(\"#define DefaultLinuxCLibMajorVersion %d\\n\", libcmajor);\n" +" printf(\"#define DefaultLinuxCLibMinorVersion %d\\n\", libcminor);\n" +" printf(\"#define DefaultLinuxCLibTeenyVersion %d\\n\", libcteeny);\n" +"\n" +" return 0;\n" +"}\n" +; + +static void +get_libc_version(FILE *inFile) +{ + char aout[4096], *tmpdir; + FILE *fp; + const char *format = "%s -o %s -x c -"; + char *cc; + int len; + char *command; + + /* If $TMPDIR is defined and has an acceptable length, + * use that as tmp dir, else use /tmp. That fixes + * problems with /tmp mounted "noexec". + */ + if((tmpdir = getenv("TMPDIR")) != NULL && strlen(tmpdir) < (4096-13)) + strcpy(aout, tmpdir); + else + strcpy(aout, "/tmp"); + strcat(aout, "/imakeXXXXXX"); + + /* Pre-create temp file safely */ + { + /* Linux + ELF has mkstemp() */ + int tmpfd; + if ((tmpfd = mkstemp(aout)) == -1) { + perror("mkstemp"); + abort(); + } + close(tmpfd); + } + cc = getenv ("CC"); + if (cc == NULL) + cc = "gcc"; + len = strlen (aout) + strlen (format) + strlen (cc); + if (len < 128) len = 128; + if((command = alloca (len)) == NULL) + abort(); + + if (snprintf (command , len, format, cc, aout) == len) + abort (); + + fp = popen (command, "w"); + if (fp == NULL || fprintf (fp, "%s\n", libc_c) < 0 + || pclose (fp) != 0) + abort (); + + fp = popen (aout, "r"); + if (fp == NULL) + abort (); + + while (fgets (command, len, fp)) + fprintf (inFile, command); + + len = pclose (fp); + remove (aout); + if (len) + abort (); +} +#endif + +#if defined(__OpenBSD__) || defined(__DragonFly__) +static void +get_stackprotector(FILE *inFile) +{ + FILE *fp; + char *cc; + char command[1024], buf[1024]; + + cc = getenv("CC"); + if (cc == NULL) { + cc = "cc"; + } + snprintf(command, sizeof(command), "%s -v 2>&1", cc); + fp = popen(command, "r"); + if (fp == NULL) + abort(); + while (fgets(buf, sizeof(buf), fp)) { + if (strstr(buf, "propolice") != NULL) { + fprintf(inFile, "#define ProPoliceSupport YES\n"); + break; + } + } + if (pclose(fp)) + abort(); +} +#endif + + +#if defined CROSSCOMPILE || defined linux || defined(__GLIBC__) +static void +get_distrib(FILE *inFile) +{ + struct stat sb; + + static char* suse = "/etc/SuSE-release"; + static char* redhat = "/etc/redhat-release"; + static char* debian = "/etc/debian_version"; + + fprintf (inFile, "%s\n", "#define LinuxUnknown 0"); + fprintf (inFile, "%s\n", "#define LinuxSuSE 1"); + fprintf (inFile, "%s\n", "#define LinuxCaldera 2"); + fprintf (inFile, "%s\n", "#define LinuxCraftworks 3"); + fprintf (inFile, "%s\n", "#define LinuxDebian 4"); + fprintf (inFile, "%s\n", "#define LinuxInfoMagic 5"); + fprintf (inFile, "%s\n", "#define LinuxKheops 6"); + fprintf (inFile, "%s\n", "#define LinuxPro 7"); + fprintf (inFile, "%s\n", "#define LinuxRedHat 8"); + fprintf (inFile, "%s\n", "#define LinuxSlackware 9"); + fprintf (inFile, "%s\n", "#define LinuxTurbo 10"); + fprintf (inFile, "%s\n", "#define LinuxWare 11"); + fprintf (inFile, "%s\n", "#define LinuxYggdrasil 12"); + +#ifdef CROSSCOMPILE + if (CrossCompiling) { + fprintf (inFile, "%s\n", + "#define DefaultLinuxDistribution LinuxUnknown"); + fprintf (inFile, "%s\n", "#define DefaultLinuxDistName Unknown"); + return; + } +#endif + if (lstat (suse, &sb) == 0) { + fprintf (inFile, "%s\n", "#define DefaultLinuxDistribution LinuxSuSE"); + fprintf (inFile, "%s\n", "#define DefaultLinuxDistName SuSE"); + return; + } + if (lstat (redhat, &sb) == 0) { + fprintf (inFile, "%s\n", "#define DefaultLinuxDistribution LinuxRedHat"); + fprintf (inFile, "%s\n", "#define DefaultLinuxDistName RedHat"); + return; + } + if (lstat (debian, &sb) == 0) { + fprintf (inFile, "%s\n", "#define DefaultLinuxDistribution LinuxDebian"); + fprintf (inFile, "%s\n", "#define DefaultLinuxDistName Debian"); + /* You could also try to get the version of the Debian distrib by looking + * at the content of /etc/debian_version */ + return; + } + /* what's the definitive way to tell what any particular distribution is? */ + + fprintf (inFile, "%s\n", "#define DefaultLinuxDistribution LinuxUnknown"); + fprintf (inFile, "%s\n", "#define DefaultLinuxDistName Unknown"); + /* would like to know what version of the distribution it is */ +} + +static void +get_ld_version(FILE *inFile) +{ + FILE* ldprog; + signed char c; + int ldmajor, ldminor; + const char *ld = "ld -v"; + +#ifdef CROSSCOMPILE + if (CrossCompiling) { + char cmd[PATH_MAX]; + strcpy (cmd, CrossCompileDir); + strcat (cmd,"/"); + strcat (cmd,ld); + ldprog = popen (cmd, "r"); + } else +#endif + ldprog = popen (ld, "r"); + + if (ldprog) { + do { + c = fgetc (ldprog); + } while (c != EOF && !isdigit (c)); + ungetc (c, ldprog); + (void) fscanf (ldprog, "%d.%d", &ldmajor, &ldminor); + /* Start conversion to a more rational number */ + if ((ldmajor > 2) || ((ldmajor == 2) && (ldminor > 9))) + ldmajor *= 100; + else + ldmajor *= 10; + + fprintf(inFile, "#define DefaultLinuxBinUtilsMajorVersion %d\n", + ldmajor + ldminor); + pclose (ldprog); + } +} +#endif + +#if defined __FreeBSD__ +static void +get_binary_format(FILE *inFile) +{ + int mib[2]; + size_t len; + int osrel = 0; + FILE *objprog = NULL; + int iself = 0; + char buf[10]; + char cmd[PATH_MAX]; + + mib[0] = CTL_KERN; + mib[1] = KERN_OSRELDATE; + len = sizeof(osrel); + sysctl(mib, 2, &osrel, &len, NULL, 0); + if (CrossCompiling) { + strcpy (cmd, CrossCompileDir); + strcat (cmd, "/"); + strcat (cmd,"objformat"); + } else + strcpy (cmd, "objformat"); + + if (osrel >= 300004 && + (objprog = popen(cmd, "r")) != NULL && + fgets(buf, sizeof(buf), objprog) != NULL && + strncmp(buf, "elf", 3) == 0) + iself = 1; + if (objprog) + pclose(objprog); + + fprintf(inFile, "#define DefaultToElfFormat %s\n", iself ? "YES" : "NO"); +} +#endif + +#if defined(sun) && defined(__SVR4) +/* Runs Sun compiler command and parses output - this is a bit of a hack + * as it depends on the particular output format of the -V flag, but it's + * worked for many releases. + * + * Input : cmd - command to run (called with -V flag) + * path - path to command to run (use $PATH if NULL) + * Output: cmajor & cminor - major and minor versions if found + * Returns: 0 if successful, -1 if not. + */ +static int +ask_sun_compiler_for_versions(const char *cmd, const char *path, + int *cmajor, int *cminor) +{ + char buf[BUFSIZ]; + char cmdtorun[PATH_MAX]; + char* vptr; + FILE* ccproc; + const char vflag[] = " -V 2>&1"; + int retval = -1; + + int len = strlen(cmd) + sizeof(vflag); + + if (path != NULL) { + len += strlen(path) + 1; + } + + if (len < sizeof(cmdtorun)) { + if (path != NULL) { + sprintf(cmdtorun, "%s/%s %s", path, cmd, vflag); + } else { + sprintf(cmdtorun, "%s %s", cmd, vflag); + } + + if ((ccproc = popen (cmdtorun, "r")) != NULL) { + if (fgets (buf, sizeof(buf), ccproc) != NULL) { + vptr = strrchr (buf, 'C'); + if (vptr) { + for (; (*vptr != '\0') && !isdigit(*vptr); vptr++) { + /* Do nothing - just scanning for first digit */ + } + if (*vptr != '\0') { + if (sscanf (vptr, "%d.%d", cmajor, cminor) == 2) { + retval = 0; + } + } + } + if (retval != 0) { + fprintf(stderr, + "warning: could not parse version number in output of:\n" + " %s\n", cmdtorun); + } + while (fgets (buf, sizeof(buf), ccproc) != NULL) {}; + } + pclose (ccproc); + } + } + return retval; +} + +/* Find Sun compilers and their versions if present */ +static void +get_sun_compiler_versions (FILE *inFile) +{ + const char* sunpro_path = "/opt/SUNWspro/bin"; + int cmajor, cminor, found = 0; + struct stat sb; + + /* If cross-compiling, only check CrossCompilerDir for compilers. + * If not cross-compiling, first check cc in users $PATH, + * then try /opt/SUNWspro if not found in the users $PATH + */ + +#if defined CROSSCOMPILE + if (CrossCompiling) { + if (ask_sun_compiler_for_versions("cc", CrossCompileDir, + &cmajor, &cminor) == 0) { + found = 1; + } + } + else +#endif + { + if (ask_sun_compiler_for_versions("cc", NULL, &cmajor, &cminor) == 0) { + found = 1; + } else if (ask_sun_compiler_for_versions("cc", sunpro_path, + &cmajor, &cminor) == 0) { + found = 1; + fprintf(inFile, "#define DefaultSunProCCompilerDir %s", sunpro_path); + } + } + + if (found) { + fprintf (inFile, + "#define DefaultSunProCCompilerMajorVersion %d\n", cmajor); + fprintf (inFile, + "#define DefaultSunProCCompilerMinorVersion %d\n", cminor); + } + + /* Now do it again for C++ compiler (CC) */ + found = 0; +#if defined CROSSCOMPILE + if (CrossCompiling) { + if (ask_sun_compiler_for_versions("CC", CrossCompileDir, + &cmajor, &cminor) == 0) { + found = 1; + } + } + else +#endif + { + if (ask_sun_compiler_for_versions("CC", NULL, &cmajor, &cminor) == 0) { + found = 1; + } else if (ask_sun_compiler_for_versions("CC", sunpro_path, + &cmajor, &cminor) == 0) { + found = 1; + fprintf(inFile, + "#define DefaultSunProCplusplusCompilerDir %s", sunpro_path); + } + } + + if (found) { + fprintf (inFile, + "#define DefaultSunProCplusplusCompilerMajorVersion %d\n", + cmajor); + fprintf (inFile, + "#define DefaultSunProCplusplusCompilerMinorVersion %d\n", + cminor); + } +} +#endif + +#if defined CROSSCOMPILE || defined __GNUC__ +static void +get_gcc_version(FILE *inFile, char *name) +{ + fprintf (inFile, "#define HasGcc 1\n"); +#ifdef CROSSCOMPILE + if (CrossCompiling) + { + if (gnu_c > 1) { + fprintf (inFile, "#define HasGcc2 1\n"); + if (gnu_c > 2) + fprintf (inFile, "#define HasGcc3 1\n"); + } + fprintf (inFile, "#define GccMajorVersion %d\n", gnu_c); + fprintf (inFile, "#define GccMinorVersion %d\n", gnu_c_minor); + } else +#endif + { +#if __GNUC__ > 1 + fprintf (inFile, "#define HasGcc2 1\n"); +# if __GNUC__ > 2 + fprintf (inFile, "#define HasGcc3 1\n"); +# endif +#endif + fprintf (inFile, "#define GccMajorVersion %d\n", __GNUC__); + fprintf (inFile, "#define GccMinorVersion %d\n", __GNUC_MINOR__); + } +#if defined(HAS_MERGE_CONSTANTS) + fprintf (inFile, "#define HasGccMergeConstants %d\n", HAS_MERGE_CONSTANTS); +#endif +} +#endif + +static boolean +get_gcc(char *cmd) +{ + struct stat sb; + static char* gcc_path[] = { +# if defined(linux) || \ + defined(__NetBSD__) || \ + defined(__OpenBSD__) || \ + defined(__FreeBSD__) || \ + defined(__DragonFly__) || \ + defined(__APPLE__) || \ + defined(__CYGWIN__) || \ + defined(__MINGW32__) || \ + defined(__GNU__) || \ + defined(__GLIBC__) + "/usr/bin/cc", /* for Linux PostIncDir */ +# endif + "/usr/local/bin/gcc", + "/opt/gnu/bin/gcc", + "/usr/pkg/bin/gcc" + }; + +#ifdef CROSSCOMPILE + static char* cross_cc_name[] = { + "cc", + "gcc" + }; + + if (CrossCompiling) { + int i; + for (i = 0; i < sizeof (cross_cc_name) / sizeof cross_cc_name[0]; i++){ + strcpy (cmd, CrossCompileDir); + strcat (cmd, "/"); + strcat (cmd, cross_cc_name[i]); + if (lstat (cmd, &sb) == 0) { + return TRUE; + break; + } + } + } else +#endif + { + int i; + for (i = 0; i < sizeof (gcc_path) / sizeof gcc_path[0]; i++) { + if (lstat (gcc_path[i], &sb) == 0) { + strcpy (cmd, gcc_path[i]); + return TRUE; + } + } + } + return FALSE; +} + +#if defined CROSSCOMPILE || !defined __UNIXOS2__ +static void +get_gcc_incdir(FILE *inFile, char* name) +{ + FILE* gccproc; + char buf[PATH_MAX]; + char cmd[PATH_MAX]; + char* ptr; + + strcpy(cmd,name); + + buf[0] = '\0'; + strcat (cmd, " --print-libgcc-file-name"); + if ((gccproc = popen (cmd, "r")) != NULL) { + if (fgets (buf, PATH_MAX, gccproc) != NULL) { + ptr = strstr (buf, "libgcc.a"); + if (ptr) strcpy (ptr, "include"); + } + (void) pclose (gccproc); + } + + if (buf[0]) + fprintf (inFile, "#define DefaultGccIncludeDir \"%s\"\n", buf); +} +#endif + +boolean +define_os_defaults(FILE *inFile) +{ +#if defined CROSSCOMPILE || ( !defined(WIN32) && !defined(__UNIXOS2__) ) +#ifdef CROSSCOMPILE +#ifdef __GNUC__ + if (1) +#else + if ((sys != win32) && (sys != emx)) +#endif +#endif + { +# if (defined(DEFAULT_OS_NAME) || defined(DEFAULT_OS_MAJOR_REV) || \ + defined(DEFAULT_OS_MINOR_REV) || defined(DEFAULT_OS_TEENY_REV)) + struct utsname *name = NULL; + struct utsname uts_name; + char buf[SYS_NMLN * 5 + 1]; + + /* Obtain the system information. */ +#ifdef CROSSCOMPILE + if (!CrossCompiling) +#endif + { + if (uname(&uts_name) < 0) + LogFatal("Cannot invoke uname", ""); + else + name = &uts_name; + } +#if defined CROSSCOMPILE && (defined linux || defined(__GLIBC__)) + else { + strncpy(uts_name.sysname,cross_uts_sysname,SYS_NMLN); + strncpy(uts_name.release,cross_uts_release,SYS_NMLN); + strncpy(uts_name.version,cross_uts_version,SYS_NMLN); + strncpy(uts_name.machine,cross_uts_machine,SYS_NMLN); + name = &uts_name; + } +#endif +# ifdef __FreeBSD__ + /* Override for compiling in chroot of other OS version, such as + * in the bento build cluster. + */ + { + char *e; + if ((e = getenv("OSREL")) != NULL && + strlen(name->sysname) + strlen(e) + 1 < SYS_NMLN) { + strcpy(name->release, e); + strcpy(name->version, name->sysname); + strcat(name->version, " "); + strcat(name->version, e); + } + } +# endif + +# if defined DEFAULT_OS_NAME +# if defined CROSSCOMPILE + if (!CrossCompiling) +# endif + { + parse_utsname(name, DEFAULT_OS_NAME, buf, + "Bad DEFAULT_OS_NAME syntax %s"); +# ifdef DEFAULT_OS_NAME_FROB + DEFAULT_OS_NAME_FROB(buf, sizeof buf); +# endif + if (buf[0] != '\0') + fprintf(inFile, "#define DefaultOSName %s\n", buf); + } +# endif + +# if defined CROSSCOMPILE + if (CrossCompiling && defaultOsName) { + parse_utsname(name, defaultOsName, buf, + "Bad DEFAULT_OS_NAME syntax %s"); + if (defaultOsNameFrob) + defaultOsNameFrob(buf, sizeof buf); + if (buf[0] != '\0') + fprintf(inFile, "#define DefaultOSName %s\n", buf); + } +# endif + +# ifdef DEFAULT_OS_MAJOR_REV +# if defined CROSSCOMPILE + if (!CrossCompiling) +# endif + { + parse_utsname(name, DEFAULT_OS_MAJOR_REV, buf, + "Bad DEFAULT_OS_MAJOR_REV syntax %s"); +# ifdef DEFAULT_OS_MAJOR_REV_FROB + DEFAULT_OS_MAJOR_REV_FROB(buf, sizeof buf); +# endif + fprintf(inFile, "#define DefaultOSMajorVersion %s\n", + *buf ? trim_version(buf) : "0"); + } +# endif + +# if defined CROSSCOMPILE + if (CrossCompiling && defaultOsMajorRev) { + parse_utsname(name, defaultOsMajorRev, buf, + "Bad defaultOsMajorRev syntax %s"); + if (defaultOsMajorRevFrob) + defaultOsMajorRevFrob(buf, sizeof buf); + fprintf(inFile, "#define DefaultOSMajorVersion %s\n", + *buf ? trim_version(buf) : "0"); + } +# endif + +# ifdef DEFAULT_OS_MINOR_REV +# if defined CROSSCOMPILE + if (!CrossCompiling) +# endif + { + parse_utsname(name, DEFAULT_OS_MINOR_REV, buf, + "Bad DEFAULT_OS_MINOR_REV syntax %s"); +# ifdef DEFAULT_OS_MINOR_REV_FROB + DEFAULT_OS_MINOR_REV_FROB(buf, sizeof buf); +# endif + fprintf(inFile, "#define DefaultOSMinorVersion %s\n", + *buf ? trim_version(buf) : "0"); + } +# endif + +# if defined CROSSCOMPILE + if (CrossCompiling && defaultOsMinorRev) { + parse_utsname(name, defaultOsMinorRev, buf, + "Bad defaultOsMinorRev syntax %s"); + if (defaultOsMinorRevFrob) + defaultOsMinorRevFrob(buf, sizeof buf); + fprintf(inFile, "#define DefaultOSMinorVersion %s\n", + *buf ? trim_version(buf) : "0"); + } +# endif + +# ifdef DEFAULT_OS_TEENY_REV +# if defined CROSSCOMPILE + if (!CrossCompiling) +# endif + { + parse_utsname(name, DEFAULT_OS_TEENY_REV, buf, + "Bad DEFAULT_OS_TEENY_REV syntax %s"); +# ifdef DEFAULT_OS_TEENY_REV_FROB + DEFAULT_OS_TEENY_REV_FROB(buf, sizeof buf); +# endif + fprintf(inFile, "#define DefaultOSTeenyVersion %s\n", + *buf ? trim_version(buf) : "0"); + } +# endif + +# if defined CROSSCOMPILE + if (CrossCompiling && defaultOsTeenyRev) { + parse_utsname(name, defaultOsTeenyRev, buf, + "Bad defaultOsTeenyRev syntax %s"); + if (defaultOsTeenyRevFrob) + defaultOsTeenyRevFrob(buf, sizeof buf); + fprintf(inFile, "#define DefaultOSTeenyVersion %s\n", + *buf ? trim_version(buf) : "0"); + } +# endif + +# ifdef DEFAULT_MACHINE_ARCHITECTURE +# if defined CROSSCOMPILE + if (!CrossCompiling) +# endif + { + parse_utsname(name, DEFAULT_MACHINE_ARCHITECTURE, buf, + "Bad DEFAULT_MACHINE_ARCHITECTURE %s"); + fprintf(inFile, "#ifndef %s\n# define %s\n#endif\n", buf, buf); + } +# endif + +# if defined CROSSCOMPILE + if (CrossCompiling && defaultMachineArchitecture) { + parse_utsname(name, defaultMachineArchitecture, buf, + "Bad defaultMachineArchitecture syntax %s"); + fprintf(inFile, "#ifndef %s\n# define %s\n#endif\n", buf, buf); + } +# endif +# endif +# if defined CROSSCOMPILE + if (CrossCompiling) + get_cross_compile_dir(inFile); + else +# endif + fprintf(inFile, "#define CrossCompiling NO\n"); +# if defined CROSSCOMPILE + if (CrossCompiling && sys == LinuX) +# endif +# if defined CROSSCOMPILE || defined linux || defined(__GLIBC__) +# if defined(CROSSCOMPILE) && defined(__linux__) + if (sys == LinuX) +# endif + get_distrib (inFile); +# endif +# if defined linux || defined(__GLIBC__) +# if defined CROSSCOMPILE + if (!CrossCompiling) +# endif + get_libc_version (inFile); +# if defined CROSSCOMPILE + else { + fprintf(inFile,"#define DefaultLinuxCLibMajorVersion %d\n", + glibc_major); + fprintf(inFile,"#define DefaultLinuxCLibMinorVersion %d\n", + glibc_minor); + fprintf(inFile,"#define DefaultLinuxCLibTeenyVersion 0\n"); + } +# endif +# endif /* linux || __GLIBC__ */ +# if defined CROSSCOMPILE || defined linux || defined(__GLIBC__) +# if defined CROSSCOMPILE && defined(__linux__) + if (sys == LinuX) +# endif + get_ld_version(inFile); +# endif +# if defined (sun) && defined(SVR4) + get_sun_compiler_versions (inFile); +# endif +# if defined CROSSCOMPILE || defined __GNUC__ +# if defined CROSSCOMPILE + if (gnu_c) +# endif + { + char name[PATH_MAX]; + if (get_gcc(name)) { + get_gcc_version (inFile,name); +# if defined CROSSCOMPILE || !defined __UNIXOS2__ +# if defined CROSSCOMPILE + if (sys != emx) +# endif + get_gcc_incdir(inFile,name); +# endif + } + } +# endif +# if defined __FreeBSD__ +# if defined CROSSCOMPILE + if (sys == freeBSD) +# endif + get_binary_format(inFile); +# endif + } +#endif /* !WIN32 && !__UNIXOS2__*/ +#if defined WIN32 +# ifdef CROSSCOMPILE + else if (sys == win32 && !CrossCompiling) +# endif + { + OSVERSIONINFO osvi; + static char* os_names[] = { "Win32s", "Windows 95", "Windows NT" }; + + memset(&osvi, 0, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); + GetVersionEx (&osvi); + + fprintf (inFile, "#define DefaultOSName Microsoft %s\n", + os_names[osvi.dwPlatformId]); + + fprintf(inFile, "#define DefaultOSMajorVersion %d\n", osvi.dwMajorVersion); + fprintf(inFile, "#define DefaultOSMinorVersion %d\n", osvi.dwMinorVersion); + fprintf(inFile, "#define DefaultOSTeenyVersion %d\n", + osvi.dwBuildNumber & 0xFFFF); + } +#endif /* WIN32 */ +#ifdef CROSSCOMPILE + else if (sys == emx) +#endif +#if defined CROSSCOMPILE || defined __UNIXOS2__ + { + fprintf(inFile, "#define DefaultOSMajorVersion 4\n"); + fprintf(inFile, "#define DefaultOSMinorVersion 0\n"); + fprintf(inFile, "#define DefaultOSTeenyVersion 0\n"); + } +#endif /* EMX */ +#if defined(__OpenBSD__) || defined(__DragonFly__) + get_stackprotector(inFile); +#endif + return FALSE; +} + +void +cppit(char *imakefile, char *template, char *masterc, + FILE *outfd, char *outfname) +{ + FILE *inFile; + + haveImakefileC = TRUE; + inFile = fopen(masterc, "w"); + if (inFile == NULL) + LogFatal("Cannot open %s for output.", masterc); + if (fprintf(inFile, "%s\n", ImakefileCHeader) < 0 || + define_os_defaults(inFile) || + optional_include(inFile, "IMAKE_LOCAL_DEFINES", "localdefines") || + optional_include(inFile, "IMAKE_ADMIN_DEFINES", "admindefines") || + fprintf(inFile, "#define %s <%s>\n", ImakeDefSym, imakefile) < 0 || + fprintf(inFile, LocalDefineFmt, ImakeTmplSym, template) < 0 || + fprintf(inFile, IncludeFmt, ImakeTmplSym) < 0 || + optional_include(inFile, "IMAKE_ADMIN_MACROS", "adminmacros") || + optional_include(inFile, "IMAKE_LOCAL_MACROS", "localmacros") || + fflush(inFile) || + fclose(inFile)) + LogFatal("Cannot write to %s.", masterc); + /* + * Fork and exec cpp + */ + doit(outfd, cpp, cpp_argv); + CleanCppOutput(outfd, outfname); +} + +void +makeit(void) +{ + doit(NULL, make_argv[0], make_argv); +} + +char * +CleanCppInput(char *imakefile) +{ + FILE *outFile = NULL; + FILE *inFile; + char *buf, /* buffer for file content */ + *pbuf, /* walking pointer to buf */ + *punwritten, /* pointer to unwritten portion of buf */ + *ptoken, /* pointer to # token */ + *pend, /* pointer to end of # token */ + savec; /* temporary character holder */ + int count; + struct stat st; + + /* + * grab the entire file. + */ + if (!(inFile = fopen(imakefile, "r"))) + LogFatal("Cannot open %s for input.", imakefile); + if (fstat(fileno(inFile), &st) < 0) + LogFatal("Cannot stat %s for size.", imakefile); + buf = Emalloc((int)st.st_size+3); + count = fread(buf + 2, 1, st.st_size, inFile); + if (count == 0 && st.st_size != 0) + LogFatal("Cannot read %s:", imakefile); + fclose(inFile); + buf[0] = '\n'; + buf[1] = '\n'; + buf[count + 2] = '\0'; + + punwritten = pbuf = buf + 2; + while (*pbuf) { + /* for compatibility, replace make comments for cpp */ + if (*pbuf == '#' && pbuf[-1] == '\n' && pbuf[-2] != '\\') { + ptoken = pbuf+1; + while (*ptoken == ' ' || *ptoken == '\t') + ptoken++; + pend = ptoken; + while (*pend && *pend != ' ' && *pend != '\t' && *pend != '\n' && *pend != '\r') + pend++; + savec = *pend; + *pend = '\0'; + if (strcmp(ptoken, "define") && + strcmp(ptoken, "if") && + strcmp(ptoken, "ifdef") && + strcmp(ptoken, "ifndef") && + strcmp(ptoken, "include") && + strcmp(ptoken, "line") && + strcmp(ptoken, "else") && + strcmp(ptoken, "elif") && + strcmp(ptoken, "endif") && + strcmp(ptoken, "error") && + strcmp(ptoken, "pragma") && + strcmp(ptoken, "undef")) { + if (outFile == NULL) { +#ifdef HAS_MKSTEMP + int fd; +#endif + tmpImakefile = Strdup(tmpImakefile); +#ifndef HAS_MKSTEMP + if (mktemp(tmpImakefile) == NULL || + (outFile = fopen(tmpImakefile, "w+")) == NULL) { + LogFatal("Cannot open %s for write.", + tmpImakefile); + } +#else + fd=mkstemp(tmpImakefile); + if (fd != -1) + outFile = fdopen(fd, "w"); + if (outFile == NULL) { + if (fd != -1) { + unlink(tmpImakefile); close(fd); + } + LogFatal("Cannot open %s for write.", + tmpImakefile); + } +#endif + } + writetmpfile(outFile, punwritten, pbuf-punwritten, + tmpImakefile); + if (ptoken > pbuf + 1) + writetmpfile(outFile, "XCOMM", 5, tmpImakefile); + else + writetmpfile(outFile, "XCOMM ", 6, tmpImakefile); + punwritten = pbuf + 1; + } + *pend = savec; + } + pbuf++; + } + if (outFile) { + writetmpfile(outFile, punwritten, pbuf-punwritten, tmpImakefile); + fclose(outFile); + + return tmpImakefile; + } + + return(imakefile); +} + +void +CleanCppOutput(FILE *tmpfd, char *tmpfname) +{ + char *input; + int blankline = 0; + + while((input = ReadLine(tmpfd, tmpfname))) { + if (isempty(input)) { + if (blankline++) + continue; +#ifdef CROSSCOMPILE + if (fixup_whitespace) +#endif +#if defined CROSSCOMPILE || defined FIXUP_CPP_WHITESPACE + KludgeResetRule(); +#endif + } else { + blankline = 0; +#ifdef CROSSCOMPILE + if (fixup_whitespace) +#endif +#if defined CROSSCOMPILE || defined FIXUP_CPP_WHITESPACE + KludgeOutputLine(&input); +#endif + writetmpfile(tmpfd, input, strlen(input), tmpfname); + } + writetmpfile(tmpfd, "\n", 1, tmpfname); + } + fflush(tmpfd); +#ifdef NFS_STDOUT_BUG + /* + * On some systems, NFS seems to leave a large number of nulls at + * the end of the file. Ralph Swick says that this kludge makes the + * problem go away. + */ + ftruncate (fileno(tmpfd), (off_t)ftell(tmpfd)); +#endif +} + +/* + * Determine if a line has nothing in it. As a side effect, we trim white + * space from the end of the line. Cpp magic cookies are also thrown away. + * "XCOMM" token is transformed to "#". + */ +boolean +isempty(char *line) +{ + char *pend; + + /* + * Check for lines of the form + * # n "... + * or + * # line n "... + */ + if (*line == '#') { + pend = line+1; + if (*pend == ' ') + pend++; + if (*pend == 'l' && pend[1] == 'i' && pend[2] == 'n' && + pend[3] == 'e' && pend[4] == ' ') + pend += 5; + if (isdigit(*pend)) { + do { + pend++; + } while (isdigit(*pend)); + if (*pend == '\n' || *pend == '\0') + return(TRUE); + if (*pend++ == ' ' && *pend == '"') + return(TRUE); + } + while (*pend) + pend++; + } else { + for (pend = line; *pend; pend++) { + if (*pend == 'X' && pend[1] == 'C' && pend[2] == 'O' && + pend[3] == 'M' && pend[4] == 'M' && + (pend == line || pend[-1] == ' ' || pend[-1] == '\t' || pend[-1] == '\r') && + (pend[5] == ' ' || pend[5] == '\t' || pend[5] == '\r' || pend[5] == '\0')) + { + *pend = '#'; + memmove(pend+1, pend+5, strlen(pend+5)+1); + } +#ifdef CROSSCOMPILE + if (magic_make_vars) +#endif + { +#if defined CROSSCOMPILE || defined MAGIC_MAKE_VARS + if (*pend == 'X' && pend[1] == 'V' && pend[2] == 'A' && + pend[3] == 'R') + { + char varbuf[5]; + int i; + + if (pend[4] == 'd' && pend[5] == 'e' && pend[6] == 'f' && + pend[7] >= '0' && pend[7] <= '9') + { + i = pend[7] - '0'; + sprintf(varbuf, "%0.4d", xvariable); + strncpy(pend+4, varbuf, 4); + xvariables[i] = xvariable; + xvariable = (xvariable + 1) % 10000; + } + else if (pend[4] == 'u' && pend[5] == 's' && + pend[6] == 'e' && pend[7] >= '0' && + pend[7] <= '9') + { + i = pend[7] - '0'; + sprintf(varbuf, "%0.4d", xvariables[i]); + strncpy(pend+4, varbuf, 4); + } + } +#endif + } + } + } + while (--pend >= line && (*pend == ' ' || *pend == '\t' || *pend == '\r')) ; + pend[1] = '\0'; + return (*line == '\0'); +} + +/*ARGSUSED*/ +char * +ReadLine(FILE *tmpfd, char *tmpfname) +{ + static boolean initialized = FALSE; + static char *buf, *pline, *end; + register char *p1, *p2; + + if (! initialized) { +#ifdef WIN32 + FILE *fp = tmpfd; +#endif + int total_red; + struct stat st; + + /* + * Slurp it all up. + */ + fseek(tmpfd, 0, 0); + if (fstat(fileno(tmpfd), &st) < 0) + LogFatal("cannot stat %s for size", tmpMakefile); + pline = buf = Emalloc((int)st.st_size+1); + total_red = fread(buf, 1, st.st_size, tmpfd); + if (total_red == 0 && st.st_size != 0) + LogFatal("cannot read %s", tmpMakefile); + end = buf + total_red; + *end = '\0'; + fseek(tmpfd, 0, 0); +#if defined(SYSV) || defined(WIN32) || defined(USE_FREOPEN) + tmpfd = freopen(tmpfname, "w+", tmpfd); +#ifdef WIN32 + if (! tmpfd) /* if failed try again */ + tmpfd = freopen(tmpfname, "w+", fp); +#endif + if (! tmpfd) + LogFatal("cannot reopen %s\n", tmpfname); +#else /* !SYSV */ + ftruncate(fileno(tmpfd), (off_t) 0); +#endif /* !SYSV */ + initialized = TRUE; + fprintf (tmpfd, "# Makefile generated by imake - do not edit!\n"); + fprintf (tmpfd, "# %s\n", + "$Xorg: imake.c,v 1.6 2001/02/09 02:03:15 xorgcvs Exp $"); + } + + for (p1 = pline; p1 < end; p1++) { + if (*p1 == '@' && *(p1+1) == '@' + /* ignore ClearCase version-extended pathnames */ + && !(p1 != pline && !isspace(*(p1-1)) && *(p1+2) == '/')) + { /* soft EOL */ + *p1++ = '\0'; + p1++; /* skip over second @ */ + break; + } + else if (*p1 == '\n') { /* real EOL */ +#if defined CROSSCOMPILE || defined WIN32 +# if defined CROSSCOMPILE + if (sys == win32) +# endif + { + if (p1 > pline && p1[-1] == '\r') + p1[-1] = '\0'; + } +#endif + *p1++ = '\0'; + break; + } + } + + /* + * return NULL at the end of the file. + */ + p2 = (pline == p1 ? NULL : pline); + pline = p1; + return(p2); +} + +void +writetmpfile(FILE *fd, char *buf, int cnt, char *fname) +{ + if (fwrite(buf, sizeof(char), cnt, fd) == -1) + LogFatal("Cannot write to %s.", fname); +} + +char * +Emalloc(int size) +{ + char *p; + + if ((p = malloc(size)) == NULL) + LogFatalI("Cannot allocate %d bytes", size); + return(p); +} + +#if defined CROSSCOMPILE || defined FIXUP_CPP_WHITESPACE +void +KludgeOutputLine(char **pline) +{ + char *p = *pline; + char quotechar = '\0'; + + switch (*p) { + case '#': /*Comment - ignore*/ + break; + case '\t': /*Already tabbed - ignore it*/ + break; + case ' ': /*May need a tab*/ + default: +#ifdef CROSSCOMPILE + if (inline_syntax) +#endif +#if defined CROSSCOMPILE || defined INLINE_SYNTAX + { + if (*p == '<' && p[1] == '<') { /* inline file close */ + InInline--; + InRule = TRUE; + break; + } + } +#endif + /* + * The following cases should not be treated as beginning of + * rules: + * variable := name (GNU make) + * variable = .*:.* (':' should be allowed as value) + * sed 's:/a:/b:' (: used in quoted values) + */ + for (; *p; p++) { + if (quotechar) { + if (quotechar == '\\' || + (*p == quotechar && +# if defined CROSSCOMPILE || defined WIN32 + ( +# if defined CROSSCOMPILE + (sys == win32) && +# endif + quotechar != ')') && +# endif + p[-1] != '\\')) + quotechar = '\0'; + continue; + } + switch (*p) { + case '\\': + case '"': + case '\'': + quotechar = *p; + break; + case '(': + quotechar = ')'; + break; + case '{': + quotechar = '}'; + break; + case '[': + quotechar = ']'; + break; + case '=': +#ifdef CROSSCOMPILE + if (remove_cpp_leadspace) +#endif +#if defined CROSSCOMPILE || defined REMOVE_CPP_LEADSPACE + { + if (!InRule && **pline == ' ') { + while (**pline == ' ') + (*pline)++; + } + } +#endif + goto breakfor; +#if defined CROSSCOMPILE || defined INLINE_SYNTAX + case '<': + if (inline_syntax) { + if (p[1] == '<') /* inline file start */ + InInline++; + } + break; +#endif + case ':': + if (p[1] == '=') + goto breakfor; + while (**pline == ' ') + (*pline)++; + InRule = TRUE; + return; + } + } +breakfor: + if (InRule && **pline == ' ') + **pline = '\t'; + break; + } +} + +void +KludgeResetRule(void) +{ + InRule = FALSE; +} +#endif +char * +Strdup(char *cp) +{ + char *new = Emalloc(strlen(cp) + 1); + + strcpy(new, cp); + return new; +} + +#ifdef CROSSCOMPILE +char* +CrossCompileCPP(void) +{ + char *cpp, *c; + int len ; + if (crosscompile_use_cc_e) + AddCppArg("-E"); + + cpp = strrchr(crosscompile_cpp,'/'); + if (!cpp) + cpp = crosscompile_cpp; + else + cpp++; + + len = strlen(cpp) + strlen(CrossCompileDir) + 2; + c = Emalloc(len); + + (void)snprintf(c, len,"%s/%s",CrossCompileDir,cpp); + + return c; +} + +#endif + +#ifdef CROSSCOMPILE +static void +get_cross_compile_dir(FILE *inFile) +{ + fprintf(inFile, "#define CrossCompileDir %s\n", + CrossCompileDir); + fprintf(inFile, "#define CrossCompiling YES\n"); +} +#endif |