cechew@bruce.OZ (Earl Chew) (11/09/89)
#! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 2 (of 2)." # Contents: cppmake.c # Wrapped by cechew@bruce on Thu Nov 9 20:07:23 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'cppmake.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'cppmake.c'\" else echo shar: Extracting \"'cppmake.c'\" \(26995 characters\) sed "s/^X//" >'cppmake.c' <<'END_OF_FILE' X/* C P P M A K E X * X * Author: C. E. Chew X * Date: October 1989 X * X * (C) Copyright C E Chew X * X * Feel free to copy, use and distribute this software provided: X * X * 1. you do not pretend that you wrote it X * 2. you leave this copyright notice intact. X * X * Patchlevel 1.5 X * X * Edit History: X * 03-Nov-1989 Oops mixed up WSTOPSIG and WTERMSIG. Patches from Bruce X * Evans about running in background and add pid_t for X * _MINIX. Scan CPPMAKECPP and CPPMAKEMAKE to break up X * into word sized morsels. Leave comments intact. X * 01-Nov-1989 Don't use @$ since some systems use $ as alphabetic. X * More problems with getline. Add CPPOPT. Add -M and -C. X * 31-Oct-1989 Quote with printable characters. X * 23-Oct-1989 Fixed getline() looping bug. Fix single argument problem. X */ X X#include <ctype.h> X#include <stdio.h> X#include <signal.h> X X#ifndef _MSDOS X#include <sys/types.h> X#endif X X#ifdef _BSD X#include <strings.h> X#else X#include <string.h> X#endif X X#ifdef _BSD X#include <sys/wait.h> X#endif X X#ifdef _MSDOS X#include <process.h> X#endif X X/* Varargs handling */ X X#ifdef __STDC__ X# include <stdarg.h> X# define VA_START(n,l) va_start(n,l) X# define VA_ALIST ... X# define VA_LIST va_list X# define VA_END(n) va_end(n) X# define VA_ARG(n,t) va_arg(n,t) X# define VA_DCL X#else X# include <varargs.h> X# define VA_START(n,l) va_start(n) X# define VA_ALIST va_alist X# define VA_LIST va_list X# define VA_END(n) va_end(n) X# define VA_ARG(n,t) va_arg(n,t) X# define VA_DCL va_dcl X#endif X X/* Function prototypes */ X X#ifdef __STDC__ X#define P(x) x X#define T(x,y) x X#define D(x) X#else X#define P(x) () X#define T(x,y) y X#define D(x) x; X#endif X X/* Local definitions */ X X#define DEFINE "-D" /* define */ X#define INCLUDE "-I" /* include */ X#define UNDEF "-U" /* undefine */ X X#define INCFILE ".i" /* extension for include file */ X X#define MAXARGS 20 /* maximum args in process descriptor */ X X#define GETLINELENGTH 80 /* initial allocation for getline */ X#define GETLINEINC 20 /* increment for getline */ X X#define CATHEADERWIDTH 60 /* header width for cat */ X X#define CPPINPUT "/tmp/cppiXXXXXX"/* cpp input */ X#define CPPOUTPUT "/tmp/cppoXXXXXX"/* cpp output */ X#define MAKEFILE "/tmp/makeXXXXXX"/* make file */ X X/* System deficiencies */ X X#ifdef _BSD Xtypedef int pid_t; /* process id */ Xtypedef union wait wait_t; /* wait return structure */ X#endif X X#ifdef _MINIX Xtypedef int pid_t; /* process id */ Xtypedef int wait_t; /* wait return structure */ X#endif X X#ifdef INTSIGNAL Xtypedef int signal_t; /* signal handler return */ X#else Xtypedef void signal_t; /* signal handler return */ X#endif X X#ifdef CHARMALLOC Xtypedef char *malloc_t; /* malloc return type */ Xtypedef int free_t; /* free return type */ X#else Xtypedef void *malloc_t; /* malloc return type */ Xtypedef void free_t; /* free return type */ X#endif X X#ifndef _MSDOS X X#ifndef WIFSTOPPED X#define WIFSTOPPED(x) ((*((unsigned int *) (&(x))) & 0xff) == 0x7f) X#endif X X#ifndef WIFEXITED X#define WIFEXITED(x) ((*((unsigned int *) (&(x))) & 0xff) == 0) X#endif X X#ifndef WIFSIGNALED X#define WIFSIGNALED(x) ((*((unsigned int *) (&(x))) - 1 & 0xffff) < 0xff) X#endif X X#ifndef WSTOPSIG X#define WSTOPSIG(x) ((*((unsigned int *) (&(x))) >> 8) & 0xff) X#endif X X#ifndef WEXITSTATUS X#define WEXITSTATUS(x) ((*((unsigned int *) (&(x))) >> 8) & 0xff) X#endif X X#ifndef WTERMSIG X#define WTERMSIG(x) (*((unsigned int *) (&(x))) & 0x7f) X#endif X X#endif X X#ifdef _BSD X#define strrchr rindex X#endif X X/* Library function prototypes */ X Xmalloc_t malloc P((unsigned int)); /* raw malloc */ Xmalloc_t realloc P((malloc_t, unsigned int));/* raw realloc */ Xfree_t free P((void *)); /* raw free */ Xsignal_t (*signal P((int, signal_t (*)(int)))) P((int)); /* signal handler */ Xchar *mktemp P((char *)); /* make a temporary filename */ Xint unlink P((char *)); /* remove file */ Xint dup P((int)); /* duplicate handle */ Xint dup2 P((int, int)); /* duplicate handle */ Xint close P((int)); /* close handle */ X X#ifndef _MSDOS Xint wait P((wait_t *)); /* wait for child */ Xpid_t wait P((int *)); /* wait for child */ Xpid_t fork P((void)); /* fork a child */ Xint execvp P((char *, char **)); /* execute process */ X#endif X Xint getopt P((int, char **, char *)); /* get options */ Xchar *getenv P((char *)); /* get environment */ X X/* Library externals */ X Xextern char *optarg; /* option argument */ Xextern int opterr; /* error processing */ Xextern int optind; /* argc index */ X X/* Local types */ X Xtypedef struct process { X int argc; X char *argv[MAXARGS+1]; X} PROCESS; X X/* Local function prototypes */ X Xchar *getline P((FILE *)); /* read a line */ XFILE *ftemp P((char *, char **)); /* create a temporary file */ Xchar *smalloc P((unsigned int)); /* safe malloc */ Xchar *srealloc P((char *, unsigned int));/* safe realloc */ Xchar *stringdup P((char *)); /* duplicate a string */ Xint procreate P((PROCESS *, FILE *, FILE *)); /* doctors and nurses */ Xvoid appendarg P((PROCESS *, ...)); /* append an argument */ Xvoid appendlist P((PROCESS *, char **));/* append an argument vector */ Xvoid setarg P((PROCESS *, char *)); /* set arguments */ Xvoid cpppreamble P((FILE *)); /* insert cpp preamble */ Xvoid cppmaketocpp P((FILE *, FILE *)); /* cppmake to cpp */ Xvoid cpptomake P((FILE *, FILE *)); /* cpp to make */ Xsignal_t wrapup P((int)); /* signal wrapup */ Xvoid purge P((void)); /* purge temporary files */ Xvoid done P((int)); /* purge then exit */ Xvoid cat P((char *, FILE *, FILE *)); /* dump a file */ Xvoid dsync P((FILE *)); /* sync a stream */ X X/* Process descriptors */ X XPROCESS cpp = {1, {"/lib/cpp", 0}}; XPROCESS make = {1, {"make", 0}}; XPROCESS cppargs = {0, {0}}; XPROCESS makeargs = {0, {0}}; X X/* File names */ X Xchar *CppInputName = 0; /* name of cpp input */ Xchar *CppOutputName = 0; /* name of cpp output */ Xchar *MakefileName = 0; /* name of makefile */ Xchar *CppMakefileName = 0; /* name of cppmake file */ Xchar *CppMakeMake = 0; /* name of make program */ Xchar *CppMakeCpp = 0; /* name of cpp program */ X X/* Option switches */ X Xchar verbose = 0; /* verbose */ Xchar nomake = 0; /* don't start make */ Xchar compileonly = 0; /* compile only */ X X/* Main program */ X Xint main(T(int argc, argc), T(char *argv[], argv)) X XD(int argc) /* number of arguments */ XD(char *argv[]) /* argument vector */ X X{ X FILE *CppMakefile; /* cppmake file */ X FILE *CppInput; /* cpp input */ X FILE *CppOutput; /* cpp output */ X FILE *Makefile; /* makefile */ X int sw; /* option switch */ X int status; /* exit status */ X char *env; /* environment */ X char *DefineArg; /* -D argument */ X char *UndefArg; /* -U argument */ X char *IncludeArg; /* -I argument */ X char *OutfileName; /* name of output file */ X int lastopt; /* last option */ X X/* Cleanup */ X#ifdef SIGINT X if (signal(SIGINT, SIG_IGN) != SIG_IGN) X (void) signal(SIGINT, wrapup); X#endif X#ifdef SIGHUP X if (signal(SIGHUP, SIG_IGN) != SIG_IGN) X (void) signal(SIGHUP, wrapup); X#endif X#ifdef SIGQUIT X if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) X (void) signal(SIGQUIT, wrapup); X#endif X X/* Check for environment */ X if ((env = getenv("CPPMAKEMAKE")) != 0) X CppMakeMake = stringdup(env); X if ((env = getenv("CPPMAKECPP")) != 0) X CppMakeCpp = stringdup(env); X X/* Do options */ X lastopt = 1; X sw = opterr = 0; X OutfileName = 0; X while (sw != '?' && (sw = getopt(argc, argv, "o:f:D:I:U:M:C:cv")) != EOF) { X switch (sw) { X case 'v': X verbose = 1; X break; X X case 'c': X compileonly = 1; X break; X X case 'f': X CppMakefileName = optarg; X break; X X case 'M': X CppMakeMake = optarg; X break; X X case 'C': X CppMakeCpp = optarg; X break; X X case 'D': X DefineArg = smalloc((unsigned int) (strlen(optarg) + sizeof(DEFINE))); X (void) strcpy(DefineArg, DEFINE); X (void) strcat(DefineArg, optarg); X appendarg(&cppargs, DefineArg, (char *) 0); X break; X X case 'I': X IncludeArg = smalloc((unsigned int) (strlen(optarg) + sizeof(INCLUDE))); X (void) strcpy(IncludeArg, INCLUDE); X (void) strcat(IncludeArg, optarg); X appendarg(&cppargs, IncludeArg, (char *) 0); X break; X X case 'U': X UndefArg = smalloc((unsigned int) (strlen(optarg) + sizeof(UNDEF))); X (void) strcpy(UndefArg, UNDEF); X (void) strcat(UndefArg, optarg); X appendarg(&cppargs, UndefArg, (char *) 0); X break; X X case 'o': X OutfileName = optarg; X break; X X case '?': X break; X } X X if (sw != '?') X lastopt = optind; X } X X/* Move argument indicator back to last argument */ X if (optind < argc) X lastopt = optind; X X/* Set the process names */ X if (CppMakeMake != 0) X setarg(&make, CppMakeMake); X if (CppMakeCpp != 0) X setarg(&cpp, CppMakeCpp); X X/* Add cpp and make options */ X#ifdef CPPOPT X appendarg(&cpp, CPPOPT, (char *) 0); X#endif X appendlist(&cpp, &cppargs.argv[0]); X appendlist(&make, &makeargs.argv[0]); X X/* Set the name of the makefile and the name of the cppmake file */ X if (! compileonly) { X X/* Makefile name */ X if (OutfileName != 0) { X nomake = 1; X MakefileName = OutfileName; X } X X/* Cppmake file name */ X if (CppMakefileName != 0) X CppMakefile = fopen(CppMakefileName, "r"); X else { X CppMakefileName = "Makefile.cpp"; X if ((CppMakefile = fopen(CppMakefileName, "r")) == 0) { X CppMakefileName = "makefile.cpp"; X CppMakefile = fopen(CppMakefileName, "r"); X } X } X } X X/* Set the name of the cppmake file and the output file */ X else { X if (lastopt == argc && CppMakefileName == 0) { X (void) fputs("No cppmake file specified.\n", stderr); X exit(1); X } X else if (CppMakefileName == 0 && lastopt < argc-1 || X CppMakefileName != 0 && lastopt < argc) { X (void) fputs("Too many cppmake files specified.\n", stderr); X exit(1); X } X X if (CppMakefileName == 0) { X CppMakefileName = argv[lastopt]; X lastopt = argc; X } X X CppMakefile = fopen(CppMakefileName, "r"); X X if (OutfileName != 0) X CppInputName = OutfileName; X else { X if ((OutfileName = strrchr(CppMakefileName, '.')) == 0) { X (void) fprintf(stderr, "Cannot make output file name from %s.\n", X CppMakefileName); X exit(1); X } X sw = OutfileName - CppMakefileName; X CppInputName = smalloc((unsigned int) (sw+sizeof(INCFILE))); X (void) strncpy(CppInputName, CppMakefileName, sw); X (void) strcpy(CppInputName+sw, INCFILE); X } X } X X/* Check that the cppmake file is ok */ X if (CppMakefile == 0) { X (void) fputs("Cannot open makefile\n", stderr); X exit(1); X } X X/* Create the temporary files */ X if (compileonly) { X if ((CppInput = fopen(CppInputName, "w")) == 0) { X (void) fprintf(stderr, "Cannot open output file %s.\n", CppInputName); X exit(1); X } X } X else { X X/* Open the temporary files */ X CppInput = ftemp(CPPINPUT, &CppInputName); X CppOutput = ftemp(CPPOUTPUT, &CppOutputName); X if (MakefileName == 0) X Makefile = ftemp(MAKEFILE, &MakefileName); X else if ((Makefile = fopen(MakefileName, "w")) == 0) { X (void) fprintf(stderr, "Cannot open makefile %s.\n", MakefileName); X done(1); X } X X/* Insert the cpp preamble */ X cpppreamble(CppInput); X } X X/* Convert cppmake file for cpp input */ X cppmaketocpp(CppMakefile, CppInput); X dsync(CppInput); X X/* Compile only so don't erase output file */ X if (compileonly) X CppInputName = 0; X X else { X X/* Run cpp on the cpp input file */ X if (verbose) X cat("Preprocessor Input", CppInput, stderr); X if ((status = procreate(&cpp, CppInput, CppOutput)) != 0) X done(status); X dsync(CppOutput); X X/* Convert cpp output to makefile */ X if (verbose) X cat("Preprocessor Output", CppOutput, stderr); X cpptomake(CppOutput, Makefile); X dsync(Makefile); X X/* Run make on the makefile */ X if (verbose) X cat("Makefile Input", Makefile, stderr); X if (nomake) { X (void) fclose(Makefile); X MakefileName = 0; X } X else { X appendarg(&make, "-f", MakefileName, (char *) 0); X for (; lastopt < argc; lastopt++) X appendarg(&make, argv[lastopt], (char *) 0); X X if ((status = procreate(&make, stdin, stdout)) != 0) X done(status); X } X } X X/* Complete */ X done(0); X X/* Don't trust return from main on some machines */ X return 0; X} X X/* Insert cpp preamble X * X * Insert a preamble into the cpp input file. This preamble will X * provide the names of the modules that make up the cppmake file. X */ X Xvoid cpppreamble(f) X XFILE *f; /* cpp input file */ X X{ X (void) fprintf(f, "#define CPPMAKEMAKE %s\n", make.argv[0]); X (void) fprintf(f, "#define CPPMAKECPP %s\n", cpp.argv[0]); X (void) fprintf(f, "#define CPPMAKEFILE %s\n", CppMakefileName); X (void) fprintf(f, "#define CPPMAKEMAKEFILE %s\n", MakefileName); X} X X/* Change an cppmake file into a cpp input file X * X * A cppmake file is changed into a makefile. The following transformations X * are made: X * X * 1. Preprocessor lines are retained X * 2. Comments are deleted X * 3. @ is replaced by @@ except in cpp commands X * 4. ' ' is replaced by @% except in cpp commands X * 5. \t is replaced by @^ except in cpp commands X * 6. \n is replaced by @! except in cpp commands X * 7. # is replaced by @& except in cpp commands X * 8. Empty lines have @* inserted. X * 9. Leading whitespace in macros definitions are removed X */ X Xvoid cppmaketocpp(T(FILE *cppmake, cppmake), T(FILE *cpp, cpp)) X XD(FILE *cppmake) /* cppmake file */ XD(FILE *cpp) /* cpp file */ X X{ X char *lp; /* line pointer */ X char *token; /* preprocessor token */ X int toklen; /* length of token */ X char *p, *q; /* scanner */ X char *qf; /* quote from here */ X char *rp; /* replacement for quote */ X X for (; (lp = getline(cppmake)) != 0; ) { X X/* Remove makefile comments */ X for (qf = p = lp; isspace(*p); p++) X ; X X/* Comment or cpp command */ X if (*p++ == '#') { X qf = lp = p-1; X X/* Join lines by removing quoted newlines */ X for (q = p = lp; *p; p++) { X if (p[0] != '\\' || p[1] != '\n') X *q++ = *p; X else X p++; X } X *q = 0; X X/* Scan for command */ X for (p = lp + 1; isspace(*p); p++) X ; X token = p; X X for (; isalpha(*p); p++) X ; X X toklen = p - token; X X if (toklen != 0) { X X/* Define macros */ X if (strncmp("define", token, toklen) == 0) { X X/* Quote spaces and tabs within macros */ X for (; isspace(*p); p++) X ; X for (; isalnum(*p) || *p == '_'; p++) X ; X if (*p == '(') { X for (; *p && *p != ')'; p++) X ; X if (*p == ')') X p++; X } X else if (isspace(*p)) X *p++ = ' '; X X/* Note start of definition */ X q = p; X X/* Quote characters in macro definition only */ X qf = p; X X/* Kill leading spaces in macro definition */ X if (isspace(*p)) { X for (; isspace(*p); p++) X ; X for (; *p; ) X *q++ = *p++; X *q = 0; X } X } X X/* Other cpp directives are left alone */ X else if (strncmp("undef", token, toklen) == 0 || X strncmp("include", token, toklen) == 0 || X strncmp("line", token, toklen) == 0 || X strncmp("endif", token, toklen) == 0 || X strncmp("if", token, toklen) == 0 || X strncmp("else", token, toklen) == 0 || X strncmp("elsif", token, toklen) == 0 || X strncmp("ifndef", token, toklen) == 0 || X strncmp("ifdef", token, toklen) == 0) X qf = lp + strlen(lp); X } X } X X/* Quote blank lines */ X if (*lp == 0) X (void) fputs("@*\n", cpp); X X else { X/* Output the current line and */ X for (q = lp, p = qf; *p; p++) { X switch (*p) { X case '@': rp = "@@"; break; X case ' ': rp = "@%"; break; X case '\t': rp = "@^"; break; X case '\n': rp = "@!"; break; X case '#': rp = "@&"; break; X default : rp = 0; break; X } X if (rp != 0) { X (void) fwrite(q, sizeof(char), p-q, cpp); X (void) fputs(rp, cpp); X q = p + 1; X } X } X if (q < p) X (void) fwrite(q, sizeof(char), p-q, cpp); X (void) putc('\n', cpp); X } X } X} X X/* Change a cpp output file into a makefile X * X * Read the cpp output file and make the following transformations: X * X * 1. Leading spaces are removed X * 2. Lines beginning with # are discarded X * 3. @@ is converted to @ X * 4. @% is converted to ' ' X * 5. @^ is converted to \t X * 6. @! is converted to \n X * 7. @& is converted to # X * 8. @* is removed X * 9. ## and surrounding whitespace is removed X * 10. @@ in the original source is converted to \n X * 11. Trailing whitespace is removed X * 12. Blank lines are removed X */ X Xvoid cpptomake(T(FILE *cpp, cpp), T(FILE *make, make)) X XD(FILE *cpp) /* cpp output */ XD(FILE *make) /* makefile */ X X{ X char *lp; /* line */ X char *p, *q; /* line scanners */ X X for (; (lp = getline(cpp)) != 0; ) { X X/* Ignore cpp line control and empty lines */ X if (*lp == '#' || *lp == 0) X continue; X X/* Skip leading whitespace */ X for (; isspace(*lp); lp++) X ; X X/* Replace quoted characters */ X for (q = p = lp; *p; p++) { X if (p[0] != '@') X *q++ = *p; X else { X switch (p[1]) { X default: *q++ = p[0]; *q++ = p[1]; break; X case '@': *q++ = '@'; break; X case '%': *q++ = ' '; break; X case '^': *q++ = '\t'; break; X case '!': *q++ = '\n'; break; X case '&': *q++ = '#'; break; X case '*': break; X } X p++; X } X } X *q = 0; X X/* Scan original source */ X for (q = p = lp; *p; p++) { X X/* Concatenate adjacent symbols */ X if (p[0] == '#' && p[1] == '#') { X for (; q > lp; ) { X if (! isspace(*--q)) { X q++; X break; X } X } X for (p += 2; isspace(*p); p++) X ; X p--; X } X X/* Visible newline */ X else if (p[0] == '@' && p[1] == '@') { X for (; q > lp; ) { X if (! isspace(*--q)) { X q++; X break; X } X } X *q++ = '\n'; X p++; X } X X/* Default is to leave it alone */ X else X *q++ = *p; X } X X/* Eat trailing whitespace */ X for (; q > lp; ) { X if (! isspace(*--q)) { X q++; X break; X } X } X *q = 0; X X/* Output the line */ X (void) fputs(lp, make); X (void) putc('\n', make); X } X} X X/* Get a line X * X * Read a line from a stream. Return a null terminated string X * containing the line. Return null on end of file. A dynamically X * allocated static buffer is used to hold the line. Lines with X * continuation marks are joined with the continuation mark and X * the \n left intact. X */ X Xchar *getline(T(FILE *f, f)) X XD(FILE *f) /* stream */ X X{ X static char *buf; /* line buffer */ X static int buflen = 0; /* size of buffer */ X char *bp; /* buffer pointer */ X int size; /* size of buffer */ X X if (buflen == 0) { X buflen = GETLINELENGTH * sizeof(char); X buf = smalloc((unsigned int) buflen); X } X for (*(bp = buf) = 0; ; ) { X if (fgets(bp, buflen - (bp - buf), f) == 0) X break; X bp += (size = strlen(bp)); X if (bp[-1] == '\n') { X if (bp - buf == 1 || bp[-2] != '\\') { X bp[-1] = 0; X break; X } X } X if (bp - buf + 1 >= buflen) { X buflen += GETLINEINC * sizeof(char); X size = bp - buf; X buf = srealloc(buf, (unsigned int) buflen); X bp = buf + size; X } X } X return bp == buf ? 0 : buf; X} X X/* Duplicate a string X * X * Return a copy of the string. The copy is made in space malloc'ed X * for the string. X */ X Xchar *stringdup(T(char *s, s)) X XD(char *s) /* string */ X X{ X return strcpy(smalloc((unsigned int) (strlen(s)+1)), s); X} X X/* Safe malloc X * X * Malloc with error checking. X */ X Xchar *smalloc(T(unsigned int n, n)) X XD(unsigned int n) /* size of malloc */ X X{ X char *p; /* area */ X X if ((p = (char *) malloc(n)) == 0) { X (void) fputs("Insufficient memory\n", stderr); X done(1); X } X return p; X} X X/* Safe realloc X * X * Realloc and check for error. X */ X Xchar *srealloc(T(char *p, p), T(unsigned int n, n)) X XD(char *p) /* area */ XD(unsigned int n) /* size */ X X{ X if ((p = (char *) realloc((malloc_t) p, n)) == 0) { X (void) fputs("Insufficient memory\n", stderr); X done(1); X } X return p; X} X X/* Open a temporary file X * X * A temporary file is opened using the given template. The X * function returns a stream pointer to the temporary file. X */ X XFILE *ftemp(T(char *template, template), T(char **name, name)) X XD(char *template) /* name template */ XD(char **name) /* real name */ X X{ X FILE *fp; /* file */ X X for (;;) { X (void) mktemp(*name = stringdup(template)); X X if ((fp = fopen(*name, "w+")) != NULL) X return fp; X free(*name); X } X} X X/* Start a child X * X * Start a child process with the specified argument list and X * the named streams as stdin and stdout. X */ X Xint procreate(T(PROCESS *child, child), T(FILE *in, in), T(FILE *out, out)) X XD(PROCESS *child) /* arguments */ XD(FILE *in) /* input */ XD(FILE *out) /* output */ X X{ X int i; /* argv index */ X#ifdef _MSDOS X int Stdin; /* saved stdin */ X int Stdout; /* saved stdout */ X int status; /* return status */ X#else X pid_t pid; /* child id */ X wait_t status; /* child exit status */ X#endif X X if (verbose) { X (void) fprintf(stderr, "Spawning child: "); X for (i = 0; i < child->argc; i++) X (void) fprintf(stderr, "%s ", child->argv[i]); X (void) putc('\n', stderr); X } X X#ifdef _MSDOS X X if (fileno(in) != 0) { X if ((Stdin = dup(0)) < 0) { X (void) fputs("Cannot save stdin\n", stderr); X done(1); X } X if (dup2(fileno(in), 0) < 0) { X (void) fputs("Cannot set stdin\n", stderr); X done(1); X } X } X X if (fileno(out) != 1) { X if ((Stdout = dup(1)) < 0) { X (void) fputs("Cannot save stdout\n", stderr); X done(1); X } X if (dup2(fileno(out), 1) < 0) { X (void) fputs("Cannot set stdout\n", stderr); X done(1); X } X } X X status = spawnvp(P_WAIT, child->argv[0], child->argv); X X if (fileno(in) != 0) { X if (dup2(Stdin, 0) < 0) { X (void) fputs("Cannot restore stdin\n", stderr); X done(1); X } X (void) close(Stdin); X } X X if (fileno(out) != 1) { X if (dup2(Stdout, 1) < 0) { X (void) fputs("Cannot restore stdout\n", stderr); X done(1); X } X (void) close(Stdout); X } X X if (status < 0) { X (void) fprintf(stderr, "Cannot spawn %s.\n", child->argv[0]); X return 1; X } X X return status; X X#else X switch (pid = fork()) { X case -1: X (void) fprintf(stderr, "Cannot fork %s.\n", child->argv[0]); X done(1); X X case 0: X#ifdef SIGINT X if (signal(SIGINT, SIG_IGN) != SIG_IGN) X (void) signal(SIGINT, SIG_DFL); X#endif X#ifdef SIGHUP X if (signal(SIGHUP, SIG_IGN) != SIG_IGN) X (void) signal(SIGHUP, SIG_DFL); X#endif X#ifdef SIGQUIT X if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) X (void) signal(SIGQUIT, SIG_DFL); X#endif X X if ((fileno(in) != 0 && dup2(fileno(in), 0) < 0) || X (fileno(out) != 1 && dup2(fileno(out), 1) < 0)) { X (void) fputs("Cannot set stdin and stdout\n", stderr); X exit(1); X } X execvp(child->argv[0], child->argv); X (void) fprintf(stderr, "Cannot exec %s.\n", child->argv[0]); X exit(1); X X default: X do ; X while (pid != wait(&status) || WIFSTOPPED(status)); X X if (WIFSIGNALED(status)) { X (void) fprintf(stderr, "%s killed by signal %d.\n", X child->argv[0], WTERMSIG(status)); X return 1; X } X X return WEXITSTATUS(status); X } X#endif X} X X/* Append arguments to the process X * X * Add null terminated list of arguments to the list of arguments X * for the process. X */ X Xvoid appendarg(T(PROCESS *p, p), VA_ALIST) X XD(PROCESS *p) /* process */ XVA_DCL X X{ X VA_LIST ap; /* point at argument list */ X char *q; /* point at argument */ X X VA_START(ap, p); X X for (; (q = VA_ARG(ap, char *)) != 0; ) { X if (p->argc >= MAXARGS) { X (void) fprintf(stderr, "Too many arguments for %s.\n", p->argv[0]); X done(1); X } X p->argv[p->argc++] = q; X p->argv[p->argc] = 0; X } X X VA_END(ap); X} X X/* Set the arguments for a process X * X * This resets the process argument list and sets it to the X * one named in the parameter list. The parameter list will X * be scanned and separated into space separated words. Note X * that the string will be written into. X */ X Xvoid setarg(T(PROCESS *p, p), T(char *s, s)) X XD(PROCESS *p) /* process */ XD(char *s) /* arguments */ X X{ X char *a; /* point at argument */ X X p->argc = 0; X p->argv[0] = 0; X X for (;;) { X for (; isspace(*s); s++) X ; X if (*s == 0) X break; X for (a = s; *s != 0 && !isspace(*s); s++) X ; X if (*s != 0) X *s++ = 0; X appendarg(p, a, (char *) 0); X } X} X X/* Append an argument vector to the list of arguments X * X * The vector of arguments is appended to the list of X * arguments for the process. X */ X Xvoid appendlist(T(PROCESS *p, p), T(char **argv, argv)) X XD(PROCESS *p) /* process descriptor */ XD(char **argv) /* argument vector */ X X{ X for (; *argv != 0; argv++) X appendarg(p, *argv, (char *) 0); X} X X/* Wrap up with exit status X * X * Delete all temporary files and exit with the specified status. X */ X Xvoid done(T(int status, status)) X XD(int status) /* exit status */ X X{ X purge(); X exit(status); X} X X/* Wrap up X * X * Delete all temporary files and exit with error status. X */ X Xsignal_t wrapup(T(int sig, sig)) X XD(int sig) /* signal */ X X{ X sig = sig; X purge(); X exit(1); X} X X/* Remove all temporary files X * X * Check for temporary files and remove them. X */ X Xvoid purge(T(void,)) X X{ X if (CppInputName != 0) X (void) unlink(CppInputName); X if (CppOutputName != 0) X (void) unlink(CppOutputName); X if (MakefileName != 0) X (void) unlink(MakefileName); X} X X/* Cat a file X * X * Copy the named stream to the named output stream. On completion X * the input stream is rewound. X */ X Xvoid cat(T(char *name, name), T(FILE *in, in), T(FILE *out, out)) X XD(char *name) /* heading to use */ XD(FILE *in) /* input stream */ XD(FILE *out) /* output stream */ X X{ X int ch; /* copy */ X int len; /* length of name */ X int left; /* left of header */ X int right; /* right of header */ X int lastch; /* last character */ X X len = strlen(name); X left = (CATHEADERWIDTH - len) / 2; X right = CATHEADERWIDTH - len - left; X X for (len = left; len--; (void) putc('-', out)) X ; X (void) fprintf(out, " %s ", name); X for (len = right; len--; (void) putc('-', out)) X ; X (void) putc('\n', out); X X for (lastch = '\n'; (ch = getc(in)) != EOF; lastch = ch) X (void) putc(ch, out); X X if (lastch != '\n') X (void) putc('\n', out); X X for (len = left; len--; (void) putc('+', out)) X ; X (void) fprintf(out, " %s ", name); X for (len = right; len--; (void) putc('+', out)) X ; X (void) putc('\n', out); X X rewind(in); X} X X/* Synchronise disk data blocks and directory X * X * Make sure that the data in the stream has been written to X * the disk and that the directory has been updated. X */ X Xvoid dsync(T(FILE *f, f)) X XD(FILE *f) /* stream */ X X{ X#ifdef _MSDOS X int sf; /* save descriptor */ X#endif X X (void) fflush(f); X rewind(f); X X#ifdef _MSDOS X if ((sf = dup(fileno(f))) < 0) { X (void) fputs("Cannot sync file.\n", stderr); X done(1); X } X (void) close(sf); X#endif X} END_OF_FILE if test 26995 -ne `wc -c <'cppmake.c'`; then echo shar: \"'cppmake.c'\" unpacked with wrong size! fi # end of 'cppmake.c' fi echo shar: End of archive 2 \(of 2\). cp /dev/null ark2isdone MISSING="" for I in 1 2 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked both archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- Earl Chew, Dept of Computer Science, Monash University, Australia 3168 ARPA: cechew%bruce.cs.monash.oz.au@uunet.uu.net ACS : cechew@bruce.oz ----------------------------------------------------------------------