home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!news.tek.com!master!saab!billr
- From: billr@saab.CNA.TEK.COM (Bill Randle)
- Newsgroups: comp.sources.games
- Subject: v16i005: nethack31 - display oriented dungeons & dragons (Ver. 3.1), Part05/108
- Message-ID: <4288@master.CNA.TEK.COM>
- Date: 28 Jan 93 19:10:52 GMT
- Sender: news@master.CNA.TEK.COM
- Lines: 1859
- Approved: billr@saab.CNA.TEK.COM
-
- Submitted-by: izchak@linc.cis.upenn.edu (Izchak Miller)
- Posting-number: Volume 16, Issue 5
- Archive-name: nethack31/Part05
- Supersedes: nethack3p9: Volume 10, Issue 46-102
- Environment: Amiga, Atari, Mac, MS-DOS, OS2, Unix, VMS, X11
-
-
-
- #! /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 5 (of 108)."
- # Contents: sys/amiga/colors.uu sys/unix/cpp2.shr
- # Wrapped by billr@saab on Wed Jan 27 16:08:46 1993
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'sys/amiga/colors.uu' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'sys/amiga/colors.uu'\"
- else
- echo shar: Extracting \"'sys/amiga/colors.uu'\" \(1754 characters\)
- sed "s/^X//" >'sys/amiga/colors.uu' <<'END_OF_FILE'
- Xbegin 777 colors.pw
- XM4&]W97)7:6YD;W=S('8R+C5C(*DQ.3@W+"`Q.3@X(&)Y($E.3U9!5%)/3DE#
- XM4RP@24Y#+B`@("`@("`@("`@("`@("`@("`@("`@```"[`````E```#\````
- XM`0`````!`````!%A;6EG83IC;VQO<G=I;BYC```G_A@``````H``R``"``&`
- XM```/```````D\P@```````````````(````!``````$``````0`````,H*"@
- XM````\/#PP&"0`````0`"$`X`8`)X``4`!?____\`````````````````````
- XM````````````!0`D]Z@```````5#;VQ?```!`*\`+0$=`%``!0`%_____P``
- XM`!-%9&ET(%-C<F5E;B!#;VQO<G,``"@)J``'`"0!#P`+`````P`#`"@&0```
- XM```````````````H")@````H"8#_____`P``!0`H!B0```````````$0```!
- XM$``,````#````````````0<`!P`````````````````````!`P````#_____
- XM````"@````L`)3\@`"5":``EVM``)>&0`"7B*``EXM@````(0FQU95!E;@``
- XM```!``````$`````"T=!1$),545014X``````0`````!```H"F@`!P`8`0\`
- XM"P````,``P`H"@``````````````````*`H@````*`I`_____P,```4`*`GD
- XM```````````!$````1``#`````P```````````$'``<`````````````````
- XM``````,`````_____P````H````+`"8/\``EZH``)?>(`"8:B``G:B``)VT(
- XM````"4=R965N4&5N``````$``````0`````,1T%$1U)%14Y014X``````0``
- XM```!```H"U``!P`,`0\`"P````,``P`H"L``````````````````*`K@````
- XM*`L`_____P,```4`*`JD```````````!$````1``#`````P```````````$'
- XM``<```````````````````````,`````_____P````H````+`">%6``H!2``
- XM*`9@`"@+*``H"+@`*`M`````!U)E9%!E;@`````!``````$`````"D=!1%)%
- XM1%!%3@`````!``````$``"@,>`#:`$$`.@`+`````P`!`"@+?```````*`NH
- XM````````````!@`H#`C_____`P``!0`H"XP````````````[````.P`,````
- XM#````````````P`!```&``$``````"@+R``````````'0V%N8V5L``````H`
- XM```!`"@+V``H"^@`*`PP`"@,0``H#%@`*`QH````!T-A;F-E;``````!````
- XM``$`````#4=!1$-/3$-!3D-%3``````!``````$````````(`$$`.@`+````
- XM`P`!`"@,I```````*`S0````````````!P`H#0#_____`P``!0`H#+0`````
- XM```````[````.P`,````#````````````P`!```-``$``````"@,\```````
- XM```%3VMA>0`````*`````0`H#2@`*`TX`"@-2``H#5@`*`UP`"@-@`````5/
- XG:V%Y``````$``````0`````+1T%$0T],3TM!60`````!``````$`
- X`
- Xend
- END_OF_FILE
- if test 1754 -ne `wc -c <'sys/amiga/colors.uu'`; then
- echo shar: \"'sys/amiga/colors.uu'\" unpacked with wrong size!
- fi
- # end of 'sys/amiga/colors.uu'
- fi
- if test -f 'sys/unix/cpp2.shr' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'sys/unix/cpp2.shr'\"
- else
- echo shar: Extracting \"'sys/unix/cpp2.shr'\" \(53580 characters\)
- sed "s/^X//" >'sys/unix/cpp2.shr' <<'END_OF_FILE'
- X#!/bin/sh
- X# This is a shell archive. Save it in a file, remove anything before
- X# this line, and then unpack it by entering "sh file". Note, it may
- X# create directories; files and directories will be owned by you and
- X# have default permissions.
- X#
- X# This archive contains:
- X#
- X# cpp1.c
- X# cpp3.c
- X# cpp4.c
- X#
- Xecho x - cpp1.c
- Xsed 's/^X//' >cpp1.c << 'END-of-cpp1.c'
- XX/*
- XX * CPP main program.
- XX *
- XX * Edit history
- XX * 21-May-84 MM "Field test" release
- XX * 23-May-84 MM Some minor hacks.
- XX * 30-May-84 ARF Didn't get enough memory for __DATE__
- XX * Added code to read stdin if no input
- XX * files are provided.
- XX * 29-Jun-84 MM Added ARF's suggestions, Unixifying cpp.
- XX * 11-Jul-84 MM "Official" first release (that's what I thought!)
- XX * 22-Jul-84 MM/ARF/SCK Fixed line number bugs, added cpp recognition
- XX * of #line, fixed problems with #include.
- XX * 23-Jul-84 MM More (minor) include hacking, some documentation.
- XX * Also, redid cpp's #include files
- XX * 25-Jul-84 MM #line filename isn't used for #include searchlist
- XX * #line format is <number> <optional name>
- XX * 25-Jul-84 ARF/MM Various bugs, mostly serious. Removed homemade doprint
- XX * 01-Aug-84 MM Fixed recursion bug, remove extra newlines and
- XX * leading whitespace from cpp output.
- XX * 02-Aug-84 MM Hacked (i.e. optimized) out blank lines and unneeded
- XX * whitespace in general. Cleaned up unget()'s.
- XX * 03-Aug-84 Keie Several bug fixes from Ed Keizer, Vrije Universitet.
- XX * -- corrected arg. count in -D and pre-defined
- XX * macros. Also, allow \n inside macro actual parameter
- XX * lists.
- XX * 06-Aug-84 MM If debugging, dump the preset vector at startup.
- XX * 12-Aug-84 MM/SCK Some small changes from Sam Kendall
- XX * 15-Aug-84 Keie/MM cerror, cwarn, etc. take a single string arg.
- XX * cierror, etc. take a single int. arg.
- XX * changed LINE_PREFIX slightly so it can be
- XX * changed in the makefile.
- XX * 31-Aug-84 MM USENET net.sources release.
- XX * 7-Sep-84 SCH/ado Lint complaints
- XX * 10-Sep-84 Keie Char's can't be signed in some implementations
- XX * 11-Sep-84 ado Added -C flag, pathological line number fix
- XX * 13-Sep-84 ado Added -E flag (does nothing) and "-" file for stdin.
- XX * 14-Sep-84 MM Allow # 123 as a synonym for #line 123
- XX * 19-Sep-84 MM scanid always reads to token, make sure #line is
- XX * written to a new line, even if -C switch given.
- XX * Also, cpp - - reads stdin, writes stdout.
- XX * 03-Oct-84 ado/MM Several changes to line counting and keepcomments
- XX * stuff. Also a rewritten control() hasher -- much
- XX * simpler and no less "perfect". Note also changes
- XX * in cpp3.c to fix numeric scanning.
- XX * 04-Oct-84 MM Added recognition of macro formal parameters if
- XX * they are the only thing in a string, per the
- XX * draft standard.
- XX * 08-Oct-84 MM One more attack on scannumber
- XX * 15-Oct-84 MM/ado Added -N to disable predefined symbols. Fixed
- XX * linecount if COMMENT_INVISIBLE enabled.
- XX * 22-Oct-84 MM Don't evaluate the #if/#ifdef argument if
- XX * compilation is supressed. This prevents
- XX * unnecessary error messages in sequences such as
- XX * #ifdef FOO -- undefined
- XX * #if FOO == 10 -- shouldn't print warning
- XX * 25-Oct-84 MM Fixed bug in false ifdef supression. On vms,
- XX * #include <foo> should open foo.h -- this duplicates
- XX * the behavior of Vax-C
- XX * 31-Oct-84 ado/MM Parametized $ in indentifiers. Added a better
- XX * token concatenator and took out the trial
- XX * concatenation code. Also improved #ifdef code
- XX * and cleaned up the macro recursion tester.
- XX * 2-Nov-84 MM/ado Some bug fixes in token concatenation, also
- XX * a variety of minor (uninteresting) hacks.
- XX * 6-Nov-84 MM Happy Birthday. Broke into 4 files and added
- XX * #if sizeof (basic_types)
- XX * 9-Nov-84 MM Added -S* for pointer type sizes
- XX * 13-Nov-84 MM Split cpp1.c, added vms defaulting
- XX * 23-Nov-84 MM/ado -E supresses error exit, added CPP_INCLUDE,
- XX * fixed strncpy bug.
- XX * 3-Dec-84 ado/MM Added OLD_PREPROCESSOR
- XX * 7-Dec-84 MM Stuff in Nov 12 Draft Standard
- XX * 17-Dec-84 george Fixed problems with recursive macros
- XX * 17-Dec-84 MM Yet another attack on #if's (f/t)level removed.
- XX * 07-Jan-85 ado Init defines before doing command line options
- XX * so -Uunix works.
- XX */
- XX
- XX/*)BUILD
- XX $(PROGRAM) = cpp
- XX $(FILES) = { cpp1 cpp2 cpp3 cpp4 cpp5 cpp6 }
- XX $(INCLUDE) = { cppdef.h cpp.h }
- XX $(STACK) = 2000
- XX $(TKBOPTIONS) = {
- XX STACK = 2000
- XX }
- XX*/
- XX
- XX#ifdef DOCUMENTATION
- XX
- XXtitle cpp C Pre-Processor
- XXindex C pre-processor
- XX
- XXsynopsis
- XX .s.nf
- XX cpp [-options] [infile [outfile]]
- XX .s.f
- XXdescription
- XX
- XX CPP reads a C source file, expands macros and include
- XX files, and writes an input file for the C compiler.
- XX If no file arguments are given, CPP reads from stdin
- XX and writes to stdout. If one file argument is given,
- XX it will define the input file, while two file arguments
- XX define both input and output files. The file name "-"
- XX is a synonym for stdin or stdout as appropriate.
- XX
- XX The following options are supported. Options may
- XX be given in either case.
- XX .lm +16
- XX .p -16
- XX -C If set, source-file comments are written
- XX to the output file. This allows the output of CPP to be
- XX used as the input to a program, such as lint, that expects
- XX commands embedded in specially-formatted comments.
- XX .p -16
- XX -Dname=value Define the name as if the programmer wrote
- XX
- XX #define name value
- XX
- XX at the start of the first file. If "=value" is not
- XX given, a value of "1" will be used.
- XX
- XX On non-unix systems, all alphabetic text will be forced
- XX to upper-case.
- XX .p -16
- XX -E Always return "success" to the operating
- XX system, even if errors were detected. Note that some fatal
- XX errors, such as a missing #include file, will terminate
- XX CPP, returning "failure" even if the -E option is given.
- XX .p -16
- XX -Idirectory Add this directory to the list of
- XX directories searched for #include "..." and #include <...>
- XX commands. Note that there is no space between the
- XX "-I" and the directory string. More than one -I command
- XX is permitted. On non-Unix systems "directory" is forced
- XX to upper-case.
- XX .p -16
- XX -N CPP normally predefines some symbols defining
- XX the target computer and operating system. If -N is specified,
- XX no symbols will be predefined. If -N -N is specified, the
- XX "always present" symbols, __LINE__, __FILE__, and __DATE__
- XX are not defined.
- XX .p -16
- XX -Stext CPP normally assumes that the size of
- XX the target computer's basic variable types is the same as the size
- XX of these types of the host computer. (This can be overridden
- XX when CPP is compiled, however.) The -S option allows dynamic
- XX respecification of these values. "text" is a string of
- XX numbers, separated by commas, that specifies correct sizes.
- XX The sizes must be specified in the exact order:
- XX
- XX char short int long float double
- XX
- XX If you specify the option as "-S*text", pointers to these
- XX types will be specified. -S* takes one additional argument
- XX for pointer to function (e.g. int (*)())
- XX
- XX For example, to specify sizes appropriate for a PDP-11,
- XX you would write:
- XX
- XX c s i l f d func
- XX -S1,2,2,2,4,8,
- XX -S*2,2,2,2,2,2,2
- XX
- XX Note that all values must be specified.
- XX .p -16
- XX -Uname Undefine the name as if
- XX
- XX #undef name
- XX
- XX were given. On non-Unix systems, "name" will be forced to
- XX upper-case.
- XX .p -16
- XX -Xnumber Enable debugging code. If no value is
- XX given, a value of 1 will be used. (For maintenence of
- XX CPP only.)
- XX .s.lm -16
- XX
- XXPre-Defined Variables
- XX
- XX When CPP begins processing, the following variables will
- XX have been defined (unless the -N option is specified):
- XX .s
- XX Target computer (as appropriate):
- XX .s
- XX pdp11, vax, M68000 m68000 m68k
- XX .s
- XX Target operating system (as appropriate):
- XX .s
- XX rsx, rt11, vms, unix
- XX .s
- XX Target compiler (as appropriate):
- XX .s
- XX decus, vax11c
- XX .s
- XX The implementor may add definitions to this list.
- XX The default definitions match the definition of the
- XX host computer, operating system, and C compiler.
- XX .s
- XX The following are always available unless undefined (or
- XX -N was specified twice):
- XX .lm +16
- XX .p -12
- XX __FILE__ The input (or #include) file being compiled
- XX (as a quoted string).
- XX .p -12
- XX __LINE__ The line number being compiled.
- XX .p -12
- XX __DATE__ The date and time of compilation as
- XX a Unix ctime quoted string (the trailing newline is removed).
- XX Thus,
- XX .s
- XX printf("Bug at line %s,", __LINE__);
- XX printf(" source file %s", __FILE__);
- XX printf(" compiled on %s", __DATE__);
- XX .s.lm -16
- XX
- XXDraft Proposed Ansi Standard Considerations
- XX
- XX The current version of the Draft Proposed Standard
- XX explicitly states that "readers are requested not to specify
- XX or claim conformance to this draft." Readers and users
- XX of Decus CPP should not assume that Decus CPP conforms
- XX to the standard, or that it will conform to the actual
- XX C Language Standard.
- XX
- XX When CPP is itself compiled, many features of the Draft
- XX Proposed Standard that are incompatible with existing
- XX preprocessors may be disabled. See the comments in CPP's
- XX source for details.
- XX
- XX The latest version of the Draft Proposed Standard (as reflected
- XX in Decus CPP) is dated November 12, 1984.
- XX
- XX Comments are removed from the input text. The comment
- XX is replaced by a single space character. The -C option
- XX preserves comments, writing them to the output file.
- XX
- XX The '$' character is considered to be a letter. This is
- XX a permitted extension.
- XX
- XX The following new features of C are processed by CPP:
- XX .s.comment Note: significant spaces, not tabs, .br quotes #if, #elif
- XX .br;####_#elif expression (_#else _#if)
- XX .br;####'_\xNNN' (Hexadecimal constant)
- XX .br;####'_\a' (Ascii BELL)
- XX .br;####'_\v' (Ascii Vertical Tab)
- XX .br;####_#if defined NAME 1 if defined, 0 if not
- XX .br;####_#if defined (NAME) 1 if defined, 0 if not
- XX .br;####_#if sizeof (basic type)
- XX .br;####unary +
- XX .br;####123U, 123LU Unsigned ints and longs.
- XX .br;####12.3L Long double numbers
- XX .br;####token_#token Token concatenation
- XX .br;####_#include token Expands to filename
- XX
- XX The Draft Proposed Standard has extended C, adding a constant
- XX string concatenation operator, where
- XX
- XX "foo" "bar"
- XX
- XX is regarded as the single string "foobar". (This does not
- XX affect CPP's processing but does permit a limited form of
- XX macro argument substitution into strings as will be discussed.)
- XX
- XX The Standard Committee plans to add token concatenation
- XX to #define command lines. One suggested implementation
- XX is as follows: the sequence "Token1#Token2" is treated
- XX as if the programmer wrote "Token1Token2". This could
- XX be used as follows:
- XX
- XX #line 123
- XX #define ATLINE foo#__LINE__
- XX
- XX ATLINE would be defined as foo123.
- XX
- XX Note that "Token2" must either have the format of an
- XX identifier or be a string of digits. Thus, the string
- XX
- XX #define ATLINE foo#1x3
- XX
- XX generates two tokens: "foo1" and "x3".
- XX
- XX If the tokens T1 and T2 are concatenated into T3,
- XX this implementation operates as follows:
- XX
- XX 1. Expand T1 if it is a macro.
- XX 2. Expand T2 if it is a macro.
- XX 3. Join the tokens, forming T3.
- XX 4. Expand T3 if it is a macro.
- XX
- XX A macro formal parameter will be substituted into a string
- XX or character constant if it is the only component of that
- XX constant:
- XX
- XX #define VECSIZE 123
- XX #define vprint(name, size) \
- XX printf("name" "[" "size" "] = {\n")
- XX ... vprint(vector, VECSIZE);
- XX
- XX expands (effectively) to
- XX
- XX vprint("vector[123] = {\n");
- XX
- XX Note that this will be useful if your C compiler supports
- XX the new string concatenation operation noted above.
- XX As implemented here, if you write
- XX
- XX #define string(arg) "arg"
- XX ... string("foo") ...
- XX
- XX This implementation generates "foo", rather than the strictly
- XX correct ""foo"" (which will probably generate an error message).
- XX This is, strictly speaking, an error in CPP and may be removed
- XX from future releases.
- XX
- XXerror messages
- XX
- XX Many. CPP prints warning or error messages if you try to
- XX use multiple-byte character constants (non-transportable)
- XX if you #undef a symbol that was not defined, or if your
- XX program has potentially nested comments.
- XX
- XXauthor
- XX
- XX Martin Minow
- XX
- XXbugs
- XX
- XX The #if expression processor uses signed integers only.
- XX I.e, #if 0xFFFFu < 0 may be TRUE.
- XX
- XX#endif
- XX
- XX#include <stdio.h>
- XX#include <ctype.h>
- XX#include "cppdef.h"
- XX#include "cpp.h"
- XX
- XX/*
- XX * Commonly used global variables:
- XX * line is the current input line number.
- XX * wrongline is set in many places when the actual output
- XX * line is out of sync with the numbering, e.g,
- XX * when expanding a macro with an embedded newline.
- XX *
- XX * token holds the last identifier scanned (which might
- XX * be a candidate for macro expansion).
- XX * errors is the running cpp error counter.
- XX * infile is the head of a linked list of input files (extended by
- XX * #include and macros being expanded). infile always points
- XX * to the current file/macro. infile->parent to the includer,
- XX * etc. infile->fd is NULL if this input stream is a macro.
- XX */
- XXint line; /* Current line number */
- XXint wrongline; /* Force #line to compiler */
- XXchar token[IDMAX + 1]; /* Current input token */
- XXint errors; /* cpp error counter */
- XXFILEINFO *infile = NULL; /* Current input file */
- XX#if DEBUG
- XXint debug; /* TRUE if debugging now */
- XX#endif
- XX/*
- XX * This counter is incremented when a macro expansion is initiated.
- XX * If it exceeds a built-in value, the expansion stops -- this tests
- XX * for a runaway condition:
- XX * #define X Y
- XX * #define Y X
- XX * X
- XX * This can be disabled by falsifying rec_recover. (Nothing does this
- XX * currently: it is a hook for an eventual invocation flag.)
- XX */
- XXint recursion; /* Infinite recursion counter */
- XXint rec_recover = TRUE; /* Unwind recursive macros */
- XX
- XX/*
- XX * instring is set TRUE when a string is scanned. It modifies the
- XX * behavior of the "get next character" routine, causing all characters
- XX * to be passed to the caller (except <DEF_MAGIC>). Note especially that
- XX * comments and \<newline> are not removed from the source. (This
- XX * prevents cpp output lines from being arbitrarily long).
- XX *
- XX * inmacro is set by #define -- it absorbs comments and converts
- XX * form-feed and vertical-tab to space, but returns \<newline>
- XX * to the caller. Strictly speaking, this is a bug as \<newline>
- XX * shouldn't delimit tokens, but we'll worry about that some other
- XX * time -- it is more important to prevent infinitly long output lines.
- XX *
- XX * instring and inmarcor are parameters to the get() routine which
- XX * were made global for speed.
- XX */
- XXint instring = FALSE; /* TRUE if scanning string */
- XXint inmacro = FALSE; /* TRUE if #defining a macro */
- XX
- XX/*
- XX * work[] and workp are used to store one piece of text in a temporay
- XX * buffer. To initialize storage, set workp = work. To store one
- XX * character, call save(c); (This will fatally exit if there isn't
- XX * room.) To terminate the string, call save(EOS). Note that
- XX * the work buffer is used by several subroutines -- be sure your
- XX * data won't be overwritten. The extra byte in the allocation is
- XX * needed for string formal replacement.
- XX */
- XXchar work[NWORK + 1]; /* Work buffer */
- XXchar *workp; /* Work buffer pointer */
- XX
- XX/*
- XX * keepcomments is set TRUE by the -C option. If TRUE, comments
- XX * are written directly to the output stream. This is needed if
- XX * the output from cpp is to be passed to lint (which uses commands
- XX * embedded in comments). cflag contains the permanent state of the
- XX * -C flag. keepcomments is always falsified when processing #control
- XX * commands and when compilation is supressed by a false #if
- XX *
- XX * If eflag is set, CPP returns "success" even if non-fatal errors
- XX * were detected.
- XX *
- XX * If nflag is non-zero, no symbols are predefined except __LINE__.
- XX * __FILE__, and __DATE__. If nflag > 1, absolutely no symbols
- XX * are predefined.
- XX */
- XXint keepcomments = FALSE; /* Write out comments flag */
- XXint cflag = FALSE; /* -C option (keep comments) */
- XXint eflag = FALSE; /* -E option (never fail) */
- XXint nflag = 0; /* -N option (no predefines) */
- XX
- XX/*
- XX * ifstack[] holds information about nested #if's. It is always
- XX * accessed via *ifptr. The information is as follows:
- XX * WAS_COMPILING state of compiling flag at outer level.
- XX * ELSE_SEEN set TRUE when #else seen to prevent 2nd #else.
- XX * TRUE_SEEN set TRUE when #if or #elif succeeds
- XX * ifstack[0] holds the compiling flag. It is TRUE if compilation
- XX * is currently enabled. Note that this must be initialized TRUE.
- XX */
- XXchar ifstack[BLK_NEST] = { TRUE }; /* #if information */
- XXchar *ifptr = ifstack; /* -> current ifstack[] */
- XX
- XX/*
- XX * incdir[] stores the -i directories (and the system-specific
- XX * #include <...> directories.
- XX */
- XXchar *incdir[NINCLUDE]; /* -i directories */
- XXchar **incend = incdir; /* -> free space in incdir[] */
- XX
- XX/*
- XX * This is the table used to predefine target machine and operating
- XX * system designators. It may need hacking for specific circumstances.
- XX * Note: it is not clear that this is part of the Ansi Standard.
- XX * The -N option supresses preset definitions.
- XX */
- XXchar *preset[] = { /* names defined at cpp start */
- XX#ifdef MACHINE
- XX MACHINE,
- XX#endif
- XX#ifdef SYSTEM
- XX SYSTEM,
- XX#endif
- XX#ifdef COMPILER
- XX COMPILER,
- XX#endif
- XX#if DEBUG
- XX "decus_cpp", /* Ourselves! */
- XX#endif
- XX NULL /* Must be last */
- XX};
- XX
- XX/*
- XX * The value of these predefined symbols must be recomputed whenever
- XX * they are evaluated. The order must not be changed.
- XX */
- XXchar *magic[] = { /* Note: order is important */
- XX "__LINE__",
- XX "__FILE__",
- XX NULL /* Must be last */
- XX};
- XX
- XXmain(argc, argv)
- XXint argc;
- XXchar *argv[];
- XX{
- XX register int i;
- XX
- XX#if HOST == SYS_VMS
- XX argc = getredirection(argc, argv); /* vms >file and <file */
- XX#endif
- XX initdefines(); /* O.S. specific def's */
- XX i = dooptions(argc, argv); /* Command line -flags */
- XX switch (i) {
- XX case 3:
- XX /*
- XX * Get output file, "-" means use stdout.
- XX */
- XX if (!streq(argv[2], "-")) {
- XX#if HOST == SYS_VMS
- XX /*
- XX * On vms, reopen stdout with "vanilla rms" attributes.
- XX */
- XX if ((i = creat(argv[2], 0, "rat=cr", "rfm=var")) == -1
- XX || dup2(i, fileno(stdout)) == -1) {
- XX#else
- XX if (freopen(argv[2], "w", stdout) == NULL) {
- XX#endif
- XX perror(argv[2]);
- XX cerror("Can't open output file \"%s\"", argv[2]);
- XX exit(IO_ERROR);
- XX }
- XX } /* Continue by opening input */
- XX case 2: /* One file -> stdin */
- XX /*
- XX * Open input file, "-" means use stdin.
- XX */
- XX if (!streq(argv[1], "-")) {
- XX if (freopen(argv[1], "r", stdin) == NULL) {
- XX perror(argv[1]);
- XX cerror("Can't open input file \"%s\"", argv[1]);
- XX exit(IO_ERROR);
- XX }
- XX strcpy(work, argv[1]); /* Remember input filename */
- XX break;
- XX } /* Else, just get stdin */
- XX case 0: /* No args? */
- XX case 1: /* No files, stdin -> stdout */
- XX#if HOST == SYS_UNIX
- XX work[0] = EOS; /* Unix can't find stdin name */
- XX#else
- XX fgetname(stdin, work); /* Vax-11C, Decus C know name */
- XX#endif
- XX break;
- XX
- XX default:
- XX exit(IO_ERROR); /* Can't happen */
- XX }
- XX setincdirs(); /* Setup -I include directories */
- XX addfile(stdin, work); /* "open" main input file */
- XX#if DEBUG
- XX if (debug > 0)
- XX dumpdef("preset #define symbols");
- XX#endif
- XX cppmain(); /* Process main file */
- XX if ((i = (ifptr - &ifstack[0])) != 0) {
- XX#if OLD_PREPROCESSOR
- XX ciwarn("Inside #ifdef block at end of input, depth = %d", i);
- XX#else
- XX cierror("Inside #ifdef block at end of input, depth = %d", i);
- XX#endif
- XX }
- XX fclose(stdout);
- XX if (errors > 0) {
- XX fprintf(stderr, (errors == 1)
- XX ? "%d error in preprocessor\n"
- XX : "%d errors in preprocessor\n", errors);
- XX if (!eflag)
- XX exit(IO_ERROR);
- XX }
- XX exit(IO_NORMAL); /* No errors or -E option set */
- XX}
- XX
- XXFILE_LOCAL
- XXcppmain()
- XX/*
- XX * Main process for cpp -- copies tokens from the current input
- XX * stream (main file, include file, or a macro) to the output
- XX * file.
- XX */
- XX{
- XX register int c; /* Current character */
- XX register int counter; /* newlines and spaces */
- XX extern int output(); /* Output one character */
- XX
- XX /*
- XX * Explicitly output a #line at the start of cpp output so
- XX * that lint (etc.) knows the name of the original source
- XX * file. If we don't do this explicitly, we may get
- XX * the name of the first #include file instead.
- XX */
- XX sharp();
- XX /*
- XX * This loop is started "from the top" at the beginning of each line
- XX * wrongline is set TRUE in many places if it is necessary to write
- XX * a #line record. (But we don't write them when expanding macros.)
- XX *
- XX * The counter variable has two different uses: at
- XX * the start of a line, it counts the number of blank lines that
- XX * have been skipped over. These are then either output via
- XX * #line records or by outputting explicit blank lines.
- XX * When expanding tokens within a line, the counter remembers
- XX * whether a blank/tab has been output. These are dropped
- XX * at the end of the line, and replaced by a single blank
- XX * within lines.
- XX */
- XX for (;;) {
- XX counter = 0; /* Count empty lines */
- XX for (;;) { /* For each line, ... */
- XX while (type[(c = get())] == SPA) /* Skip leading blanks */
- XX ; /* in this line. */
- XX if (c == '\n') /* If line's all blank, */
- XX ++counter; /* Do nothing now */
- XX else if (c == '#') { /* Is 1st non-space '#' */
- XX keepcomments = FALSE; /* Don't pass comments */
- XX counter = control(counter); /* Yes, do a #command */
- XX keepcomments = (cflag && compiling);
- XX }
- XX else if (c == EOF_CHAR) /* At end of file? */
- XX break;
- XX else if (!compiling) { /* #ifdef false? */
- XX skipnl(); /* Skip to newline */
- XX counter++; /* Count it, too. */
- XX }
- XX else {
- XX break; /* Actual token */
- XX }
- XX }
- XX if (c == EOF_CHAR) /* Exit process at */
- XX break; /* End of file */
- XX /*
- XX * If the loop didn't terminate because of end of file, we
- XX * know there is a token to compile. First, clean up after
- XX * absorbing newlines. counter has the number we skipped.
- XX */
- XX if ((wrongline && infile->fp != NULL) || counter > 4)
- XX sharp(); /* Output # line number */
- XX else { /* If just a few, stuff */
- XX while (--counter >= 0) /* them out ourselves */
- XX putchar('\n');
- XX }
- XX /*
- XX * Process each token on this line.
- XX */
- XX unget(); /* Reread the char. */
- XX for (;;) { /* For the whole line, */
- XX do { /* Token concat. loop */
- XX for (counter = 0; (type[(c = get())] == SPA);) {
- XX#if COMMENT_INVISIBLE
- XX if (c != COM_SEP)
- XX counter++;
- XX#else
- XX counter++; /* Skip over blanks */
- XX#endif
- XX }
- XX if (c == EOF_CHAR || c == '\n')
- XX goto end_line; /* Exit line loop */
- XX else if (counter > 0) /* If we got any spaces */
- XX putchar(' '); /* Output one space */
- XX c = macroid(c); /* Grab the token */
- XX } while (type[c] == LET && catenate());
- XX if (c == EOF_CHAR || c == '\n') /* From macro exp error */
- XX goto end_line; /* Exit line loop */
- XX switch (type[c]) {
- XX case LET:
- XX fputs(token, stdout); /* Quite ordinary token */
- XX break;
- XX
- XX
- XX case DIG: /* Output a number */
- XX case DOT: /* Dot may begin floats */
- XX scannumber(c, output);
- XX break;
- XX
- XX case QUO: /* char or string const */
- XX scanstring(c, output); /* Copy it to output */
- XX break;
- XX
- XX default: /* Some other character */
- XX cput(c); /* Just output it */
- XX break;
- XX } /* Switch ends */
- XX } /* Line for loop */
- XXend_line: if (c == '\n') { /* Compiling at EOL? */
- XX putchar('\n'); /* Output newline, if */
- XX if (infile->fp == NULL) /* Expanding a macro, */
- XX wrongline = TRUE; /* Output # line later */
- XX }
- XX } /* Continue until EOF */
- XX}
- XX
- XXoutput(c)
- XXint c;
- XX/*
- XX * Output one character to stdout -- output() is passed as an
- XX * argument to scanstring()
- XX */
- XX{
- XX#if COMMENT_INVISIBLE
- XX if (c != TOK_SEP && c != COM_SEP)
- XX#else
- XX if (c != TOK_SEP)
- XX#endif
- XX putchar(c);
- XX}
- XX
- XXstatic char *sharpfilename = NULL;
- XX
- XXFILE_LOCAL
- XXsharp()
- XX/*
- XX * Output a line number line.
- XX */
- XX{
- XX register char *name;
- XX
- XX if (keepcomments) /* Make sure # comes on */
- XX putchar('\n'); /* a fresh, new line. */
- XX printf("#%s %d", LINE_PREFIX, line);
- XX if (infile->fp != NULL) {
- XX name = (infile->progname != NULL)
- XX ? infile->progname : infile->filename;
- XX if (sharpfilename == NULL
- XX || sharpfilename != NULL && !streq(name, sharpfilename)) {
- XX if (sharpfilename != NULL)
- XX free(sharpfilename);
- XX sharpfilename = savestring(name);
- XX printf(" \"%s\"", name);
- XX }
- XX }
- XX putchar('\n');
- XX wrongline = FALSE;
- XX}
- XEND-of-cpp1.c
- Xecho x - cpp3.c
- Xsed 's/^X//' >cpp3.c << 'END-of-cpp3.c'
- XX/*
- XX * C P P 3 . C
- XX *
- XX * File open and command line options
- XX *
- XX * Edit history
- XX * 13-Nov-84 MM Split from cpp1.c
- XX */
- XX
- XX#include <stdio.h>
- XX#include <ctype.h>
- XX#include "cppdef.h"
- XX#include "cpp.h"
- XX#if DEBUG && (HOST == SYS_VMS || HOST == SYS_UNIX)
- XX#include <signal.h>
- XXextern int abort(); /* For debugging */
- XX#endif
- XX
- XXint
- XXopenfile(filename)
- XXchar *filename;
- XX/*
- XX * Open a file, add it to the linked list of open files.
- XX * This is called only from openfile() above.
- XX */
- XX{
- XX register FILE *fp;
- XX
- XX if ((fp = fopen(filename, "r")) == NULL) {
- XX#if DEBUG
- XX perror(filename);
- XX#endif
- XX return (FALSE);
- XX }
- XX#if DEBUG
- XX if (debug)
- XX fprintf(stderr, "Reading from \"%s\"\n", filename);
- XX#endif
- XX addfile(fp, filename);
- XX return (TRUE);
- XX}
- XX
- XXaddfile(fp, filename)
- XXFILE *fp; /* Open file pointer */
- XXchar *filename; /* Name of the file */
- XX/*
- XX * Initialize tables for this open file. This is called from openfile()
- XX * above (for #include files), and from the entry to cpp to open the main
- XX * input file. It calls a common routine, getfile() to build the FILEINFO
- XX * structure which is used to read characters. (getfile() is also called
- XX * to setup a macro replacement.)
- XX */
- XX{
- XX register FILEINFO *file;
- XX extern FILEINFO *getfile();
- XX
- XX file = getfile(NBUFF, filename);
- XX file->fp = fp; /* Better remember FILE * */
- XX file->buffer[0] = EOS; /* Initialize for first read */
- XX line = 1; /* Working on line 1 now */
- XX wrongline = TRUE; /* Force out initial #line */
- XX}
- XX
- XXsetincdirs()
- XX/*
- XX * Append system-specific directories to the include directory list.
- XX * Called only when cpp is started.
- XX */
- XX{
- XX
- XX#ifdef CPP_INCLUDE
- XX *incend++ = CPP_INCLUDE;
- XX#define IS_INCLUDE 1
- XX#else
- XX#define IS_INCLUDE 0
- XX#endif
- XX
- XX#if HOST == SYS_UNIX
- XX *incend++ = "/usr/include";
- XX#define MAXINCLUDE (NINCLUDE - 1 - IS_INCLUDE)
- XX#endif
- XX
- XX#if HOST == SYS_VMS
- XX extern char *getenv();
- XX
- XX if (getenv("C$LIBRARY") != NULL)
- XX *incend++ = "C$LIBRARY:";
- XX *incend++ = "SYS$LIBRARY:";
- XX#define MAXINCLUDE (NINCLUDE - 2 - IS_INCLUDE)
- XX#endif
- XX
- XX#if HOST == SYS_RSX
- XX extern int $$rsts; /* TRUE on RSTS/E */
- XX extern int $$pos; /* TRUE on PRO-350 P/OS */
- XX extern int $$vms; /* TRUE on VMS compat. */
- XX
- XX if ($$pos) { /* P/OS? */
- XX *incend++ = "SY:[ZZDECUSC]"; /* C #includes */
- XX *incend++ = "LB:[1,5]"; /* RSX library */
- XX }
- XX else if ($$rsts) { /* RSTS/E? */
- XX *incend++ = "SY:@"; /* User-defined account */
- XX *incend++ = "C:"; /* Decus-C library */
- XX *incend++ = "LB:[1,1]"; /* RSX library */
- XX }
- XX else if ($$vms) { /* VMS compatibility? */
- XX *incend++ = "C:";
- XX }
- XX else { /* Plain old RSX/IAS */
- XX *incend++ = "LB:[1,1]";
- XX }
- XX#define MAXINCLUDE (NINCLUDE - 3 - IS_INCLUDE)
- XX#endif
- XX
- XX#if HOST == SYS_RT11
- XX extern int $$rsts; /* RSTS/E emulation? */
- XX
- XX if ($$rsts)
- XX *incend++ = "SY:@"; /* User-defined account */
- XX *incend++ = "C:"; /* Decus-C library disk */
- XX *incend++ = "SY:"; /* System (boot) disk */
- XX#define MAXINCLUDE (NINCLUDE - 3 - IS_INCLUDE)
- XX#endif
- XX}
- XX
- XXint
- XXdooptions(argc, argv)
- XXint argc;
- XXchar *argv[];
- XX/*
- XX * dooptions is called to process command line arguments (-Detc).
- XX * It is called only at cpp startup.
- XX */
- XX{
- XX register char *ap;
- XX register DEFBUF *dp;
- XX register int c;
- XX int i, j;
- XX char *arg;
- XX SIZES *sizp; /* For -S */
- XX int size; /* For -S */
- XX int isdatum; /* FALSE for -S* */
- XX int endtest; /* For -S */
- XX
- XX for (i = j = 1; i < argc; i++) {
- XX arg = ap = argv[i];
- XX if (*ap++ != '-' || *ap == EOS)
- XX argv[j++] = argv[i];
- XX else {
- XX c = *ap++; /* Option byte */
- XX if (islower(c)) /* Normalize case */
- XX c = toupper(c);
- XX switch (c) { /* Command character */
- XX case 'C': /* Keep comments */
- XX cflag = TRUE;
- XX keepcomments = TRUE;
- XX break;
- XX
- XX case 'D': /* Define symbol */
- XX#if HOST != SYS_UNIX
- XX zap_uc(ap); /* Force define to U.C. */
- XX#endif
- XX /*
- XX * If the option is just "-Dfoo", make it -Dfoo=1
- XX */
- XX while (*ap != EOS && *ap != '=')
- XX ap++;
- XX if (*ap == EOS)
- XX ap = "1";
- XX else
- XX *ap++ = EOS;
- XX /*
- XX * Now, save the word and its definition.
- XX */
- XX dp = defendel(argv[i] + 2, FALSE);
- XX dp->repl = savestring(ap);
- XX dp->nargs = DEF_NOARGS;
- XX break;
- XX
- XX case 'E': /* Ignore non-fatal */
- XX eflag = TRUE; /* errors. */
- XX break;
- XX
- XX case 'I': /* Include directory */
- XX if (incend >= &incdir[MAXINCLUDE])
- XX cfatal("Too many include directories", NULLST);
- XX *incend++ = ap;
- XX break;
- XX
- XX case 'N': /* No predefineds */
- XX nflag++; /* Repeat to undefine */
- XX break; /* __LINE__, etc. */
- XX
- XX case 'S':
- XX sizp = size_table;
- XX if (isdatum = (*ap != '*')) /* If it's just -S, */
- XX endtest = T_FPTR; /* Stop here */
- XX else { /* But if it's -S* */
- XX ap++; /* Step over '*' */
- XX endtest = 0; /* Stop at end marker */
- XX }
- XX while (sizp->bits != endtest && *ap != EOS) {
- XX if (!isdigit(*ap)) { /* Skip to next digit */
- XX ap++;
- XX continue;
- XX }
- XX size = 0; /* Compile the value */
- XX while (isdigit(*ap)) {
- XX size *= 10;
- XX size += (*ap++ - '0');
- XX }
- XX if (isdatum)
- XX sizp->size = size; /* Datum size */
- XX else
- XX sizp->psize = size; /* Pointer size */
- XX sizp++;
- XX }
- XX if (sizp->bits != endtest)
- XX cwarn("-S, too few values specified in %s", argv[i]);
- XX else if (*ap != EOS)
- XX cwarn("-S, too many values, \"%s\" unused", ap);
- XX break;
- XX
- XX case 'U': /* Undefine symbol */
- XX#if HOST != SYS_UNIX
- XX zap_uc(ap);
- XX#endif
- XX if (defendel(ap, TRUE) == NULL)
- XX cwarn("\"%s\" wasn't defined", ap);
- XX break;
- XX
- XX#if DEBUG
- XX case 'X': /* Debug */
- XX debug = (isdigit(*ap)) ? atoi(ap) : 1;
- XX#if (HOST == SYS_VMS || HOST == SYS_UNIX)
- XX signal(SIGINT, abort); /* Trap "interrupt" */
- XX#endif
- XX fprintf(stderr, "Debug set to %d\n", debug);
- XX break;
- XX#endif
- XX
- XX default: /* What is this one? */
- XX cwarn("Unknown option \"%s\"", arg);
- XX fprintf(stderr, "The following options are valid:\n\
- XX -C\t\t\tWrite source file comments to output\n\
- XX -Dsymbol=value\tDefine a symbol with the given (optional) value\n\
- XX -Idirectory\t\tAdd a directory to the #include search list\n\
- XX -N\t\t\tDon't predefine target-specific names\n\
- XX -Stext\t\tSpecify sizes for #if sizeof\n\
- XX -Usymbol\t\tUndefine symbol\n");
- XX#if DEBUG
- XX fprintf(stderr, " -Xvalue\t\tSet internal debug flag\n");
- XX#endif
- XX break;
- XX } /* Switch on all options */
- XX } /* If it's a -option */
- XX } /* For all arguments */
- XX if (j > 3) {
- XX cerror(
- XX "Too many file arguments. Usage: cpp [input [output]]",
- XX NULLST);
- XX }
- XX return (j); /* Return new argc */
- XX}
- XX
- XX#if HOST != SYS_UNIX
- XXFILE_LOCAL
- XXzap_uc(ap)
- XXregister char *ap;
- XX/*
- XX * Dec operating systems mangle upper-lower case in command lines.
- XX * This routine forces the -D and -U arguments to uppercase.
- XX * It is called only on cpp startup by dooptions().
- XX */
- XX{
- XX while (*ap != EOS) {
- XX /*
- XX * Don't use islower() here so it works with Multinational
- XX */
- XX if (*ap >= 'a' && *ap <= 'z')
- XX *ap = toupper(*ap);
- XX ap++;
- XX }
- XX}
- XX#endif
- XX
- XXinitdefines()
- XX/*
- XX * Initialize the built-in #define's. There are two flavors:
- XX * #define decus 1 (static definitions)
- XX * #define __FILE__ ?? (dynamic, evaluated by magic)
- XX * Called only on cpp startup.
- XX *
- XX * Note: the built-in static definitions are supressed by the -N option.
- XX * __LINE__, __FILE__, and __DATE__ are always present.
- XX */
- XX{
- XX register char **pp;
- XX register char *tp;
- XX register DEFBUF *dp;
- XX int i;
- XX long tvec;
- XX extern char *ctime();
- XX
- XX /*
- XX * Predefine the built-in symbols. Allow the
- XX * implementor to pre-define a symbol as "" to
- XX * eliminate it.
- XX */
- XX if (nflag == 0) {
- XX for (pp = preset; *pp != NULL; pp++) {
- XX if (*pp[0] != EOS) {
- XX dp = defendel(*pp, FALSE);
- XX dp->repl = savestring("1");
- XX dp->nargs = DEF_NOARGS;
- XX }
- XX }
- XX }
- XX /*
- XX * The magic pre-defines (__FILE__ and __LINE__ are
- XX * initialized with negative argument counts. expand()
- XX * notices this and calls the appropriate routine.
- XX * DEF_NOARGS is one greater than the first "magic" definition.
- XX */
- XX if (nflag < 2) {
- XX for (pp = magic, i = DEF_NOARGS; *pp != NULL; pp++) {
- XX dp = defendel(*pp, FALSE);
- XX dp->nargs = --i;
- XX }
- XX#if OK_DATE
- XX /*
- XX * Define __DATE__ as today's date.
- XX */
- XX dp = defendel("__DATE__", FALSE);
- XX dp->repl = tp = getmem(27);
- XX dp->nargs = DEF_NOARGS;
- XX time(&tvec);
- XX *tp++ = '"';
- XX strcpy(tp, ctime(&tvec));
- XX tp[24] = '"'; /* Overwrite newline */
- XX#endif
- XX }
- XX}
- XX
- XX#if HOST == SYS_VMS
- XX/*
- XX * getredirection() is intended to aid in porting C programs
- XX * to VMS (Vax-11 C) which does not support '>' and '<'
- XX * I/O redirection. With suitable modification, it may
- XX * useful for other portability problems as well.
- XX */
- XX
- XXint
- XXgetredirection(argc, argv)
- XXint argc;
- XXchar **argv;
- XX/*
- XX * Process vms redirection arg's. Exit if any error is seen.
- XX * If getredirection() processes an argument, it is erased
- XX * from the vector. getredirection() returns a new argc value.
- XX *
- XX * Warning: do not try to simplify the code for vms. The code
- XX * presupposes that getredirection() is called before any data is
- XX * read from stdin or written to stdout.
- XX *
- XX * Normal usage is as follows:
- XX *
- XX * main(argc, argv)
- XX * int argc;
- XX * char *argv[];
- XX * {
- XX * argc = getredirection(argc, argv);
- XX * }
- XX */
- XX{
- XX register char *ap; /* Argument pointer */
- XX int i; /* argv[] index */
- XX int j; /* Output index */
- XX int file; /* File_descriptor */
- XX extern int errno; /* Last vms i/o error */
- XX
- XX for (j = i = 1; i < argc; i++) { /* Do all arguments */
- XX switch (*(ap = argv[i])) {
- XX case '<': /* <file */
- XX if (freopen(++ap, "r", stdin) == NULL) {
- XX perror(ap); /* Can't find file */
- XX exit(errno); /* Is a fatal error */
- XX }
- XX break;
- XX
- XX case '>': /* >file or >>file */
- XX if (*++ap == '>') { /* >>file */
- XX /*
- XX * If the file exists, and is writable by us,
- XX * call freopen to append to the file (using the
- XX * file's current attributes). Otherwise, create
- XX * a new file with "vanilla" attributes as if the
- XX * argument was given as ">filename".
- XX * access(name, 2) returns zero if we can write on
- XX * the specified file.
- XX */
- XX if (access(++ap, 2) == 0) {
- XX if (freopen(ap, "a", stdout) != NULL)
- XX break; /* Exit case statement */
- XX perror(ap); /* Error, can't append */
- XX exit(errno); /* After access test */
- XX } /* If file accessable */
- XX }
- XX /*
- XX * On vms, we want to create the file using "standard"
- XX * record attributes. creat(...) creates the file
- XX * using the caller's default protection mask and
- XX * "variable length, implied carriage return"
- XX * attributes. dup2() associates the file with stdout.
- XX */
- XX if ((file = creat(ap, 0, "rat=cr", "rfm=var")) == -1
- XX || dup2(file, fileno(stdout)) == -1) {
- XX perror(ap); /* Can't create file */
- XX exit(errno); /* is a fatal error */
- XX } /* If '>' creation */
- XX break; /* Exit case test */
- XX
- XX default:
- XX argv[j++] = ap; /* Not a redirector */
- XX break; /* Exit case test */
- XX }
- XX } /* For all arguments */
- XX argv[j] = NULL; /* Terminate argv[] */
- XX return (j); /* Return new argc */
- XX}
- XX#endif
- XX
- XX
- XX
- XEND-of-cpp3.c
- Xecho x - cpp4.c
- Xsed 's/^X//' >cpp4.c << 'END-of-cpp4.c'
- XX/*
- XX * C P P 4 . C
- XX * M a c r o D e f i n i t i o n s
- XX *
- XX * Edit History
- XX * 31-Aug-84 MM USENET net.sources release
- XX * 04-Oct-84 MM __LINE__ and __FILE__ must call ungetstring()
- XX * so they work correctly with token concatenation.
- XX * Added string formal recognition.
- XX * 25-Oct-84 MM "Short-circuit" evaluate #if's so that we
- XX * don't print unnecessary error messages for
- XX * #if !defined(FOO) && FOO != 0 && 10 / FOO ...
- XX * 31-Oct-84 ado/MM Added token concatenation
- XX * 6-Nov-84 MM Split off eval stuff
- XX */
- XX
- XX#include <stdio.h>
- XX#include <ctype.h>
- XX#include "cppdef.h"
- XX#include "cpp.h"
- XX/*
- XX * parm[], parmp, and parlist[] are used to store #define() argument
- XX * lists. nargs contains the actual number of parameters stored.
- XX */
- XXstatic char parm[NPARMWORK + 1]; /* define param work buffer */
- XXstatic char *parmp; /* Free space in parm */
- XXstatic char *parlist[LASTPARM]; /* -> start of each parameter */
- XXstatic int nargs; /* Parameters for this macro */
- XX
- XXdodefine()
- XX/*
- XX * Called from control when a #define is scanned. This module
- XX * parses formal parameters and the replacement string. When
- XX * the formal parameter name is encountered in the replacement
- XX * string, it is replaced by a character in the range 128 to
- XX * 128+NPARAM (this allows up to 32 parameters within the
- XX * Dec Multinational range). If cpp is ported to an EBCDIC
- XX * machine, you will have to make other arrangements.
- XX *
- XX * There is some special case code to distinguish
- XX * #define foo bar
- XX * from #define foo() bar
- XX *
- XX * Also, we make sure that
- XX * #define foo foo
- XX * expands to "foo" but doesn't put cpp into an infinite loop.
- XX *
- XX * A warning message is printed if you redefine a symbol to a
- XX * different text. I.e,
- XX * #define foo 123
- XX * #define foo 123
- XX * is ok, but
- XX * #define foo 123
- XX * #define foo +123
- XX * is not.
- XX *
- XX * The following subroutines are called from define():
- XX * checkparm called when a token is scanned. It checks through the
- XX * array of formal parameters. If a match is found, the
- XX * token is replaced by a control byte which will be used
- XX * to locate the parameter when the macro is expanded.
- XX * textput puts a string in the macro work area (parm[]), updating
- XX * parmp to point to the first free byte in parm[].
- XX * textput() tests for work buffer overflow.
- XX * charput puts a single character in the macro work area (parm[])
- XX * in a manner analogous to textput().
- XX */
- XX{
- XX register int c;
- XX register DEFBUF *dp; /* -> new definition */
- XX int isredefine; /* TRUE if redefined */
- XX char *old; /* Remember redefined */
- XX extern int save(); /* Save char in work[] */
- XX
- XX if (type[(c = skipws())] != LET)
- XX goto bad_define;
- XX isredefine = FALSE; /* Set if redefining */
- XX if ((dp = lookid(c)) == NULL) /* If not known now */
- XX dp = defendel(token, FALSE); /* Save the name */
- XX else { /* It's known: */
- XX isredefine = TRUE; /* Remember this fact */
- XX old = dp->repl; /* Remember replacement */
- XX dp->repl = NULL; /* No replacement now */
- XX }
- XX parlist[0] = parmp = parm; /* Setup parm buffer */
- XX if ((c = get()) == '(') { /* With arguments? */
- XX nargs = 0; /* Init formals counter */
- XX do { /* Collect formal parms */
- XX if (nargs >= LASTPARM)
- XX cfatal("Too many arguments for macro", NULLST);
- XX else if ((c = skipws()) == ')')
- XX break; /* Got them all */
- XX else if (type[c] != LET) /* Bad formal syntax */
- XX goto bad_define;
- XX scanid(c); /* Get the formal param */
- XX parlist[nargs++] = parmp; /* Save its start */
- XX textput(token); /* Save text in parm[] */
- XX } while ((c = skipws()) == ','); /* Get another argument */
- XX if (c != ')') /* Must end at ) */
- XX goto bad_define;
- XX c = ' '; /* Will skip to body */
- XX }
- XX else {
- XX /*
- XX * DEF_NOARGS is needed to distinguish between
- XX * "#define foo" and "#define foo()".
- XX */
- XX nargs = DEF_NOARGS; /* No () parameters */
- XX }
- XX if (type[c] == SPA) /* At whitespace? */
- XX c = skipws(); /* Not any more. */
- XX workp = work; /* Replacement put here */
- XX inmacro = TRUE; /* Keep \<newline> now */
- XX while (c != EOF_CHAR && c != '\n') { /* Compile macro body */
- XX#if OK_CONCAT
- XX if (c == '#') { /* Token concatenation? */
- XX while (workp > work && type[workp[-1]] == SPA)
- XX --workp; /* Erase leading spaces */
- XX save(TOK_SEP); /* Stuff a delimiter */
- XX c = skipws(); /* Eat whitespace */
- XX if (type[c] == LET) /* Another token here? */
- XX ; /* Stuff it normally */
- XX else if (type[c] == DIG) { /* Digit string after? */
- XX while (type[c] == DIG) { /* Stuff the digits */
- XX save(c);
- XX c = get();
- XX }
- XX save(TOK_SEP); /* Delimit 2nd token */
- XX }
- XX else {
- XX ciwarn("Strange character after # (%d.)", c);
- XX }
- XX continue;
- XX }
- XX#endif
- XX switch (type[c]) {
- XX case LET:
- XX checkparm(c, dp); /* Might be a formal */
- XX break;
- XX
- XX case DIG: /* Number in mac. body */
- XX case DOT: /* Maybe a float number */
- XX scannumber(c, save); /* Scan it off */
- XX break;
- XX
- XX case QUO: /* String in mac. body */
- XX#if STRING_FORMAL
- XX stparmscan(c, dp); /* Do string magic */
- XX#else
- XX stparmscan(c);
- XX#endif
- XX break;
- XX
- XX case BSH: /* Backslash */
- XX save('\\');
- XX if ((c = get()) == '\n')
- XX wrongline = TRUE;
- XX save(c);
- XX break;
- XX
- XX case SPA: /* Absorb whitespace */
- XX /*
- XX * Note: the "end of comment" marker is passed on
- XX * to allow comments to separate tokens.
- XX */
- XX if (workp[-1] == ' ') /* Absorb multiple */
- XX break; /* spaces */
- XX else if (c == '\t')
- XX c = ' '; /* Normalize tabs */
- XX /* Fall through to store character */
- XX default: /* Other character */
- XX save(c);
- XX break;
- XX }
- XX c = get();
- XX }
- XX inmacro = FALSE; /* Stop newline hack */
- XX unget(); /* For control check */
- XX if (workp > work && workp[-1] == ' ') /* Drop trailing blank */
- XX workp--;
- XX *workp = EOS; /* Terminate work */
- XX dp->repl = savestring(work); /* Save the string */
- XX dp->nargs = nargs; /* Save arg count */
- XX#if DEBUG
- XX if (debug)
- XX dumpadef("macro definition", dp);
- XX#endif
- XX if (isredefine) { /* Error if redefined */
- XX if ((old != NULL && dp->repl != NULL && !streq(old, dp->repl))
- XX || (old == NULL && dp->repl != NULL)
- XX || (old != NULL && dp->repl == NULL)) {
- XX cerror("Redefining defined variable \"%s\"", dp->name);
- XX }
- XX if (old != NULL) /* We don't need the */
- XX free(old); /* old definition now. */
- XX }
- XX return;
- XX
- XXbad_define:
- XX cerror("#define syntax error", NULLST);
- XX inmacro = FALSE; /* Stop <newline> hack */
- XX}
- XX
- XXcheckparm(c, dp)
- XXregister int c;
- XXDEFBUF *dp;
- XX/*
- XX * Replace this param if it's defined. Note that the macro name is a
- XX * possible replacement token. We stuff DEF_MAGIC in front of the token
- XX * which is treated as a LETTER by the token scanner and eaten by
- XX * the output routine. This prevents the macro expander from
- XX * looping if someone writes "#define foo foo".
- XX */
- XX{
- XX register int i;
- XX register char *cp;
- XX
- XX scanid(c); /* Get parm to token[] */
- XX for (i = 0; i < nargs; i++) { /* For each argument */
- XX if (streq(parlist[i], token)) { /* If it's known */
- XX save(i + MAC_PARM); /* Save a magic cookie */
- XX return; /* And exit the search */
- XX }
- XX }
- XX if (streq(dp->name, token)) /* Macro name in body? */
- XX save(DEF_MAGIC); /* Save magic marker */
- XX for (cp = token; *cp != EOS;) /* And save */
- XX save(*cp++); /* The token itself */
- XX}
- XX
- XX#if STRING_FORMAL
- XXstparmscan(delim, dp)
- XXint delim;
- XXregister DEFBUF *dp;
- XX/*
- XX * Scan the string (starting with the given delimiter).
- XX * The token is replaced if it is the only text in this string or
- XX * character constant. The algorithm follows checkparm() above.
- XX * Note that scanstring() has approved of the string.
- XX */
- XX{
- XX register int c;
- XX
- XX /*
- XX * Warning -- this code hasn't been tested for a while.
- XX * It exists only to preserve compatibility with earlier
- XX * implementations of cpp. It is not part of the Draft
- XX * ANSI Standard C language.
- XX */
- XX save(delim);
- XX instring = TRUE;
- XX while ((c = get()) != delim
- XX && c != '\n'
- XX && c != EOF_CHAR) {
- XX if (type[c] == LET) /* Maybe formal parm */
- XX checkparm(c, dp);
- XX else {
- XX save(c);
- XX if (c == '\\')
- XX save(get());
- XX }
- XX }
- XX instring = FALSE;
- XX if (c != delim)
- XX cerror("Unterminated string in macro body", NULLST);
- XX save(c);
- XX}
- XX#else
- XXstparmscan(delim)
- XXint delim;
- XX/*
- XX * Normal string parameter scan.
- XX */
- XX{
- XX register char *wp;
- XX register int i;
- XX extern int save();
- XX
- XX wp = workp; /* Here's where it starts */
- XX if (!scanstring(delim, save))
- XX return; /* Exit on scanstring error */
- XX workp[-1] = EOS; /* Erase trailing quote */
- XX wp++; /* -> first string content byte */
- XX for (i = 0; i < nargs; i++) {
- XX if (streq(parlist[i], wp)) {
- XX *wp++ = MAC_PARM + PAR_MAC; /* Stuff a magic marker */
- XX *wp++ = (i + MAC_PARM); /* Make a formal marker */
- XX *wp = wp[-3]; /* Add on closing quote */
- XX workp = wp + 1; /* Reset string end */
- XX return;
- XX }
- XX }
- XX workp[-1] = wp[-1]; /* Nope, reset end quote. */
- XX}
- XX#endif
- XX
- XXdoundef()
- XX/*
- XX * Remove the symbol from the defined list.
- XX * Called from the #control processor.
- XX */
- XX{
- XX register int c;
- XX
- XX if (type[(c = skipws())] != LET)
- XX cerror("Illegal #undef argument", NULLST);
- XX else {
- XX scanid(c); /* Get name to token[] */
- XX if (defendel(token, TRUE) == NULL) {
- XX cwarn("Symbol \"%s\" not defined in #undef", token);
- XX }
- XX }
- XX}
- XX
- XXtextput(text)
- XXchar *text;
- XX/*
- XX * Put the string in the parm[] buffer.
- XX */
- XX{
- XX register int size;
- XX
- XX size = strlen(text) + 1;
- XX if ((parmp + size) >= &parm[NPARMWORK])
- XX cfatal("Macro work area overflow", NULLST);
- XX else {
- XX strcpy(parmp, text);
- XX parmp += size;
- XX }
- XX}
- XX
- XXcharput(c)
- XXregister int c;
- XX/*
- XX * Put the byte in the parm[] buffer.
- XX */
- XX{
- XX if (parmp >= &parm[NPARMWORK])
- XX cfatal("Macro work area overflow", NULLST);
- XX else {
- XX *parmp++ = c;
- XX }
- XX}
- XX
- XX/*
- XX * M a c r o E x p a n s i o n
- XX */
- XX
- XXstatic DEFBUF *macro; /* Catches start of infinite macro */
- XX
- XXexpand(tokenp)
- XXregister DEFBUF *tokenp;
- XX/*
- XX * Expand a macro. Called from the cpp mainline routine (via subroutine
- XX * macroid()) when a token is found in the symbol table. It calls
- XX * expcollect() to parse actual parameters, checking for the correct number.
- XX * It then creates a "file" containing a single line containing the
- XX * macro with actual parameters inserted appropriately. This is
- XX * "pushed back" onto the input stream. (When the get() routine runs
- XX * off the end of the macro line, it will dismiss the macro itself.)
- XX */
- XX{
- XX register int c;
- XX register FILEINFO *file;
- XX extern FILEINFO *getfile();
- XX
- XX#if DEBUG
- XX if (debug)
- XX dumpadef("expand entry", tokenp);
- XX#endif
- XX /*
- XX * If no macro is pending, save the name of this macro
- XX * for an eventual error message.
- XX */
- XX if (recursion++ == 0)
- XX macro = tokenp;
- XX else if (recursion == RECURSION_LIMIT) {
- XX cerror("Recursive macro definition of \"%s\"", tokenp->name);
- XX fprintf(stderr, "(Defined by \"%s\")\n", macro->name);
- XX if (rec_recover) {
- XX do {
- XX c = get();
- XX } while (infile != NULL && infile->fp == NULL);
- XX unget();
- XX recursion = 0;
- XX return;
- XX }
- XX }
- XX /*
- XX * Here's a macro to expand.
- XX */
- XX nargs = 0; /* Formals counter */
- XX parmp = parm; /* Setup parm buffer */
- XX switch (tokenp->nargs) {
- XX case (-2): /* __LINE__ */
- XX sprintf(work, "%d", line);
- XX ungetstring(work);
- XX break;
- XX
- XX case (-3): /* __FILE__ */
- XX for (file = infile; file != NULL; file = file->parent) {
- XX if (file->fp != NULL) {
- XX sprintf(work, "\"%s\"", (file->progname != NULL)
- XX ? file->progname : file->filename);
- XX ungetstring(work);
- XX break;
- XX }
- XX }
- XX break;
- XX
- XX default:
- XX /*
- XX * Nothing funny about this macro.
- XX */
- XX if (tokenp->nargs < 0)
- XX cfatal("Bug: Illegal __ macro \"%s\"", tokenp->name);
- XX while ((c = skipws()) == '\n') /* Look for (, skipping */
- XX wrongline = TRUE; /* spaces and newlines */
- XX if (c != '(') {
- XX /*
- XX * If the programmer writes
- XX * #define foo() ...
- XX * ...
- XX * foo [no ()]
- XX * just write foo to the output stream.
- XX */
- XX unget();
- XX cwarn("Macro \"%s\" needs arguments", tokenp->name);
- XX fputs(tokenp->name, stdout);
- XX return;
- XX }
- XX else if (expcollect()) { /* Collect arguments */
- XX if (tokenp->nargs != nargs) { /* Should be an error? */
- XX cwarn("Wrong number of macro arguments for \"%s\"",
- XX tokenp->name);
- XX }
- XX#if DEBUG
- XX if (debug)
- XX dumpparm("expand");
- XX#endif
- XX } /* Collect arguments */
- XX case DEF_NOARGS: /* No parameters just stuffs */
- XX expstuff(tokenp); /* Do actual parameters */
- XX } /* nargs switch */
- XX}
- XX
- XXFILE_LOCAL int
- XXexpcollect()
- XX/*
- XX * Collect the actual parameters for this macro. TRUE if ok.
- XX */
- XX{
- XX register int c;
- XX register int paren; /* For embedded ()'s */
- XX extern int charput();
- XX
- XX for (;;) {
- XX paren = 0; /* Collect next arg. */
- XX while ((c = skipws()) == '\n') /* Skip over whitespace */
- XX wrongline = TRUE; /* and newlines. */
- XX if (c == ')') { /* At end of all args? */
- XX /*
- XX * Note that there is a guard byte in parm[]
- XX * so we don't have to check for overflow here.
- XX */
- XX *parmp = EOS; /* Make sure terminated */
- XX break; /* Exit collection loop */
- XX }
- XX else if (nargs >= LASTPARM)
- XX cfatal("Too many arguments in macro expansion", NULLST);
- XX parlist[nargs++] = parmp; /* At start of new arg */
- XX for (;; c = cget()) { /* Collect arg's bytes */
- XX if (c == EOF_CHAR) {
- XX cerror("end of file within macro argument", NULLST);
- XX return (FALSE); /* Sorry. */
- XX }
- XX else if (c == '\\') { /* Quote next character */
- XX charput(c); /* Save the \ for later */
- XX charput(cget()); /* Save the next char. */
- XX continue; /* And go get another */
- XX }
- XX else if (type[c] == QUO) { /* Start of string? */
- XX scanstring(c, charput); /* Scan it off */
- XX continue; /* Go get next char */
- XX }
- XX else if (c == '(') /* Worry about balance */
- XX paren++; /* To know about commas */
- XX else if (c == ')') { /* Other side too */
- XX if (paren == 0) { /* At the end? */
- XX unget(); /* Look at it later */
- XX break; /* Exit arg getter. */
- XX }
- XX paren--; /* More to come. */
- XX }
- XX else if (c == ',' && paren == 0) /* Comma delimits args */
- XX break;
- XX else if (c == '\n') /* Newline inside arg? */
- XX wrongline = TRUE; /* We'll need a #line */
- XX charput(c); /* Store this one */
- XX } /* Collect an argument */
- XX charput(EOS); /* Terminate argument */
- XX#if DEBUG
- XX if (debug)
- XX printf("parm[%d] = \"%s\"\n", nargs, parlist[nargs - 1]);
- XX#endif
- XX } /* Collect all args. */
- XX return (TRUE); /* Normal return */
- XX}
- XX
- XXFILE_LOCAL
- XXexpstuff(tokenp)
- XXDEFBUF *tokenp; /* Current macro being expanded */
- XX/*
- XX * Stuff the macro body, replacing formal parameters by actual parameters.
- XX */
- XX{
- XX register int c; /* Current character */
- XX register char *inp; /* -> repl string */
- XX register char *defp; /* -> macro output buff */
- XX int size; /* Actual parm. size */
- XX char *defend; /* -> output buff end */
- XX int string_magic; /* String formal hack */
- XX FILEINFO *file; /* Funny #include */
- XX extern FILEINFO *getfile();
- XX
- XX file = getfile(NBUFF, tokenp->name);
- XX inp = tokenp->repl; /* -> macro replacement */
- XX defp = file->buffer; /* -> output buffer */
- XX defend = defp + (NBUFF - 1); /* Note its end */
- XX if (inp != NULL) {
- XX while ((c = (*inp++ & 0xFF)) != EOS) {
- XX if (c >= MAC_PARM && c <= (MAC_PARM + PAR_MAC)) {
- XX string_magic = (c == (MAC_PARM + PAR_MAC));
- XX if (string_magic)
- XX c = (*inp++ & 0xFF);
- XX /*
- XX * Replace formal parameter by actual parameter string.
- XX */
- XX if ((c -= MAC_PARM) < nargs) {
- XX size = strlen(parlist[c]);
- XX if ((defp + size) >= defend)
- XX goto nospace;
- XX /*
- XX * Erase the extra set of quotes.
- XX */
- XX if (string_magic && defp[-1] == parlist[c][0]) {
- XX strcpy(defp-1, parlist[c]);
- XX defp += (size - 2);
- XX }
- XX else {
- XX strcpy(defp, parlist[c]);
- XX defp += size;
- XX }
- XX }
- XX }
- XX else if (defp >= defend) {
- XXnospace: cfatal("Out of space in macro \"%s\" arg expansion",
- XX tokenp->name);
- XX }
- XX else {
- XX *defp++ = c;
- XX }
- XX }
- XX }
- XX *defp = EOS;
- XX#if DEBUG
- XX if (debug > 1)
- XX printf("macroline: \"%s\"\n", file->buffer);
- XX#endif
- XX}
- XX
- XX#if DEBUG
- XXdumpparm(why)
- XXchar *why;
- XX/*
- XX * Dump parameter list.
- XX */
- XX{
- XX register int i;
- XX
- XX printf("dump of %d parameters (%d bytes total) %s\n",
- XX nargs, parmp - parm, why);
- XX for (i = 0; i < nargs; i++) {
- XX printf("parm[%d] (%d) = \"%s\"\n",
- XX i + 1, strlen(parlist[i]), parlist[i]);
- XX }
- XX}
- XX#endif
- XEND-of-cpp4.c
- Xexit
- X
- END_OF_FILE
- if test 53580 -ne `wc -c <'sys/unix/cpp2.shr'`; then
- echo shar: \"'sys/unix/cpp2.shr'\" unpacked with wrong size!
- fi
- # end of 'sys/unix/cpp2.shr'
- fi
- echo shar: End of archive 5 \(of 108\).
- cp /dev/null ark5isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
- 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
- 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \
- 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 \
- 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 \
- 101 102 103 104 105 106 107 108 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 108 archives.
- echo "Now execute 'rebuild.sh'"
- rm -f ark10[0-8]isdone ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-