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
----------------------------------------------------------------------