From: jwalz Date: Sat, 5 Jan 2002 21:05:59 +0000 (+0000) Subject: *** empty log message *** X-Git-Tag: MOVE2GIT~3651 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d8c87acbbebb92988b8602ab6d2b7accc6c6045d;p=nethack *** empty log message *** --- diff --git a/sys/unix/cpp1.shr b/sys/unix/cpp1.shr new file mode 100644 index 000000000..f2b133d45 --- /dev/null +++ b/sys/unix/cpp1.shr @@ -0,0 +1,1783 @@ +# This is a shell archive. Save it in a file, remove anything before +# this line, and then unpack it by entering "sh file". Note, it may +# create directories; files and directories will be owned by you and +# have default permissions. +# +# This archive contains: +# +# makefile.txt +# readme.txt +# cpp.mem +# cpp.h +# cppdef.h +# cpp2.c +# +echo x - makefile.txt +sed 's/^X//' >makefile.txt << 'END-of-makefile.txt' +X# +X# The redefinition of strchr() and strrchr() are needed for +X# Ultrix-32, Unix 4.2 bsd (and maybe some other Unices). +X# +XBSDDEFINE = -Dstrchr=index -Dstrrchr=rindex +X# +X# On certain systems, such as Unix System III, you may need to define +X# $(LINTFLAGS) in the make command line to set system-specific lint flags. +X# +X# This Makefile assumes cpp will replace the "standard" preprocessor. +X# Delete the reference to -DLINE_PREFIX=\"\" if cpp is used stand-alone. +X# LINEFIX is a sed script filter that reinserts #line -- used for testing +X# if LINE_PREFIX is set to "". Note that we must stand on our heads to +X# match the # and a line had better not begin with $. By the way, what +X# we really want is +X# LINEFIX = | sed "s/^#/#line/" +X# +XCPPDEFINE = -DLINE_PREFIX=\"\" +XLINEFIX = | sed "s/^[^ !\"%-~]/&line/" +X# +X# Define OLD_PREPROCESSOR non-zero to make a preprocessor which is +X# "as compatible as possible" with the standard Unix V7 or Ultrix +X# preprocessors. This is needed to rebuild 4.2bsd, for example, as +X# the preprocessor is used to modify assembler code, rather than C. +X# This is not recommended for current development. OLD_PREPROCESSOR +X# forces the following definitions: +X# OK_DOLLAR FALSE $ is not allowed in variables +X# OK_CONCAT FALSE # cannot concatenate tokens +X# COMMENT_INVISIBLE TRUE old-style comment concatenation +X# STRING_FORMAL TRUE old-style string expansion +X# +XOLDDEFINE = -DOLD_PREPROCESSOR=1 +X# +X# DEFINES collects all -D arguments for cc and lint: +X# Change DEFINES = $(BSDDEFINE) $(CPPDEFINE) $(OLDDEFINE) +X# for an old-style preprocessor. +X# +X# DEFINES = $(BSDDEFINE) $(CPPDEFINE) +XDEFINES = $(CPPDEFINE) +X +XCFLAGS = -O $(DEFINES) +X +X# +X# ** compile cpp +X# +XSRCS = cpp1.c cpp2.c cpp3.c cpp4.c cpp5.c cpp6.c +XOBJS = cpp1.o cpp2.o cpp3.o cpp4.o cpp5.o cpp6.o +Xcpp: $(OBJS) +X $(CC) $(CFLAGS) $(OBJS) -o cpp +X +X# +X# ** Test cpp by preprocessing itself, compiling the result, +X# ** repeating the process and diff'ing the result. Note: this +X# ** is not a good test of cpp, but a simple verification. +X# ** The diff's should not report any changes. +X# ** Note that a sed script may be executed for each compile +X# +Xtest: +X cpp cpp1.c $(LINEFIX) >old.tmp1.c +X cpp cpp2.c $(LINEFIX) >old.tmp2.c +X cpp cpp3.c $(LINEFIX) >old.tmp3.c +X cpp cpp4.c $(LINEFIX) >old.tmp4.c +X cpp cpp5.c $(LINEFIX) >old.tmp5.c +X cpp cpp6.c $(LINEFIX) >old.tmp6.c +X $(CC) $(CFLAGS) old.tmp[123456].c +X a.out cpp1.c >new.tmp1.c +X a.out cpp2.c >new.tmp2.c +X a.out cpp3.c >new.tmp3.c +X a.out cpp4.c >new.tmp4.c +X a.out cpp5.c >new.tmp5.c +X a.out cpp6.c >new.tmp6.c +X diff old.tmp1.c new.tmp1.c +X diff old.tmp2.c new.tmp2.c +X diff old.tmp3.c new.tmp3.c +X diff old.tmp4.c new.tmp4.c +X diff old.tmp5.c new.tmp5.c +X diff old.tmp6.c new.tmp6.c +X rm a.out old.tmp[123456].* new.tmp[123456].* +X +X# +X# A somewhat more extensive test is provided by the "clock" +X# program (which is not distributed). Substitute your favorite +X# macro-rich program here. +X# +Xclock: clock.c cpp +X cpp clock.c $(LINEFIX) >temp.cpp.c +X cc temp.cpp.c -lcurses -ltermcap -o clock +X rm temp.cpp.c +X +X# +X# ** Lint the code +X# +X +Xlint: $(SRCS) +X lint $(LINTFLAGS) $(DEFINES) $(SRCS) +X +X# +X# ** Remove unneeded files +X# +Xclean: +X rm -f $(OBJS) cpp +X +X# +X# ** Rebuild the archive files needed to distribute cpp +X# ** Uses the Decus C archive utility. +X# +X +Xarchc: archc.c +X $(CC) $(CFLAGS) archc.c -o archc +X +Xarchx: archx.c +X $(CC) $(CFLAGS) archx.c -o archx +X +Xarchive: archc +X archc readme.txt cpp.mem archx.c archc.c cpp.rno makefile.txt \ +X cpp*.h >cpp1.arc +X archc cpp1.c cpp2.c cpp3.c >cpp2.arc +X archc cpp4.c cpp5.c cpp6.c >cpp3.arc +X +X# +X# Object module dependencies +X# +X +Xcpp1.o : cpp1.c cpp.h cppdef.h +X +Xcpp2.o : cpp2.c cpp.h cppdef.h +X +Xcpp3.o : cpp3.c cpp.h cppdef.h +X +Xcpp4.o : cpp4.c cpp.h cppdef.h +X +Xcpp5.o : cpp5.c cpp.h cppdef.h +X +Xcpp6.o : cpp6.c cpp.h cppdef.h +X +X +END-of-makefile.txt +echo x - readme.txt +sed 's/^X//' >readme.txt << 'END-of-readme.txt' +X +XDecus cpp is a public-domain implementation of the C preprocessor. +XIt runs on VMS native (Vax C), VMS compatibilty mode (Decus C), +XRSX-11M, RSTS/E, P/OS, and RT11, as well as on several varieties +Xof Unix, including Ultrix. Decus cpp attempts to implement features +Xin the Draft ANSI Standard for the C language. It should be noted, +Xhowever, that this standard is under active development: the current +Xdraft of the standard explicitly states that "readers are requested +Xnot to specify or claim conformance to this draft." Thus readers +Xand users of Decus cpp should not assume that it conforms to the +Xdraft standard, or that it will conform to the actual C language +Xstandard. +X +XThese notes describe how to extract the cpp source files, configure it +Xfor your needs, and mention a few design decisions that may be of interest +Xto maintainers. +X +X Installation +X +XBecause the primary development of cpp was not on Unix, it +Xis distributed using the Decus C archive program (quite similar +Xto the archiver published in Kernighan and Plauger's Software +XTools). To extract the files from the net.sources distribution, +Xsave this message as cpp1.arc and the other two distribution +Xfiles as cpp2.arc and cpp3.arc. Then, using your favorite editor, +Xlocate the archx.c program, just following the line beginning with +X"-h- archx.c" -- the format of the distribution is just: +X +X -h- readme.txt +X ... this file +X -h- cpp.mem +X ... description of cpp +X -h- archx.c +X ... archx.c program -- extracts archives +X -h- archc.c +X ... archc.c program -- creates archives +X +XCompile archx.c -- it shouldn't require any special editing. +XThen run it as follows: +X +X archx *.arc +X +XYou do not need to remove mail headers from the saved messages. +X +XYou should then read through cppdef.h to make sure the HOST and +XTARGET (and other implementation-specific) definitions are set +Xcorrectly for your machine, editing them as needed. +X +XYou may then copy makefile.txt to Makefile, editing it as needed +Xfor your particular system. On Unix, cpp should be compiled +Xby make without further difficulty. On other operating systems, +Xyou should compile the six source modules, linking them together. +XNote that, on Decus C based systems, you must extend the default +Xstack allocation. The Decus C build utility will create the +Xappropriate command file. +X +X Support Notes +X +XThe USENET distribution kit was designed to keep all submissions around +X50,000 bytes: +X +Xcpp1.arc: +X readme.txt This file +X cpp.mem Documentation page (see below) +X archx.c Archive extraction program +X archc.c Archive construction program +X cpp.rno Source for cpp.mem (see below) +X makefile.txt Unix makefile -- copy to Makefile +X cpp.h Main header file (structure def's and globals) +X cppdef.h Configuration file (host and target definitions) +X +Xcpp2.arc: +X cpp1.c Mainline code, documentation master sources +X cpp2.c most #control processing +X cpp3.c filename stuff and command line parsing +Xcpp3.arc: +X cpp4.c #define processor +X cpp5.c #if processor +X cpp6.c Support code (symbol table and I/O routines) +X +XCpp intentionally does not rely on the presence of a full-scale +Xmacro preprocessor, it does require the simple parameter substitution +Xpreprocessor capabilities of Unix V6 and Decus C. If your C +Xlanguage lacks full preprocessing, you should make sure "nomacargs" +Xis #define'd in cpp.h. (This is done automatically by the Decus C +Xcompiler.) +X +XThe documentation (manual page) for cpp is included as cpp.mem +Xand cpp.rno. Cpp.rno is in Dec Runoff format, built by a Decus C +Xutility (getrno) from original source which is embedded in cpp1.c. +XTo my knowledge, there is no equivalent program that creates +Xthe nroff source appropriate for Unix. +X +XI would be happy to receive fixes to any problems you encounter. +XAs I do not maintain distribution kit base-levels, bare-bones +Xdiff listings without sufficient context are not very useful. +XIt is unlikely that I can find time to help you with other +Xdifficulties. +X +X Acknowledgements +X +XI received a great deal of help from many people in debugging cpp. +XAlan Feuer and Sam Kendall used "state of the art" run-time code +Xcheckers to locate several errors. Ed Keiser found problems when +Xcpp was used on machines with different int and pointer sizes. +XDave Conroy helped with the initial debugging, while Arthur Olsen +Xand George Rosenberg found (and solved) several problems in the +Xfirst USENET release. +X +XMartin Minow +Xdecvax!minow +X +END-of-readme.txt +echo x - cpp.mem +sed 's/^X//' >cpp.mem << 'END-of-cpp.mem' +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-cpp.mem +echo x - cpp.h +sed 's/^X//' >cpp.h << 'END-of-cpp.h' +X +X/* +X * I n t e r n a l D e f i n i t i o n s f o r C P P +X * +X * In general, definitions in this file should not be changed. +X */ +X +X#ifndef TRUE +X#define TRUE 1 +X#define FALSE 0 +X#endif +X#ifndef EOS +X/* +X * This is predefined in Decus C +X */ +X#define EOS '\0' /* End of string */ +X#endif +X#define EOF_CHAR 0 /* Returned by get() on eof */ +X#define NULLST ((char *) NULL) /* Pointer to nowhere (linted) */ +X#define DEF_NOARGS (-1) /* #define foo vs #define foo() */ +X +X/* +X * The following may need to change if the host system doesn't use ASCII. +X */ +X#define DEF_MAGIC 0x1D /* Magic for #defines */ +X#define TOK_SEP 0x1E /* Token concatenation delim. */ +X#define COM_SEP 0x1F /* Magic comment separator */ +X +X/* +X * Note -- in Ascii, the following will map macro formals onto DEL + the +X * C1 control character region (decimal 128 .. (128 + PAR_MAC)) which will +X * be ok as long as PAR_MAC is less than 33). Note that the last PAR_MAC +X * value is reserved for string substitution. +X */ +X +X#define MAC_PARM 0x7F /* Macro formals start here */ +X#if PAR_MAC >= 33 +X assertion fails -- PAR_MAC isn't less than 33 +X#endif +X#define LASTPARM (PAR_MAC - 1) +X +X/* +X * Character type codes. +X */ +X +X#define INV 0 /* Invalid, must be zero */ +X#define OP_EOE INV /* End of expression */ +X#define DIG 1 /* Digit */ +X#define LET 2 /* Identifier start */ +X#define FIRST_BINOP OP_ADD +X#define OP_ADD 3 +X#define OP_SUB 4 +X#define OP_MUL 5 +X#define OP_DIV 6 +X#define OP_MOD 7 +X#define OP_ASL 8 +X#define OP_ASR 9 +X#define OP_AND 10 /* &, not && */ +X#define OP_OR 11 /* |, not || */ +X#define OP_XOR 12 +X#define OP_EQ 13 +X#define OP_NE 14 +X#define OP_LT 15 +X#define OP_LE 16 +X#define OP_GE 17 +X#define OP_GT 18 +X#define OP_ANA 19 /* && */ +X#define OP_ORO 20 /* || */ +X#define OP_QUE 21 /* ? */ +X#define OP_COL 22 /* : */ +X#define OP_CMA 23 /* , (relevant?) */ +X#define LAST_BINOP OP_CMA /* Last binary operand */ +X/* +X * The following are unary. +X */ +X#define FIRST_UNOP OP_PLU /* First Unary operand */ +X#define OP_PLU 24 /* + (draft ANSI standard) */ +X#define OP_NEG 25 /* - */ +X#define OP_COM 26 /* ~ */ +X#define OP_NOT 27 /* ! */ +X#define LAST_UNOP OP_NOT +X#define OP_LPA 28 /* ( */ +X#define OP_RPA 29 /* ) */ +X#define OP_END 30 /* End of expression marker */ +X#define OP_MAX (OP_END + 1) /* Number of operators */ +X#define OP_FAIL (OP_END + 1) /* For error returns */ +X +X/* +X * The following are for lexical scanning only. +X */ +X +X#define QUO 65 /* Both flavors of quotation */ +X#define DOT 66 /* . might start a number */ +X#define SPA 67 /* Space and tab */ +X#define BSH 68 /* Just a backslash */ +X#define END 69 /* EOF */ +X +X/* +X * These bits are set in ifstack[] +X */ +X#define WAS_COMPILING 1 /* TRUE if compile set at entry */ +X#define ELSE_SEEN 2 /* TRUE when #else processed */ +X#define TRUE_SEEN 4 /* TRUE when #if TRUE processed */ +X +X/* +X * Define bits for the basic types and their adjectives +X */ +X +X#define T_CHAR 1 +X#define T_INT 2 +X#define T_FLOAT 4 +X#define T_DOUBLE 8 +X#define T_SHORT 16 +X#define T_LONG 32 +X#define T_SIGNED 64 +X#define T_UNSIGNED 128 +X#define T_PTR 256 /* Pointer */ +X#define T_FPTR 512 /* Pointer to functions */ +X +X/* +X * The DEFBUF structure stores information about #defined +X * macros. Note that the defbuf->repl information is always +X * in malloc storage. +X */ +X +Xtypedef struct defbuf { +X struct defbuf *link; /* Next define in chain */ +X char *repl; /* -> replacement */ +X int hash; /* Symbol table hash */ +X int nargs; /* For define(args) */ +X char name[1]; /* #define name */ +X} DEFBUF; +X +X/* +X * The FILEINFO structure stores information about open files +X * and macros being expanded. +X */ +X +Xtypedef struct fileinfo { +X char *bptr; /* Buffer pointer */ +X int line; /* for include or macro */ +X FILE *fp; /* File if non-null */ +X struct fileinfo *parent; /* Link to includer */ +X char *filename; /* File/macro name */ +X char *progname; /* From #line statement */ +X unsigned int unrecur; /* For macro recursion */ +X char buffer[1]; /* current input line */ +X} FILEINFO; +X +X/* +X * The SIZES structure is used to store the values for #if sizeof +X */ +X +Xtypedef struct sizes { +X short bits; /* If this bit is set, */ +X short size; /* this is the datum size value */ +X short psize; /* this is the pointer size */ +X} SIZES; +X/* +X * nomacarg is a built-in #define on Decus C. +X */ +X +X#ifdef nomacarg +X#define cput output /* cput concatenates tokens */ +X#else +X#if COMMENT_INVISIBLE +X#define cput(c) { if (c != TOK_SEP && c != COM_SEP) putchar(c); } +X#else +X#define cput(c) { if (c != TOK_SEP) putchar(c); } +X#endif +X#endif +X +X#ifndef nomacarg +X#define streq(s1, s2) (strcmp(s1, s2) == 0) +X#endif +X +X/* +X * Error codes. VMS uses system definitions. +X * Decus C codes are defined in stdio.h. +X * Others are cooked to order. +X */ +X +X#if HOST == SYS_VMS +X#include +X#include +X#define IO_NORMAL (SS$_NORMAL | STS$M_INHIB_MSG) +X#define IO_ERROR SS$_ABORT +X#endif +X/* +X * Note: IO_NORMAL and IO_ERROR are defined in the Decus C stdio.h file +X */ +X#ifndef IO_NORMAL +X#define IO_NORMAL 0 +X#endif +X#ifndef IO_ERROR +X#define IO_ERROR 1 +X#endif +X +X/* +X * Externs +X */ +X +Xextern int line; /* Current line number */ +Xextern int wrongline; /* Force #line to cc pass 1 */ +Xextern char type[]; /* Character classifier */ +Xextern char token[IDMAX + 1]; /* Current input token */ +Xextern int instring; /* TRUE if scanning string */ +Xextern int inmacro; /* TRUE if scanning #define */ +Xextern int errors; /* Error counter */ +Xextern int recursion; /* Macro depth counter */ +Xextern char ifstack[BLK_NEST]; /* #if information */ +X#define compiling ifstack[0] +Xextern char *ifptr; /* -> current ifstack item */ +Xextern char *incdir[NINCLUDE]; /* -i directories */ +Xextern char **incend; /* -> active end of incdir */ +Xextern int cflag; /* -C option (keep comments) */ +Xextern int eflag; /* -E option (ignore errors) */ +Xextern int nflag; /* -N option (no pre-defines) */ +Xextern int rec_recover; /* unwind recursive macros */ +Xextern char *preset[]; /* Standard predefined symbols */ +Xextern char *magic[]; /* Magic predefined symbols */ +Xextern FILEINFO *infile; /* Current input file */ +Xextern char work[NWORK + 1]; /* #define scratch */ +Xextern char *workp; /* Free space in work */ +X#if DEBUG +Xextern int debug; /* Debug level */ +X#endif +Xextern int keepcomments; /* Don't remove comments if set */ +Xextern SIZES size_table[]; /* For #if sizeof sizes */ +Xextern char *getmem(); /* Get memory or die. */ +Xextern DEFBUF *lookid(); /* Look for a #define'd thing */ +Xextern DEFBUF *defendel(); /* Symbol table enter/delete */ +Xextern char *savestring(); /* Stuff string in malloc mem. */ +Xextern char *strcpy(); +Xextern char *strcat(); +Xextern char *strrchr(); +Xextern char *strchr(); +Xextern long time(); +X/* extern char *sprintf(); /* Lint needs this */ +END-of-cpp.h +echo x - cppdef.h +sed 's/^X//' >cppdef.h << 'END-of-cppdef.h' +X/* +X * S y s t e m D e p e n d e n t +X * D e f i n i t i o n s f o r C P P +X * +X * Definitions in this file may be edited to configure CPP for particular +X * host operating systems and target configurations. +X * +X * NOTE: cpp assumes it is compiled by a compiler that supports macros +X * with arguments. If this is not the case (as for Decus C), #define +X * nomacarg -- and provide function equivalents for all macros. +X * +X * cpp also assumes the host and target implement the Ascii character set. +X * If this is not the case, you will have to do some editing here and there. +X */ +X +X/* +X * This redundant definition of TRUE and FALSE works around +X * a limitation of Decus C. +X */ +X#ifndef TRUE +X#define TRUE 1 +X#define FALSE 0 +X#endif +X +X/* +X * Define the HOST operating system. This is needed so that +X * cpp can use appropriate filename conventions. +X */ +X#define SYS_UNKNOWN 0 +X#define SYS_UNIX 1 +X#define SYS_VMS 2 +X#define SYS_RSX 3 +X#define SYS_RT11 4 +X#define SYS_LATTICE 5 +X#define SYS_ONYX 6 +X#define SYS_68000 7 +X#define SYS_GCOS 8 +X#define SYS_IBM 9 +X#define SYS_OS 10 +X#define SYS_TSS 11 +X +X#ifndef HOST +X#ifdef unix +X#define HOST SYS_UNIX +X#else +X#ifdef vms +X#define HOST SYS_VMS +X#else +X#ifdef rsx +X#define HOST SYS_RSX +X#else +X#ifdef rt11 +X#define HOST SYS_RT11 +X#else +X#ifdef dmert +X#define HOST SYS_DMERT +X#else +X#ifdef gcos +X#define HOST SYS_GCOS +X#else +X#ifdef ibm +X#define HOST SYS_IBM +X#else +X#ifdef os +X#define HOST SYS_OS +X#else +X#ifdef tss +X#define HOST SYS_TSS +X#endif +X#endif +X#endif +X#endif +X#endif +X#endif +X#endif +X#endif +X#endif +X +X#ifndef HOST +X#define HOST SYS_UNKNOWN +X#endif +X +X/* +X * We assume that the target is the same as the host system +X */ +X#ifndef TARGET +X#define TARGET HOST +X#endif +X +X/* +X * In order to predefine machine-dependent constants, +X * several strings are defined here: +X * +X * MACHINE defines the target cpu (by name) +X * SYSTEM defines the target operating system +X * COMPILER defines the target compiler +X * +X * The above may be #defined as "" if they are not wanted. +X * They should not be #defined as NULL. +X * +X * LINE_PREFIX defines the # output line prefix, if not "line" +X * This should be defined as "" if cpp is to replace +X * the "standard" C pre-processor. +X * +X * FILE_LOCAL marks functions which are referenced only in the +X * file they reside. Some C compilers allow these +X * to be marked "static" even though they are referenced +X * by "extern" statements elsewhere. +X * +X * OK_DOLLAR Should be set TRUE if $ is a valid alphabetic character +X * in identifiers (default), or zero if $ is invalid. +X * Default is TRUE. +X * +X * OK_CONCAT Should be set TRUE if # may be used to concatenate +X * tokens in macros (per the Ansi Draft Standard) or +X * FALSE for old-style # processing (needed if cpp is +X * to process assembler source code). +X * +X * OK_DATE Predefines the compilation date if set TRUE. +X * Not permitted by the Nov. 12, 1984 Draft Standard. +X * +X * S_CHAR etc. Define the sizeof the basic TARGET machine word types. +X * By default, sizes are set to the values for the HOST +X * computer. If this is inappropriate, see the code in +X * cpp3.c for details on what to change. Also, if you +X * have a machine where sizeof (signed int) differs from +X * sizeof (unsigned int), you will have to edit code and +X * tables in cpp3.c (and extend the -S option definition.) +X * +X * CPP_LIBRARY May be defined if you have a site-specific include directory +X * which is to be searched *before* the operating-system +X * specific directories. +X */ +X +X#if TARGET == SYS_LATTICE +X/* +X * We assume the operating system is pcdos for the IBM-PC. +X * We also assume the small model (just like the PDP-11) +X */ +X#define MACHINE "i8086" +X#define SYSTEM "pcdos" +X#endif +X +X#if TARGET == SYS_ONYX +X#define MACHINE "z8000" +X#define SYSTEM "unix" +X#endif +X +X#if TARGET == SYS_VMS +X#define MACHINE "vax" +X#define SYSTEM "vms" +X#define COMPILER "vax11c" +X#endif +X +X#if TARGET == SYS_RSX +X#define MACHINE "pdp11" +X#define SYSTEM "rsx" +X#define COMPILER "decus" +X#endif +X +X#if TARGET == SYS_RT11 +X#define MACHINE "pdp11" +X#define SYSTEM "rt11" +X#define COMPILER "decus" +X#endif +X +X#if TARGET == SYS_68000 +X/* +X * All three machine designators have been seen in various systems. +X * Warning -- compilers differ as to sizeof (int). cpp3 assumes that +X * sizeof (int) == 2 +X */ +X#define MACHINE "M68000", "m68000", "m68k" +X#define SYSTEM "unix" +X#endif +X +X#if TARGET == SYS_UNIX +X#define SYSTEM "unix" +X#ifdef pdp11 +X#define MACHINE "pdp11" +X#endif +X#ifdef vax +X#define MACHINE "vax" +X#endif +X#ifdef u370 +X#define MACHINE "u370" +X#endif +X#ifdef interdata +X#define MACHINE "interdata" +X#endif +X#ifdef u3b +X#define MACHINE "u3b" +X#endif +X#ifdef u3b5 +X#define MACHINE "u3b5" +X#endif +X#ifdef u3b2 +X#define MACHINE "u3b2" +X#endif +X#ifdef u3b20d +X#define MACHINE "u3b20d" +X#endif +X#endif +X#endif +X +X/* +X * defaults +X */ +X +X#ifndef MSG_PREFIX +X#define MSG_PREFIX "cpp: " +X#endif +X +X#ifndef LINE_PREFIX +X#ifdef decus +X#define LINE_PREFIX "" +X#else +X#define LINE_PREFIX "line" +X#endif +X#endif +X +X/* +X * OLD_PREPROCESSOR forces the definition of OK_DOLLAR, OK_CONCAT, +X * COMMENT_INVISIBLE, and STRING_FORMAL to values appropriate for +X * an old-style preprocessor. +X */ +X +X#ifndef OLD_PREPROCESSOR +X#define OLD_PREPROCESSOR FALSE +X#endif +X +X#if OLD_PREPROCESSOR +X#define OK_DOLLAR FALSE +X#define OK_CONCAT FALSE +X#define COMMENT_INVISIBLE TRUE +X#define STRING_FORMAL TRUE +X#endif +X +X/* +X * RECURSION_LIMIT may be set to -1 to disable the macro recursion test. +X */ +X#ifndef RECURSION_LIMIT +X#define RECURSION_LIMIT 1000 +X#endif +X +X/* +X * BITS_CHAR may be defined to set the number of bits per character. +X * it is needed only for multi-byte character constants. +X */ +X#ifndef BITS_CHAR +X#define BITS_CHAR 8 +X#endif +X +X/* +X * BIG_ENDIAN is set TRUE on machines (such as the IBM 360 series) +X * where 'ab' stores 'a' in the high-bits and 'b' in the low-bits. +X * It is set FALSE on machines (such as the PDP-11 and Vax-11) +X * where 'ab' stores 'a' in the low-bits and 'b' in the high-bits. +X * (Or is it the other way around?) -- Warning: BIG_ENDIAN code is untested. +X */ +X#ifndef BIG_ENDIAN +X#define BIG_ENDIAN FALSE +X#endif +X +X/* +X * COMMENT_INVISIBLE may be defined to allow "old-style" comment +X * processing, whereby the comment becomes a zero-length token +X * delimiter. This permitted tokens to be concatenated in macro +X * expansions. This was removed from the Draft Ansi Standard. +X */ +X#ifndef COMMENT_INVISIBLE +X#define COMMENT_INVISIBLE FALSE +X#endif +X +X/* +X * STRING_FORMAL may be defined to allow recognition of macro parameters +X * anywhere in replacement strings. This was removed from the Draft Ansi +X * Standard and a limited recognition capability added. +X */ +X#ifndef STRING_FORMAL +X#define STRING_FORMAL FALSE +X#endif +X +X/* +X * OK_DOLLAR enables use of $ as a valid "letter" in identifiers. +X * This is a permitted extension to the Ansi Standard and is required +X * for e.g., VMS, RSX-11M, etc. It should be set FALSE if cpp is +X * used to preprocess assembler source on Unix systems. OLD_PREPROCESSOR +X * sets OK_DOLLAR FALSE for that reason. +X */ +X#ifndef OK_DOLLAR +X#define OK_DOLLAR TRUE +X#endif +X +X/* +X * OK_CONCAT enables (one possible implementation of) token concatenation. +X * If cpp is used to preprocess Unix assembler source, this should be +X * set FALSE as the concatenation character, #, is used by the assembler. +X */ +X#ifndef OK_CONCAT +X#define OK_CONCAT TRUE +X#endif +X +X/* +X * OK_DATE may be enabled to predefine today's date as a string +X * at the start of each compilation. This is apparently not permitted +X * by the Draft Ansi Standard. +X */ +X#ifndef OK_DATE +X#define OK_DATE TRUE +X#endif +X +X/* +X * Some common definitions. +X */ +X +X#ifndef DEBUG +X#define DEBUG FALSE +X#endif +X +X/* +X * The following definitions are used to allocate memory for +X * work buffers. In general, they should not be modified +X * by implementors. +X * +X * PAR_MAC The maximum number of #define parameters (31 per Standard) +X * Note: we need another one for strings. +X * IDMAX The longest identifier, 31 per Ansi Standard +X * NBUFF Input buffer size +X * NWORK Work buffer size -- the longest macro +X * must fit here after expansion. +X * NEXP The nesting depth of #if expressions +X * NINCLUDE The number of directories that may be specified +X * on a per-system basis, or by the -I option. +X * BLK_NEST The number of nested #if's permitted. +X */ +X +X#define IDMAX 31 +X#define PAR_MAC (31 + 1) +X#define NBUFF 1024 +X#define NWORK 1024 +X#define NEXP 128 +X#define NINCLUDE 7 +X#define NPARMWORK (NWORK * 2) +X#define BLK_NEST 32 +X +X/* +X * Some special constants. These may need to be changed if cpp +X * is ported to a wierd machine. +X * +X * NOTE: if cpp is run on a non-ascii machine, ALERT and VT may +X * need to be changed. They are used to implement the proposed +X * ANSI standard C control characters '\a' and '\v' only. +X * DEL is used to tag macro tokens to prevent #define foo foo +X * from looping. Note that we don't try to prevent more elaborate +X * #define loops from occurring. +X */ +X +X#ifndef ALERT +X#define ALERT '\007' /* '\a' is "Bell" */ +X#endif +X +X#ifndef VT +X#define VT '\013' /* Vertical Tab CTRL/K */ +X#endif +X +X +X#ifndef FILE_LOCAL +X#ifdef decus +X#define FILE_LOCAL static +X#else +X#ifdef vax11c +X#define FILE_LOCAL static +X#else +X#define FILE_LOCAL /* Others are global */ +X#endif +X#endif +X#endif +X +END-of-cppdef.h +echo x - cpp2.c +sed 's/^X//' >cpp2.c << 'END-of-cpp2.c' +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 */ +X +X#include +X#include +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 +X#include +X#include +X#include +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_ident ('i' + ('e' << 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_sccs ('s' + ('c' << 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 c = skipws(); +X if (c == '\n' || c == EOF_CHAR) +X return (counter + 1); +X if (!isdigit(c)) +X scanid(c); /* Get #word to token[] */ +X else { +X unget(); /* Hack -- allow #123 as a */ +X strcpy(token, "line"); /* synonym for #line 123 */ +X } +X hash = (token[1] == EOS) ? L_nogood : (token[0] + (token[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_ident: tp = "ident"; 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_sccs: tp = "sccs"; 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, token)) +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", token); +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_ident: +X case L_sccs: +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. */ +Xdump_line: skipnl(); /* Ignore rest of line */ +X 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 and +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", token); +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_if: +X case L_ifdef: +X case L_ifndef: +X if (++ifptr >= &ifstack[BLK_NEST]) +Xif_nest_err: cfatal("Too many nested #%s statements", token); +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", token); +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_ident: +X case L_sccs: +X goto dump_line; +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 "); +X while ((c = get()) != '\n' && c != EOF_CHAR) +X cput(c); +X unget(); +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\"", token); +X break; +X } +X if (hash != L_include) { +X#if OLD_PREPROCESSOR || !VERBOSE +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 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 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 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 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 . +X * #include Search in an implementation-dependent +X * list of places. +X * #include token Expand the token, it must be one of +X * "file" or , process as such. +X * +X * Note: the November 12 draft forbids '>' in the #include 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 delim = macroid(skipws()); +X if (delim != '<' && delim != '"') +X goto incerr; +X if (delim == '<') +X delim = '>'; +X workp = work; +X instring = TRUE; /* Accept all characters */ +X while ((c = get()) != '\n' && c != delim && c != EOF_CHAR) +X save(c); /* Put it away. */ +X skipnl(); +X /* +X * The draft is unclear if the following should be done. +X */ +X +X while (--workp >= work && (type[*workp] == SPA)) +X ; /* Trim blanks from filename */ +X +X/* +X * if (*workp != delim) +X * goto incerr; +X */ +X *(workp + 1) = EOS; /* Terminate filename */ +X instring = FALSE; +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 return; +X#else +X if (openinclude(work, (delim == '"'))) +X 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 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 if (searchlocal) { +X /* +X * Look in local directory first +X */ +X#if HOST == SYS_UNIX +X /* +X * Try to open filename relative to the directory of the current +X * source file (as opposed to the current directory). (ARF, SCK). +X */ +X if (filename[0] != '/' +X && hasdirectory(infile->filename, tmpname)) +X strcat(tmpname, filename); +X else { +X strcpy(tmpname, filename); +X } +X#else +X if (!hasdirectory(filename, tmpname) +X && hasdirectory(infile->filename, tmpname)) +X strcat(tmpname, filename); +X else { +X strcpy(tmpname, filename); +X } +X#endif +X if (openfile(tmpname)) +X 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) >= (NWORK - 1)) +X cfatal("Filename work buffer overflow", NULLST); +X else { +X#if HOST == SYS_UNIX +X if (filename[0] == '/') +X strcpy(tmpname, filename); +X else { +X sprintf(tmpname, "%s/%s", *incptr, filename); +X } +X#else +X if (!hasdirectory(filename, tmpname)) +X sprintf(tmpname, "%s%s", *incptr, filename); +X#endif +X if (openfile(tmpname)) +X return (TRUE); +X } +X } +X 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 if ((tp = strrchr(source, '/')) == NULL) +X return (FALSE); +X else { +X strncpy(result, source, tp - source + 1); +X result[tp - source + 1] = EOS; +X return (TRUE); +X } +X#else +X#if HOST == SYS_VMS +X if (vmsparse(source, NULLST, result) +X && result[0] != EOS) +X return (TRUE); +X else { +X return (FALSE); +X } +X#else +X /* +X * Random DEC operating system (RSX, RT11, RSTS/E) +X */ +X register char *tp; +X +X if ((tp = strrchr(source, ']')) == NULL +X && (tp = strrchr(source, ':')) == NULL) +X return (FALSE); +X else { +X strncpy(result, source, tp - source + 1); +X result[tp - source + 1] = EOS; +X return (TRUE); +X } +X#endif +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 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 return (TRUE); +X } +X return (FALSE); +X} +X#endif +X +END-of-cpp2.c +exit