[comp.sources.amiga] v90i023: cpp - a c preprocessor with some ANSI features, Part02/05

Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator) (01/18/90)

Submitted-by: Olaf 'Rhialto' Seibert <U211344@HNYKUN11.BITNET>
Posting-number: Volume 90, Issue 023
Archive-name: unix/cpp/part02

#!/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 5)."
# Contents:  Cpp2.c Cpp3.c org/cpp.mem
# Wrapped by tadguy@xanth on Wed Jan 17 19:17:33 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Cpp2.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Cpp2.c'\"
else
echo shar: Extracting \"'Cpp2.c'\" \(17735 characters\)
sed "s/^X//" >'Cpp2.c' <<'END_OF_FILE'
X/*
X *				C P P 2 . C
X *
X *			   Process #control lines
X *
X * Edit history
X * 13-Nov-84	MM	Split from cpp1.c
X * 21-Oct-85	RMS	Do not turn on `instring' while reading #include arg.
X *			Rename `token' to `tokenbuf'.
X *			Flush tabs at end of #include line, like spaces.
X * 14-Mar-86	FNF	Incorporate macro based C debugging package.
X *			Port to Commodore AMIGA.
X * 25-May-86	FNF	Change handling of fully qualified include file
X *			pathnames (like "/usr/include/stdio.h" for unix,
X *			or "df0:include/stdio.h" for the Amiga) to be
X *			used verbatum in the first open attempt.
X * 20-Aug-88	Ois	Added #error. Passed unrecognized # commands.
X *			Added \n when those lines are passed.
X */
X
X#include	<stdio.h>
X#include	<ctype.h>
X#include	"cppdef.h"
X#include	"cpp.h"
X#if HOST == SYS_VMS
X/*
X * Include the rms stuff.  (We can't just include rms.h as it uses the
X * VaxC-specific library include syntax that Decus CPP doesn't support.
X * By including things by hand, we can CPP ourself.)
X */
X#include	<nam.h>
X#include	<fab.h>
X#include	<rab.h>
X#include	<rmsdef.h>
X#endif
X
X/*
X * Generate (by hand-inspection) a set of unique values for each control
X * operator.  Note that this is not guaranteed to work for non-Ascii
X * machines.  CPP won't compile if there are hash conflicts.
X */
X
X#define L_assert	('a' + ('s' << 1))
X#define L_define	('d' + ('f' << 1))
X#define L_elif		('e' + ('i' << 1))
X#define L_else		('e' + ('s' << 1))
X#define L_endif 	('e' + ('d' << 1))
X#define L_error 	('e' + ('r' << 1))
X#define L_if		('i' + (EOS << 1))
X#define L_ifdef 	('i' + ('d' << 1))
X#define L_ifndef	('i' + ('n' << 1))
X#define L_include	('i' + ('c' << 1))
X#define L_line		('l' + ('n' << 1))
X#define L_nogood	(EOS + (EOS << 1))      /* To catch #i          */
X#define L_pragma	('p' + ('a' << 1))
X#define L_undef 	('u' + ('d' << 1))
X#if DEBUG
X#define L_debug 	('d' + ('b' << 1))      /* #debug               */
X#define L_nodebug	('n' + ('d' << 1))      /* #nodebug             */
X#endif
X
Xint
Xcontrol(counter)
Xint		counter;	/* Pending newline counter		*/
X/*
X * Process #control lines.  Simple commands are processed inline,
X * while complex commands have their own subroutines.
X *
X * The counter is used to force out a newline before #line, and
X * #pragma commands.  This prevents these commands from ending up at
X * the end of the previous line if cpp is invoked with the -C option.
X */
X{
X	register int		c;
X	register char		*tp;
X	register int		hash;
X	char			*ep;
X
X	DBUG_ENTER ("control");
X	c = skipws();
X	if (c == '\n' || c == EOF_CHAR)
X	    DBUG_RETURN (counter + 1);
X	if (!isdigit(c))
X	    scanid(c);                  /* Get #word to tokenbuf        */
X	else {
X	    unget();                    /* Hack -- allow #123 as a      */
X	    strcpy(tokenbuf, "line");   /* synonym for #line 123        */
X	}
X	hash = (tokenbuf[1] == EOS) ? L_nogood : (tokenbuf[0] + (tokenbuf[2] << 1));
X	switch (hash) {
X	case L_assert:	tp = "assert";          break;
X	case L_define:	tp = "define";          break;
X	case L_elif:	tp = "elif";            break;
X	case L_else:	tp = "else";            break;
X	case L_endif:	tp = "endif";           break;
X	case L_error:	tp = "error";           break;
X	case L_if:	tp = "if";              break;
X	case L_ifdef:	tp = "ifdef";           break;
X	case L_ifndef:	tp = "ifndef";          break;
X	case L_include: tp = "include";         break;
X	case L_line:	tp = "line";            break;
X	case L_pragma:	tp = "pragma";          break;
X	case L_undef:	tp = "undef";           break;
X#if DEBUG
X	case L_debug:	tp = "debug";           break;
X	case L_nodebug: tp = "nodebug";         break;
X#endif
X	default:	hash = L_nogood;
X	case L_nogood:	tp = "";                break;
X	}
X	if (!streq(tp, tokenbuf))
X	    hash = L_nogood;
X	/*
X	 * hash is set to a unique value corresponding to the
X	 * control keyword (or L_nogood if we think it's nonsense).
X	 */
X	if (infile->fp == NULL)
X	    cwarn("Control line \"%s\" within macro expansion", tokenbuf);
X	if (!compiling) {                       /* Not compiling now    */
X	    switch (hash) {
X	    case L_if:				/* These can't turn     */
X	    case L_ifdef:			/*  compilation on, but */
X	    case L_ifndef:			/*   we must nest #if's */
X		if (++ifptr >= &ifstack[BLK_NEST])
X		    goto if_nest_err;
X		*ifptr = 0;			/* !WAS_COMPILING	*/
X	    case L_line:			/* Many 		*/
X	    /*
X	     * Are pragma's always processed?
X	     */
X	    case L_pragma:			/*  options		*/
X	    case L_include:			/*   are uninteresting	*/
X	    case L_define:			/*    if we		*/
X	    case L_undef:			/*     aren't           */
X	    case L_assert:			/*	compiling.	*/
X	    case L_error:
Xdump_line:	skipnl();                       /* Ignore rest of line  */
X		DBUG_RETURN (counter + 1);
X	    }
X	}
X	/*
X	 * Make sure that #line and #pragma are output on a fresh line.
X	 */
X	if (counter > 0 && (hash == L_line || hash == L_pragma)) {
X	    putchar('\n');
X	    counter--;
X	}
X	switch (hash) {
X	case L_line:
X	    /*
X	     * Parse the line to update the line number and "progname"
X	     * field and line number for the next input line.
X	     * Set wrongline to force it out later.
X	     */
X	    c = skipws();
X	    workp = work;			/* Save name in work	*/
X	    while (c != '\n' && c != EOF_CHAR) {
X		save(c);
X		c = get();
X	    }
X	    unget();
X	    save(EOS);
X	    /*
X	     * Split #line argument into <line-number> and <name>
X	     * We subtract 1 as we want the number of the next line.
X	     */
X	    line = atoi(work) - 1;              /* Reset line number    */
X	    for (tp = work; isdigit(*tp) || type[*tp] == SPA; tp++)
X		;				/* Skip over digits	*/
X	    if (*tp != EOS) {                   /* Got a filename, so:  */
X		if (*tp == '"' && (ep = strrchr(tp + 1, '"')) != NULL) {
X		    tp++;			/* Skip over left quote */
X		    *ep = EOS;			/* And ignore right one */
X		}
X		if (infile->progname != NULL)   /* Give up the old name */
X		    free(infile->progname);     /* if it's allocated.   */
X		infile->progname = savestring(tp);
X	    }
X	    wrongline = TRUE;			/* Force output later	*/
X	    break;
X
X	case L_include:
X	    doinclude();
X	    break;
X
X	case L_define:
X	    dodefine();
X	    break;
X
X	case L_undef:
X	    doundef();
X	    break;
X
X	case L_else:
X	    if (ifptr == &ifstack[0])
X		goto nest_err;
X	    else if ((*ifptr & ELSE_SEEN) != 0)
X		goto else_seen_err;
X	    *ifptr |= ELSE_SEEN;
X	    if ((*ifptr & WAS_COMPILING) != 0) {
X		if (compiling || (*ifptr & TRUE_SEEN) != 0)
X		    compiling = FALSE;
X		else {
X		    compiling = TRUE;
X		}
X	    }
X	    break;
X
X	case L_elif:
X	    if (ifptr == &ifstack[0])
X		goto nest_err;
X	    else if ((*ifptr & ELSE_SEEN) != 0) {
Xelse_seen_err:	cerror("#%s may not follow #else", tokenbuf);
X		goto dump_line;
X	    }
X	    if ((*ifptr & (WAS_COMPILING | TRUE_SEEN)) != WAS_COMPILING) {
X		compiling = FALSE;		/* Done compiling stuff */
X		goto dump_line; 		/* Skip this clause	*/
X	    }
X	    doif(L_if);
X	    break;
X
X	case L_error:
X	    cerror("#error directive encountered", NULLST);
X	    break;
X
X	case L_if:
X	case L_ifdef:
X	case L_ifndef:
X	    if (++ifptr >= &ifstack[BLK_NEST])
Xif_nest_err:	cfatal("Too many nested #%s statements", tokenbuf);
X	    *ifptr = WAS_COMPILING;
X	    doif(hash);
X	    break;
X
X	case L_endif:
X	    if (ifptr == &ifstack[0]) {
Xnest_err:	cerror("#%s must be in an #if", tokenbuf);
X		goto dump_line;
X	    }
X	    if (!compiling && (*ifptr & WAS_COMPILING) != 0)
X		wrongline = TRUE;
X	    compiling = ((*ifptr & WAS_COMPILING) != 0);
X	    --ifptr;
X	    break;
X
X	case L_assert:
X	    if (eval() == 0)
X		cerror("Preprocessor assertion failure", NULLST);
X	    break;
X
X	case L_pragma:
X	    /*
X	     * #pragma is provided to pass "options" to later
X	     * passes of the compiler.	cpp doesn't have any yet.
X	     */
X	    printf("#pragma ");
Xpass_line:
X	    while ((c = get()) != '\n' && c != EOF_CHAR)
X		cput(c);
X	    unget();
X	    cput('\n');
X	    break;
X
X#if DEBUG
X	case L_debug:
X	    if (debug == 0)
X		dumpdef("debug set on");
X	    debug++;
X	    break;
X
X	case L_nodebug:
X	    debug--;
X	    break;
X#endif
X
X	default:
X	    /*
X	     * Undefined #control keyword.
X	     * Note: the correct behavior may be to warn and
X	     * pass the line to a subsequent compiler pass.
X	     * This would allow #asm or similar extensions.
X	     */
X	    /* cerror("Illegal # command \"%s\"", tokenbuf); */
X	    printf("#%s ", tokenbuf);
X	    goto pass_line;
X	    break;
X	}
X	if (hash != L_include) {
X#if OLD_PREPROCESSOR
X	    /*
X	     * Ignore the rest of the #control line so you can write
X	     *		#if	foo
X	     *		#endif	foo
X	     */
X	    goto dump_line;			/* Take common exit	*/
X#else
X	    if (skipws() != '\n') {
X		cwarn("Unexpected text in #control line ignored", NULLST);
X		skipnl();
X	    }
X#endif
X	}
X	DBUG_RETURN (counter + 1);
X}
X
XFILE_LOCAL
Xdoif(hash)
Xint		hash;
X/*
X * Process an #if, #ifdef, or #ifndef.	The latter two are straightforward,
X * while #if needs a subroutine of its own to evaluate the expression.
X *
X * doif() is called only if compiling is TRUE.  If false, compilation
X * is always supressed, so we don't need to evaluate anything.  This
X * supresses unnecessary warnings.
X */
X{
X	register int		c;
X	register int		found;
X
X	DBUG_ENTER ("doif");
X	if ((c = skipws()) == '\n' || c == EOF_CHAR) {
X	    unget();
X	    goto badif;
X	}
X	if (hash == L_if) {
X	    unget();
X	    found = (eval() != 0);      /* Evaluate expr, != 0 is  TRUE */
X	    hash = L_ifdef;		/* #if is now like #ifdef	*/
X	}
X	else {
X	    if (type[c] != LET)         /* Next non-blank isn't letter  */
X		goto badif;		/* ... is an error		*/
X	    found = (lookid(c) != NULL); /* Look for it in symbol table */
X	}
X	if (found == (hash == L_ifdef)) {
X	    compiling = TRUE;
X	    *ifptr |= TRUE_SEEN;
X	}
X	else {
X	    compiling = FALSE;
X	}
X	DBUG_VOID_RETURN;
X
Xbadif:	cerror("#if, #ifdef, or #ifndef without an argument", NULLST);
X#if !OLD_PREPROCESSOR
X	skipnl();                               /* Prevent an extra     */
X	unget();                                /* Error message        */
X#endif
X	DBUG_VOID_RETURN;
X}
X
XFILE_LOCAL
Xdoinclude()
X/*
X * Process the #include control line.
X * There are three variations:
X *	#include "file"         search somewhere relative to the
X *				current source file, if not found,
X *				treat as #include <file>.
X *	#include <file> 	Search in an implementation-dependent
X *				list of places.
X *	#include token		Expand the token, it must be one of
X *				"file" or <file>, process as such.
X *
X * Note: the November 12 draft forbids '>' in the #include <file> format.
X * This restriction is unnecessary and not implemented.
X */
X{
X	register int		c;
X	register int		delim;
X#if HOST == SYS_VMS
X	char			def_filename[NAM$C_MAXRSS + 1];
X#endif
X
X	DBUG_ENTER ("doinclude");
X	delim = macroid(skipws());
X	if (delim != '<' && delim != '"')
X	    goto incerr;
X	if (delim == '<')
X	    delim = '>';
X	workp = work;
X	while ((c = get()) != '\n' && c != EOF_CHAR)
X	    save(c);                    /* Put it away.                 */
X	unget();                        /* Force nl after includee      */
X	/*
X	 * The draft is unclear if the following should be done.
X	 */
X	while (--workp >= work && (*workp == ' ' || *workp == '\t'))
X	    ;				/* Trim blanks from filename	*/
X	if (*workp != delim)
X	    goto incerr;
X	*workp = EOS;			/* Terminate filename		*/
X#if HOST == SYS_VMS
X	/*
X	 * Assume the default .h filetype.
X	 */
X	if (!vmsparse(work, ".H", def_filename)) {
X	    perror(work);               /* Oops.                        */
X	    goto incerr;
X	}
X	else if (openinclude(def_filename, (delim == '"')))
X	    DBUG_VOID_RETURN;
X#else
X	if (openinclude(work, (delim == '"')))
X	    DBUG_VOID_RETURN;
X#endif
X	/*
X	 * No sense continuing if #include file isn't there.
X	 */
X	cfatal("Cannot open include file \"%s\"", work);
X
Xincerr: cerror("#include syntax error", NULLST);
X	DBUG_VOID_RETURN;
X}
X
XFILE_LOCAL int
Xopeninclude(filename, searchlocal)
Xchar		*filename;		/* Input file name		*/
Xint		searchlocal;		/* TRUE if #include "file"      */
X/*
X * Actually open an include file.  This routine is only called from
X * doinclude() above, but was written as a separate subroutine for
X * programmer convenience.  It searches the list of directories
X * and actually opens the file, linking it into the list of
X * active files.  Returns TRUE if the file was opened, FALSE
X * if openinclude() fails.  No error message is printed.
X */
X{
X	register char		**incptr;
X#if HOST == SYS_VMS
X#if NWORK < (NAM$C_MAXRSS + 1)
X    << error, NWORK isn't greater than NAM$C_MAXRSS >>
X#endif
X#endif
X	char			tmpname[NWORK]; /* Filename work area	*/
X
X	DBUG_ENTER ("openinclude");
X#if HOST == SYS_UNIX
X	if ((filename[0] == '/') && openfile(filename)) {
X	    DBUG_RETURN (TRUE);
X	}
X#endif
X#if HOST == SYS_AMIGADOS
X	if ((strchr (filename, ':') != NULL) && openfile (filename)) {
X	    DBUG_RETURN (TRUE);
X	}
X#endif
X	if (searchlocal) {
X	    /*
X	     * Look in local directory first.
X	     * Try to open filename relative to the directory of the current
X	     * source file (as opposed to the current directory). (ARF, SCK).
X	     * Note that the fully qualified pathname is always built by
X	     * discarding the last pathname component of the source file
X	     * name then tacking on the #include argument.
X	     */
X	    if(hasdirectory(infile->filename, tmpname)) {
X		strcat(tmpname, filename);
X	    } else {
X		strcpy(tmpname, filename);
X	    }
X	    if (openfile(tmpname))
X		DBUG_RETURN (TRUE);
X	}
X	/*
X	 * Look in any directories specified by -I command line
X	 * arguments, then in the builtin search list.
X	 */
X	for (incptr = incdir; incptr < incend; incptr++) {
X	    if (strlen(*incptr) + strlen(filename) >= sizeof(tmpname)) {
X		cfatal("Filename work buffer overflow", NULLST);
X	    } else {
X#if HOST == SYS_UNIX			    /* Implied '/' */
X		sprintf(tmpname, "%s/%s", *incptr, filename);
X#else
X		sprintf(tmpname, "%s%s", *incptr, filename);
X#endif
X		if (openfile(tmpname))
X		    DBUG_RETURN (TRUE);
X	    }
X	}
X	DBUG_RETURN (FALSE);
X}
X
XFILE_LOCAL int
Xhasdirectory(source, result)
Xchar		*source;	/* Directory to examine 		*/
Xchar		*result;	/* Put directory stuff here		*/
X/*
X * If a device or directory is found in the source filename string, the
X * node/device/directory part of the string is copied to result and
X * hasdirectory returns TRUE.  Else, nothing is copied and it returns FALSE.
X */
X{
X#if HOST == SYS_UNIX
X	register char		*tp;
X
X	DBUG_ENTER ("hasdirectory");
X	if ((tp = strrchr(source, '/')) == NULL)
X	    DBUG_RETURN (FALSE);
X	else {
X	    strncpy(result, source, tp - source + 1);
X	    result[tp - source + 1] = EOS;
X	    DBUG_RETURN (TRUE);
X	}
X#elif HOST == SYS_AMIGADOS
X	register char		*tp1, *tp2;
X
X	DBUG_ENTER ("hasdirectory");
X
X	if ((tp1 = strrchr(source, ':')) == NULL)
X	    tp1 = source;
X	if ((tp2 = strrchr(tp1, '/')) == NULL)
X	    tp2 = tp1;
X
X	if (tp2 == source)
X	    DBUG_RETURN (FALSE);
X	else {
X	    strncpy(result, source, tp2 - source + 1);
X	    result[tp2 - source + 1] = EOS;
X	    DBUG_RETURN (TRUE);
X	}
X#elif HOST == SYS_VMS
X	DBUG_ENTER ("hasdirectory");
X	if (vmsparse(source, NULLST, result)
X	 && result[0] != EOS)
X	    DBUG_RETURN (TRUE);
X	else {
X	    DBUG_RETURN (FALSE);
X	}
X#else
X	/*
X	 * Random DEC operating system (RSX, RT11, RSTS/E)
X	 */
X	register char		*tp;
X
X		DBUG_ENTER ("hasdirectory");
X	if ((tp = strrchr(source, ']')) == NULL
X	 && (tp = strrchr(source, ':')) == NULL)
X	    DBUG_RETURN (FALSE);
X	else {
X	    strncpy(result, source, tp - source + 1);
X	    result[tp - source + 1] = EOS;
X	    DBUG_RETURN (TRUE);
X	}
X#endif
X}
X
X#if HOST == SYS_VMS
X
X/*
X * EXP_DEV is set if a device was specified, EXP_DIR if a directory
X * is specified.  (Both set indicate a file-logical, but EXP_DEV
X * would be set by itself if you are reading, say, SYS$INPUT:)
X */
X#define DEVDIR (NAM$M_EXP_DEV | NAM$M_EXP_DIR)
X
XFILE_LOCAL int
Xvmsparse(source, defstring, result)
Xchar		*source;
Xchar		*defstring;	/* non-NULL -> default string.		*/
Xchar		*result;	/* Size is at least NAM$C_MAXRSS + 1	*/
X/*
X * Parse the source string, applying the default (properly, using
X * the system parse routine), storing it in result.
X * TRUE if it parsed, FALSE on error.
X *
X * If defstring is NULL, there are no defaults and result gets
X * (just) the node::[directory] part of the string (possibly "")
X */
X{
X	struct FAB	fab = cc$rms_fab;	/* File access block	*/
X	struct NAM	nam = cc$rms_nam;	/* File name block	*/
X	char		fullname[NAM$C_MAXRSS + 1];
X	register char	*rp;			/* Result pointer	*/
X
X	DBUG_ENTER ("vmsparse");
X	fab.fab$l_nam = &nam;			/* fab -> nam		*/
X	fab.fab$l_fna = source; 		/* Source filename	*/
X	fab.fab$b_fns = strlen(source);         /* Size of source       */
X	fab.fab$l_dna = defstring;		/* Default string	*/
X	if (defstring != NULLST)
X	    fab.fab$b_dns = strlen(defstring);  /* Size of default      */
X	nam.nam$l_esa = fullname;		/* Expanded filename	*/
X	nam.nam$b_ess = NAM$C_MAXRSS;		/* Expanded name size	*/
X	if (sys$parse(&fab) == RMS$_NORMAL) {   /* Parse away           */
X	    fullname[nam.nam$b_esl] = EOS;	/* Terminate string	*/
X	    result[0] = EOS;			/* Just in case 	*/
X	    rp = &result[0];
X	    /*
X	     * Remove stuff added implicitly, accepting node names and
X	     * dev:[directory] strings (but not process-permanent files).
X	     */
X	    if ((nam.nam$l_fnb & NAM$M_PPF) == 0) {
X		if ((nam.nam$l_fnb & NAM$M_NODE) != 0) {
X		    strncpy(result, nam.nam$l_node, nam.nam$b_node);
X		    rp += nam.nam$b_node;
X		    *rp = EOS;
X		}
X		if ((nam.nam$l_fnb & DEVDIR) == DEVDIR) {
X		    strncpy(rp, nam.nam$l_dev, nam.nam$b_dev + nam.nam$b_dir);
X		    rp += nam.nam$b_dev + nam.nam$b_dir;
X		    *rp = EOS;
X		}
X	    }
X	    if (defstring != NULLST) {
X		strncpy(rp, nam.nam$l_name, nam.nam$b_name + nam.nam$b_type);
X		rp += nam.nam$b_name + nam.nam$b_type;
X		*rp = EOS;
X		if ((nam.nam$l_fnb & NAM$M_EXP_VER) != 0) {
X		    strncpy(rp, nam.nam$l_ver, nam.nam$b_ver);
X		    rp[nam.nam$b_ver] = EOS;
X		}
X	    }
X	    DBUG_RETURN (TRUE);
X	}
X	DBUG_RETURN (FALSE);
X}
X#endif
X
END_OF_FILE
if test 17735 -ne `wc -c <'Cpp2.c'`; then
    echo shar: \"'Cpp2.c'\" unpacked with wrong size!
