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