fi
# end of 'Cpp2.c'
fi
if test -f 'Cpp3.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Cpp3.c'\"
else
echo shar: Extracting \"'Cpp3.c'\" \(14103 characters\)
sed "s/^X//" >'Cpp3.c' <<'END_OF_FILE'
X/*
X *				C P P 3 . C
X *
X *		    File open and command line options
X *
X * Edit history
X * 13-Nov-84	MM	Split from cpp1.c
X * 21-Oct-85	rms	Make -g command arg not cause an error.
X * 14-Mar-86	FNF	Incorporate macro based C debugging package.
X *			Port to the Commodore AMIGA.
X * 20-Aug-88	Ois	Added __TIME__, and changed __DATE__ to standard.
X */
X
X#include	<stdio.h>
X#include	<ctype.h>
X#include	<time.h>	/*OIS*0.92*/
X#include	"cppdef.h"
X#include	"cpp.h"
X#if DEBUG && (HOST == SYS_VMS || HOST == SYS_UNIX)
X#include	<signal.h>
Xextern int	abort();                /* For debugging                */
X#endif
X
Xint
Xopenfile(filename)
Xchar		*filename;
X/*
X * Open a file, add it to the linked list of open files.
X * This is called only from openfile() above.
X */
X{
X	register FILE		*fp;
X	extern FILE		*fopen ();
X
X	DBUG_ENTER ("openfile");
X	if ((fp = fopen(filename, "r")) == NULL) {
X#if DEBUG
X	    perror(filename);
X#endif
X	    DBUG_RETURN (FALSE);
X	}
X#if DEBUG
X	if (debug)
X	    fprintf(stderr, "Reading from \"%s\"\n", filename);
X#endif
X	addfile(fp, filename);
X	DBUG_RETURN (TRUE);
X}
X
Xaddfile(fp, filename)
XFILE		*fp;			/* Open file pointer		*/
Xchar		*filename;		/* Name of the file		*/
X/*
X * Initialize tables for this open file.  This is called from openfile()
X * above (for #include files), and from the entry to cpp to open the main
X * input file.	It calls a common routine, getfile() to build the FILEINFO
X * structure which is used to read characters.	(getfile() is also called
X * to setup a macro replacement.)
X */
X{
X	register FILEINFO	*file;
X	extern FILEINFO 	*getfile();
X
X	DBUG_ENTER ("addfile");
X	file = getfile(NBUFF, filename);
X	file->fp = fp;			/* Better remember FILE *	*/
X	file->buffer[0] = EOS;		/* Initialize for first read	*/
X	line = 1;			/* Working on line 1 now	*/
X	wrongline = TRUE;		/* Force out initial #line	*/
X	DBUG_VOID_RETURN;
X}
X
Xsetincdirs()
X/*
X * Append system-specific directories to the include directory list.
X * Called only when cpp is started.
X */
X{
X
X	DBUG_ENTER ("setincdirs");
X#ifdef	CPP_INCLUDE
X	*incend++ = CPP_INCLUDE;
X#define IS_INCLUDE	1
X#else
X#define IS_INCLUDE	0
X#endif
X
X#if HOST == SYS_UNIX
X	*incend++ = "/usr/include";
X#define MAXINCLUDE	(NINCLUDE - 1 - IS_INCLUDE)
X#endif
X
X#if HOST == SYS_AMIGADOS
X	*incend++ = "df0:include/";      /* These should be fixed. fnf */
X	*incend++ = "df1:include/";
X#define MAXINCLUDE	(NINCLUDE - 2 - IS_INCLUDE)
X#endif
X
X#if HOST == SYS_VMS
X	extern char	*getenv();
X
X	if (getenv("C$LIBRARY") != NULL)
X	    *incend++ = "C$LIBRARY:";
X	*incend++ = "SYS$LIBRARY:";
X#define MAXINCLUDE	(NINCLUDE - 2 - IS_INCLUDE)
X#endif
X
X#if HOST == SYS_RSX
X	extern int	$$rsts; 		/* TRUE on RSTS/E	*/
X	extern int	$$pos;			/* TRUE on PRO-350 P/OS */
X	extern int	$$vms;			/* TRUE on VMS compat.	*/
X
X	if ($$pos) {                            /* P/OS?                */
X	    *incend++ = "SY:[ZZDECUSC]";        /* C #includes          */
X	    *incend++ = "LB:[1,5]";             /* RSX library          */
X	}
X	else if ($$rsts) {                      /* RSTS/E?              */
X	    *incend++ = "SY:@";                 /* User-defined account */
X	    *incend++ = "C:";                   /* Decus-C library      */
X	    *incend++ = "LB:[1,1]";             /* RSX library          */
X	}
X	else if ($$vms) {                       /* VMS compatibility?   */
X	    *incend++ = "C:";
X	}
X	else {					/* Plain old RSX/IAS	*/
X	    *incend++ = "LB:[1,1]";
X	}
X#define MAXINCLUDE	(NINCLUDE - 3 - IS_INCLUDE)
X#endif
X
X#if HOST == SYS_RT11
X	extern int	$$rsts; 		/* RSTS/E emulation?	*/
X
X	if ($$rsts)
X	    *incend++ = "SY:@";                 /* User-defined account */
X	*incend++ = "C:";                       /* Decus-C library disk */
X	*incend++ = "SY:";                      /* System (boot) disk   */
X#define MAXINCLUDE	(NINCLUDE - 3 - IS_INCLUDE)
X#endif
X	DBUG_VOID_RETURN;
X}
X
Xint
Xdooptions(argc, argv)
Xint		argc;
Xchar		*argv[];
X/*
X * dooptions is called to process command line arguments (-Detc).
X * It is called only at cpp startup.
X */
X{
X	register char		*ap;
X	register DEFBUF 	*dp;
X	register int		c;
X	int			i, j;
X	char			*arg;
X	SIZES			*sizp;		/* For -S		*/
X	int			size;		/* For -S		*/
X	int			isdatum;	/* FALSE for -S*	*/
X	int			endtest;	/* For -S		*/
X
X	DBUG_ENTER ("dooptions");
X	for (i = j = 1; i < argc; i++) {
X	    arg = ap = argv[i];
X	    if (*ap++ != '-' || *ap == EOS)
X		argv[j++] = argv[i];
X	    else {
X		c = *ap++;			/* Option byte		*/
X		if (islower(c))                 /* Normalize case       */
X		    c = toupper(c);
X		switch (c) {                    /* Command character    */
X		case 'C':                       /* Keep comments        */
X		    cflag = TRUE;
X		    keepcomments = TRUE;
X		    break;
X
X		case 'D':                       /* Define symbol        */
X#if HOST != SYS_UNIX && HOST != SYS_AMIGADOS
X		    zap_uc(ap);                 /* Force define to U.C. */
X#endif
X		    /*
X		     * If the option is just "-Dfoo", make it -Dfoo=1
X		     */
X		    while (*ap != EOS && *ap != '=')
X			ap++;
X		    if (*ap == EOS)
X			ap = "1";
X		    else
X			*ap++ = EOS;
X		    /*
X		     * Now, save the word and its definition.
X		     */
X		    dp = defendel(argv[i] + 2, FALSE);
X		    dp->repl = savestring(ap);
X		    dp->nargs = DEF_NOARGS;
X		    break;
X
X		case 'E':                       /* Ignore non-fatal     */
X		    eflag = TRUE;		/* errors.		*/
X		    break;
X
X		case 'G':                       /* Cmpiler's debug switch */
X		    break;
X
X		case 'I':                       /* Include directory    */
X		    if (incend >= &incdir[MAXINCLUDE])
X			cfatal("Too many include directories", NULLST);
X		    *incend++ = ap;
X		    break;
X
X		case 'N':                       /* No predefineds       */
X		    nflag++;			/* Repeat to undefine	*/
X		    break;			/* __LINE__, etc.	*/
X
X#if OK_SIZEOF
X		case 'S':
X		    sizp = size_table;
X		    if (isdatum = (*ap != '*')) /* If it's just -S,     */
X			endtest = T_FPTR;	/* Stop here		*/
X		    else {			/* But if it's -S*      */
X			ap++;			/* Step over '*'        */
X			endtest = 0;		/* Stop at end marker	*/
X		    }
X		    while (sizp->bits != endtest && *ap != EOS) {
X			if (!isdigit(*ap)) {    /* Skip to next digit   */
X			    ap++;
X			    continue;
X			}
X			size = 0;		/* Compile the value	*/
X			while (isdigit(*ap)) {
X			    size *= 10;
X			    size += (*ap++ - '0');
X			}
X			if (isdatum)
X			    sizp->size = size;	/* Datum size		*/
X			else
X			    sizp->psize = size; /* Pointer size 	*/
X			sizp++;
X		    }
X		    if (sizp->bits != endtest)
X			cwarn("-S, too few values specified in %s", argv[i]);
X		    else if (*ap != EOS)
X			cwarn("-S, too many values, \"%s\" unused", ap);
X		    break;
X#endif /* OK_SIZEOF */
X
X		case 'U':                       /* Undefine symbol      */
X#if HOST != SYS_UNIX && HOST != SYS_AMIGADOS
X		    zap_uc(ap);
X#endif
X		    if (defendel(ap, TRUE) == NULL)
X			cwarn("\"%s\" wasn't defined", ap);
X		    break;
X		case 'W':
X		    wflag++;
X		    break;
X#if DEBUG
X		case 'X':                       /* Debug                */
X		    debug = (isdigit(*ap)) ? atoi(ap) : 1;
X#if (HOST == SYS_VMS || HOST == SYS_UNIX)
X		    signal(SIGINT, abort);      /* Trap "interrupt"     */
X#endif
X		    fprintf(stderr, "Debug set to %d\n", debug);
X		    break;
X#endif
X
X		default:			/* What is this one?	*/
X		    cwarn("Unknown option \"%s\"", arg);
Xfprintf(stderr, "The following options are valid:\n");
Xfprintf(stderr, "  -C\t\t\tWrite source file comments to output\n");
Xfprintf(stderr, "  -Dsymbol=value");
Xfprintf(stderr, "\tDefine a symbol with the given (optional) value\n");
Xfprintf(stderr, "  -Idirectory");
Xfprintf(stderr, "\t\tAdd a directory to the #include search list\n");
Xfprintf(stderr, "  -N\t\t\tDon't predefine target-specific names\n");
Xfprintf(stderr, "  -Stext\t\tSpecify sizes for #if sizeof\n");
Xfprintf(stderr, "  -Usymbol\t\tUndefine symbol\n");
X#if DEBUG
X		    fprintf(stderr, "  -Xvalue\t\tSet internal debug flag\n");
X#endif
X		    break;
X		}			/* Switch on all options	*/
X	    }				/* If it's a -option            */
X	}				/* For all arguments		*/
X	if (j > 3) {
X	    cerror(
X		"Too many file arguments.  Usage: cpp [input [output]]",
X		NULLST);
X	}
X	DBUG_RETURN (j);                        /* Return new argc              */
X}
X
X#if HOST != SYS_UNIX && HOST != SYS_AMIGADOS
XFILE_LOCAL
Xzap_uc(ap)
Xregister char	*ap;
X/*
X * Dec operating systems mangle upper-lower case in command lines.
X * This routine forces the -D and -U arguments to uppercase.
X * It is called only on cpp startup by dooptions().
X */
X{
X	DBUG_ENTER ("zap_uc");
X	while (*ap != EOS) {
X	    /*
X	     * Don't use islower() here so it works with Multinational
X	     */
X	    if (*ap >= 'a' && *ap <= 'z')
X		*ap = toupper(*ap);
X	    ap++;
X	}
X	DBUG_VOID_RETURN;
X}
X#endif
X
Xinitdefines()
X/*
X * Initialize the built-in #define's.  There are two flavors:
X *	#define decus	1		(static definitions)
X *	#define __FILE__ ??		(dynamic, evaluated by magic)
X * Called only on cpp startup.
X *
X * Note: the built-in static definitions are supressed by the -N option.
X * __LINE__, __FILE__, __TIME__ and __DATE__ are always present.
X */
X{
X	register char		**pp;
X	register char		*tp;
X	register DEFBUF 	*dp;
X	register struct tm	*tm, *localtime();
X	int			i;
X	long			tvec;
X
X	static char months[12][4] = {
X		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
X		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
X	};
X
X	DBUG_ENTER ("initdefines");
X	DBUG_2 ("defs", "initialize built in defines");
X	/*
X	 * Predefine the built-in symbols.  Allow the
X	 * implementor to pre-define a symbol as "" to
X	 * eliminate it.
X	 */
X	if (nflag == 0) {
X	    for (pp = preset; *pp != NULL; pp++) {
X		if (*pp[0] != EOS) {
X		    dp = defendel(*pp, FALSE);
X		    dp->repl = savestring("1");
X		    dp->nargs = DEF_NOARGS;
X		}
X	    }
X	}
X	/*
X	 * The magic pre-defines (__FILE__ and __LINE__ are
X	 * initialized with negative argument counts.  expand()
X	 * notices this and calls the appropriate routine.
X	 * DEF_NOARGS is one greater than the first "magic" definition.
X	 */
X	if (nflag < 2) {
X	    for (pp = magic, i = DEF_NOARGS; *pp != NULL; pp++) {
X		dp = defendel(*pp, FALSE);
X		dp->nargs = --i;
X	    }
X#if OK_DATE
X	    /*
X	     * Define __DATE__ as today's date.
X	     */
X	    dp = defendel("__DATE__", FALSE);
X	    dp->repl = tp = getmem(14);
X	    dp->nargs = DEF_NOARGS;
X	    time(&tvec);
X	    tm = localtime(&tvec);
X	    sprintf(tp, "\"%3s %2d %4d\"",      /* "Aug 20 1988" */
X		months[tm->tm_mon],
X		tm->tm_mday,
X		tm->tm_year + 1900);
X
X	    /*
X	     * Define __TIME__ as this moment's time.
X	     */
X	    dp = defendel("__TIME__", FALSE);
X	    dp->repl = tp = getmem(11);
X	    dp->nargs = DEF_NOARGS;
X	    sprintf(tp, "\"%2d:%02d:%02d\"",    /* "20:42:31" */
X		tm->tm_hour,
X		tm->tm_min,
X		tm->tm_sec);
X#endif
X	}
X	DBUG_VOID_RETURN;
X}
X
Xdeldefines()
X/*
X * Delete the built-in #define's.
X */
X{
X	register char		**pp;
X	int			i;
X
X
X	DBUG_ENTER ("deldefines");
X	DBUG_2 ("deldefs", "delete built in defines");
X	/*
X	 * Delete the built-in symbols, unless -WW.
X	 */
X	if (wflag < 2) {
X	    for (pp = preset; *pp != NULL; pp++) {
X		defendel(*pp, TRUE);
X	    }
X	}
X	/*
X	 * The magic pre-defines __FILE__ and __LINE__
X	 */
X	for (pp = magic, i = DEF_NOARGS; *pp != NULL; pp++) {
X	    defendel(*pp, TRUE);
X	}
X#if OK_DATE
X	/*
X	 * Undefine __DATE__.
X	 */
X	defendel("__DATE__", TRUE);
X
X	/*
X	 * Undefine __TIME__.
X	 */
X	defendel("__TIME__", TRUE);
X#endif
X	DBUG_VOID_RETURN;
X}
X
X#if HOST == SYS_VMS
X/*
X * getredirection() is intended to aid in porting C programs
X * to VMS (Vax-11 C) which does not support '>' and '<'
X * I/O redirection.  With suitable modification, it may
X * useful for other portability problems as well.
X */
X
Xint
Xgetredirection(argc, argv)
Xint		argc;
Xchar		**argv;
X/*
X * Process vms redirection arg's.  Exit if any error is seen.
X * If getredirection() processes an argument, it is erased
X * from the vector.  getredirection() returns a new argc value.
X *
X * Warning: do not try to simplify the code for vms.  The code
X * presupposes that getredirection() is called before any data is
X * read from stdin or written to stdout.
X *
X * Normal usage is as follows:
X *
X *	main(argc, argv)
X *	int		argc;
X *	char		*argv[];
X *	{
X *		argc = getredirection(argc, argv);
X *	}
X */
X{
X	register char		*ap;	/* Argument pointer	*/
X	int			i;	/* argv[] index 	*/
X	int			j;	/* Output index 	*/
X	int			file;	/* File_descriptor	*/
X	extern int		errno;	/* Last vms i/o error	*/
X
X	DBUG_ENTER ("getredirection");
X	for (j = i = 1; i < argc; i++) {   /* Do all arguments  */
X	    switch (*(ap = argv[i])) {
X	    case '<':                   /* <file                */
X		if (freopen(++ap, "r", stdin) == NULL) {
X		    perror(ap);         /* Can't find file      */
X		    exit(errno);        /* Is a fatal error     */
X		}
X		break;
X
X	    case '>':                   /* >file or >>file      */
X		if (*++ap == '>') {     /* >>file               */
X		    /*
X		     * If the file exists, and is writable by us,
X		     * call freopen to append to the file (using the
X		     * file's current attributes).  Otherwise, create
X		     * a new file with "vanilla" attributes as if the
X		     * argument was given as ">filename".
X		     * access(name, 2) returns zero if we can write on
X		     * the specified file.
X		     */
X		    if (access(++ap, 2) == 0) {
X			if (freopen(ap, "a", stdout) != NULL)
X			    break;	/* Exit case statement	*/
X			perror(ap);     /* Error, can't append  */
X			exit(errno);    /* After access test    */
X		    }			/* If file accessable	*/
X		}
X		/*
X		 * On vms, we want to create the file using "standard"
X		 * record attributes.  creat(...) creates the file
X		 * using the caller's default protection mask and
X		 * "variable length, implied carriage return"
X		 * attributes. dup2() associates the file with stdout.
X		 */
X		if ((file = creat(ap, 0, "rat=cr", "rfm=var")) == -1
X		 || dup2(file, fileno(stdout)) == -1) {
X		    perror(ap);         /* Can't create file    */
X		    exit(errno);        /* is a fatal error     */
X		}			/* If '>' creation      */
X		break;			/* Exit case test	*/
X
X	    default:
X		argv[j++] = ap; 	/* Not a redirector	*/
X		break;			/* Exit case test	*/
X	    }
X	}				/* For all arguments	*/
X	argv[j] = NULL; 		/* Terminate argv[]	*/
X	DBUG_RETURN (j);                /* Return new argc      */
X}
X#endif
X
X
END_OF_FILE
if test 14103 -ne `wc -c <'Cpp3.c'`; then
    echo shar: \"'Cpp3.c'\" unpacked with wrong size!
fi
# end of 'Cpp3.c'
fi
if test -f 'org/cpp.mem' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'org/cpp.mem'\"
else
echo shar: Extracting \"'org/cpp.mem'\" \(12104 characters\)
sed "s/^X//" >'org/cpp.mem' <<'END_OF_FILE'
X
X
X
X
X        1.0  C Pre-Processor
X
X
X
X                                    *******
X                                    * cpp *
X                                    *******
X
X
X
X        NAME:   cpp -- C Pre-Processor
X
X        SYNOPSIS:
X
X                cpp [-options] [infile [outfile]]
X
X        DESCRIPTION:
X
X                CPP reads a C source file, expands  macros  and  include
X                files,  and writes an input file for the C compiler.  If
X                no file arguments are given, CPP reads  from  stdin  and
X                writes  to  stdout.   If  one file argument is given, it
X                will define the input file,  while  two  file  arguments
X                define  both  input and output files.  The file name "-"
X                is a synonym for stdin or stdout as appropriate.
X
X                The following options are  supported.   Options  may  be
X                given in either case.
X
X                -C              If set, source-file comments are written
X                                to  the  output  file.   This allows the
X                                output of CPP to be used as the input to
X                                a  program,  such  as lint, that expects
X                                commands embedded in specially-formatted
X                                comments.
X
X                -Dname=value    Define the name  as  if  the  programmer
X                                wrote
X
X                                    #define name value
X
X                                at the start  of  the  first  file.   If
X                                "=value"  is  not  given, a value of "1"
X                                will be used.
X
X                                On non-unix systems, all alphabetic text
X                                will be forced to upper-case.
X
X                -E              Always return "success" to the operating
X                                system,  even  if  errors were detected.
X                                Note that some fatal errors, such  as  a
X                                missing  #include  file,  will terminate
X                                CPP, returning "failure" even if the  -E
X                                option is given.
X                                                                          Page 2
X        cpp     C Pre-Processor
X
X
X                -Idirectory     Add  this  directory  to  the  list   of
X                                directories  searched for #include "..."
X                                and #include <...> commands.  Note  that
X                                there  is  no space between the "-I" and
X                                the directory string.  More than one  -I
X                                command   is   permitted.   On  non-Unix
X                                systems   "directory"   is   forced   to
X                                upper-case.
X
X                -N              CPP  normally  predefines  some  symbols
X                                defining   the   target   computer   and
X                                operating system.  If -N  is  specified,
X                                no symbols will be predefined.  If -N -N
X                                is  specified,  the   "always   present"
X                                symbols,    __LINE__,    __FILE__,   and
X                                __DATE__ are not defined.
X
X                -Stext          CPP normally assumes that  the  size  of
X                                the  target  computer's  basic  variable
X                                types is the same as the size  of  these
X                                types  of  the host computer.  (This can
X                                be  overridden  when  CPP  is  compiled,
X                                however.)  The  -S option allows dynamic
X                                respecification of these values.  "text"
X                                is  a  string  of  numbers, separated by
X                                commas, that  specifies  correct  sizes.
X                                The sizes must be specified in the exact
X                                order:
X
X                                    char short int long float double
X
X                                If you specify the option as  "-S*text",
X                                pointers   to   these   types   will  be
X                                specified.   -S*  takes  one  additional
X                                argument  for  pointer to function (e.g.
X                                int (*)())
X
X                                For   example,    to    specify    sizes
X                                appropriate  for  a  PDP-11,  you  would
X                                write:
X
X                                       c s i l f d func
X                                     -S1,2,2,2,4,8,
X                                    -S*2,2,2,2,2,2,2
X
X                                Note that all values must be specified.
X
X                -Uname          Undefine the name as if
X
X                                    #undef name
X
X                                were given.  On non-Unix systems, "name"
X                                will be forced to upper-case.
X                                                                          Page 3
X        cpp     C Pre-Processor
X
X
X                -Xnumber        Enable debugging code.  If no  value  is
X                                given,  a value of 1 will be used.  (For
X                                maintenence of CPP only.)
X
X
X        PRE-DEFINED VARIABLES:
X
X                When CPP begins processing, the following variables will
X                have been defined (unless the -N option is specified):
X
X                Target computer (as appropriate):
X
X                    pdp11, vax, M68000 m68000 m68k
X
X                Target operating system (as appropriate):
X
X                    rsx, rt11, vms, unix
X
X                Target compiler (as appropriate):
X
X                    decus, vax11c
X
X                The implementor may add definitions to this  list.   The
X                default  definitions  match  the  definition of the host
X                computer, operating system, and C compiler.
X
X                The following are always available unless undefined  (or
X                -N was specified twice):
X
X                    __FILE__    The  input  (or  #include)  file   being
X                                compiled (as a quoted string).
X
X                    __LINE__    The line number being compiled.
X
X                    __DATE__    The date and time of  compilation  as  a
X                                Unix  ctime  quoted string (the trailing
X                                newline is removed).  Thus,
X
X                                    printf("Bug at line %s,", __LINE__);
X                                    printf(" source file %s", __FILE__);
X                                    printf(" compiled on %s", __DATE__);
X
X
X        DRAFT PROPOSED ANSI STANDARD CONSIDERATIONS:
X
X                The current  version  of  the  Draft  Proposed  Standard
X                explicitly  states  that  "readers  are requested not to
X                specify or claim conformance to this draft." Readers and
X                users  of  Decus  CPP  should  not assume that Decus CPP
X                conforms to the standard, or that it will conform to the
X                actual C Language Standard.
X
X                When CPP is itself compiled, many features of the  Draft
X                Proposed  Standard  that  are incompatible with existing
X                                                                          Page 4
X        cpp     C Pre-Processor
X
X
X                preprocessors may be  disabled.   See  the  comments  in
X                CPP's source for details.
X
X                The latest version of the Draft  Proposed  Standard  (as
X                reflected in Decus CPP) is dated November 12, 1984.
X
X                Comments are removed from the input text.   The  comment
X                is  replaced by a single space character.  The -C option
X                preserves comments, writing them to the output file.
X
X                The '$' character is considered to be a letter.  This is
X                a permitted extension.
X
X                The following new features of C are processed by CPP:
X
X                    #elif expression (#else #if)
X                    '\xNNN' (Hexadecimal constant)
X                    '\a' (Ascii BELL)
X                    '\v' (Ascii Vertical Tab)
X                    #if defined NAME 1 if defined, 0 if not
X                    #if defined (NAME) 1 if defined, 0 if not
X                    #if sizeof (basic type)
X                    unary +
X                    123U, 123LU Unsigned ints and longs.
X                    12.3L Long double numbers
X                    token#token Token concatenation
X                    #include token Expands to filename
X
X                The Draft Proposed Standard has  extended  C,  adding  a
X                constant string concatenation operator, where
X
X                    "foo" "bar"
X
X                is regarded as the single string "foobar".   (This  does
X                not  affect  CPP's  processing but does permit a limited
X                form of macro argument substitution into strings as will
X                be discussed.)
X
X                The Standard Committee plans to add token  concatenation
X                to  #define command lines.  One suggested implementation
X                is as follows:  the sequence "Token1#Token2" is  treated
X                as  if  the programmer wrote "Token1Token2".  This could
X                be used as follows:
X
X                    #line 123
X                    #define ATLINE foo#__LINE__
X
X                ATLINE would be defined as foo123.
X
X                Note that "Token2" must either have  the  format  of  an
X                identifier or be a string of digits.  Thus, the string
X
X                    #define ATLINE foo#1x3
X                                                                          Page 5
X        cpp     C Pre-Processor
X
X
X                generates two tokens:  "foo1" and "x3".
X
X                If the tokens T1 and T2 are concatenated into  T3,  this
X                implementation operates as follows:
X
X                  1. Expand T1 if it is a macro.
X                  2. Expand T2 if it is a macro.
X                  3. Join the tokens, forming T3.
X                  4. Expand T3 if it is a macro.
X
X                A macro formal parameter  will  be  substituted  into  a
X                string or character constant if it is the only component
X                of that constant:
X
X                    #define VECSIZE 123
X                    #define vprint(name, size) \
X                      printf("name" "[" "size" "] = {\n")
X                      ... vprint(vector, VECSIZE);
X
X                expands (effectively) to
X
X                      vprint("vector[123] = {\n");
X
X                Note that  this  will  be  useful  if  your  C  compiler
X                supports  the  new  string concatenation operation noted
X                above.  As implemented here, if you write
X
X                    #define string(arg) "arg"
X                      ... string("foo") ...
X
X                This implementation generates  "foo",  rather  than  the
X                strictly  correct  ""foo"" (which will probably generate
X                an error message).  This is, strictly speaking, an error
X                in CPP and may be removed from future releases.
X
X        ERROR MESSAGES:
X
X                Many.  CPP prints warning or error messages if  you  try
X                to     use     multiple-byte     character     constants
X                (non-transportable) if you #undef a symbol that was  not
X                defined,  or  if  your  program  has  potentially nested
X                comments.
X
X        AUTHOR:
X
X                Martin Minow
X
X        BUGS:
X
X                The #if expression processor uses signed integers  only.
X                I.e, #if 0xFFFFu < 0 may be TRUE.
X
END_OF_FILE
if test 12104 -ne `wc -c <'org/cpp.mem'`; then
    echo shar: \"'org/cpp.mem'\" unpacked with wrong size!
fi
# end of 'org/cpp.mem'
fi
echo shar: End of archive 2 \(of 5\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 4 5 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 5 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
-- 
Submissions to comp.sources.amiga and comp.binaries.amiga should be sent to:
	amiga@cs.odu.edu	
or	amiga@xanth.cs.odu.edu	( obsolescent mailers may need this address )
or	...!uunet!xanth!amiga	( very obsolescent mailers need this address )

Comments, questions, and suggestions s should be addressed to ``amiga-request''
(only use ``amiga'' for submissions) at the above addresses.