diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1279d5b --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +fcpp +*.o +*~ diff --git a/FPPBase.h b/FPPBase.h new file mode 100644 index 0000000..4e76e1a --- /dev/null +++ b/FPPBase.h @@ -0,0 +1,56 @@ +/****************************************************************************** + * FREXXWARE + * ---------------------------------------------------------------------------- + * + * Project: Frexx C Preprocessor + * $Source: /home/user/start/cpp/RCS/FPPBase.h,v $ + * $Revision: 1.3 $ + * $Date: 1993/12/06 13:51:20 $ + * $Author: start $ + * $State: Exp $ + * $Locker: start $ + * + * ---------------------------------------------------------------------------- + * $Log: FPPBase.h,v $ + * Revision 1.3 1993/12/06 13:51:20 start + * A lot of new stuff (too much to mention) + * + * Revision 1.2 1993/11/11 07:16:39 start + * New stuff + * + * Revision 1.2 1993/11/11 07:16:39 start + * New stuff + * + * Revision 1.1 1993/11/03 09:15:59 start + * Initial revision + * + * + *****************************************************************************/ +#ifndef FPP_BASE_H +#define FPP_BASE_H + +/* +** $Filename: libraries/FPPbase.h $ +** $Release: 1.0 $ +** $Date: 1993/12/06 13:51:20 $ +** +** (C) Copyright 1992, 1993 by FrexxWare +** All Rights Reserved +*/ + +#include +#include + +struct FPPBase { + struct Library LibNode; + UBYTE Flags; + UBYTE pad; + /* long word aligned */ + ULONG SysLib; + ULONG DosLib; + ULONG SegList; +}; + +#define FPPNAME "fpp.library" + +#endif diff --git a/FPP_protos.h b/FPP_protos.h new file mode 100644 index 0000000..85ffb6d --- /dev/null +++ b/FPP_protos.h @@ -0,0 +1,35 @@ +/****************************************************************************** + * FREXXWARE + * ---------------------------------------------------------------------------- + * + * Project: Frexx C Preprocessor + * $Source: /home/user/start/cpp/RCS/FPP_protos.h,v $ + * $Revision: 1.3 $ + * $Date: 1993/12/06 13:51:20 $ + * $Author: start $ + * $State: Exp $ + * $Locker: start $ + * + * ---------------------------------------------------------------------------- + * $Log: FPP_protos.h,v $ + * Revision 1.3 1993/12/06 13:51:20 start + * A lot of new stuff (too much to mention) + * + * Revision 1.2 1993/11/11 07:16:39 start + * New stuff + * + * Revision 1.2 1993/11/11 07:16:39 start + * New stuff + * + * Revision 1.1 1993/11/03 09:15:59 start + * Initial revision + * + * + *****************************************************************************/ +/****************************************************** + * + * FPP_protos.h + * + *******/ + +int fppPreProcess(struct fppTag *); diff --git a/cpp.h b/cpp.h new file mode 100644 index 0000000..b60c739 --- /dev/null +++ b/cpp.h @@ -0,0 +1,249 @@ +/****************************************************************************** + * FREXXWARE + * ---------------------------------------------------------------------------- + * + * Project: Frexx C Preprocessor + * $Source: /home/user/start/cpp/RCS/cpp.h,v $ + * $Revision: 1.3 $ + * $Date: 1993/12/06 13:51:20 $ + * $Author: start $ + * $State: Exp $ + * $Locker: start $ + * + * ---------------------------------------------------------------------------- + * $Log: cpp.h,v $ + * Revision 1.3 1993/12/06 13:51:20 start + * A lot of new stuff (too much to mention) + * + * Revision 1.2 1993/11/11 07:16:39 start + * New stuff + * + * Revision 1.2 1993/11/11 07:16:39 start + * New stuff + * + * Revision 1.1 1993/11/03 09:15:59 start + * Initial revision + * + * + *****************************************************************************/ + +/* + * 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 + * + * In general, definitions in this file should not be changed. + */ + +#include +#include +#ifndef toupper +#define toupper(c) ((c) + ('A' - 'a')) +#endif /* no toupper */ +#ifndef tolower +#define tolower(c) ((c) + ('a' - 'A')) +#endif /* no tolower */ + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif +#ifndef EOS +/* + * This is predefined in Decus C + */ +#define EOS '\0' /* End of string */ +#endif +#define EOF_CHAR 0 /* Returned by get() on eof */ +#define NULLST ((char *) NULL) /* Pointer to nowhere (linted) */ +#define DEF_NOARGS (-1) /* #define foo vs #define foo() */ + +/* + * The following may need to change if the host system doesn't use ASCII. + */ +#define QUOTE_PARM 0x1C /* Magic quoting operator */ +#define DEF_MAGIC 0x1D /* Magic for #defines */ +#define TOK_SEP 0x1E /* Token concatenation delim. */ +#define COM_SEP 0x1F /* Magic comment separator */ + +/* + * Note -- in Ascii, the following will map macro formals onto DEL + the + * C1 control character region (decimal 128 .. (128 + PAR_MAC)) which will + * be ok as long as PAR_MAC is less than 33). Note that the last PAR_MAC + * value is reserved for string substitution. + */ + +#define MAC_PARM 0x7F /* Macro formals start here */ +#ifndef OS9 +#if (PAR_MAC >= 33) +#error "assertion fails -- PAR_MAC isn't less than 33" + +#endif +#endif +#define LASTPARM (PAR_MAC - 1) + +/* + * Character type codes. + */ + +#define INV 0 /* Invalid, must be zero */ +#define OP_EOE INV /* End of expression */ +#define DIG 1 /* Digit */ +#define LET 2 /* Identifier start */ +#define FIRST_BINOP OP_ADD +#define OP_ADD 3 +#define OP_SUB 4 +#define OP_MUL 5 +#define OP_DIV 6 +#define OP_MOD 7 +#define OP_ASL 8 +#define OP_ASR 9 +#define OP_AND 10 /* &, not && */ +#define OP_OR 11 /* |, not || */ +#define OP_XOR 12 +#define OP_EQ 13 +#define OP_NE 14 +#define OP_LT 15 +#define OP_LE 16 +#define OP_GE 17 +#define OP_GT 18 +#define OP_ANA 19 /* && */ +#define OP_ORO 20 /* || */ +#define OP_QUE 21 /* ? */ +#define OP_COL 22 /* : */ +#define OP_CMA 23 /* , (relevant?) */ +#define LAST_BINOP OP_CMA /* Last binary operand */ +/* + * The following are unary. + */ +#define FIRST_UNOP OP_PLU /* First Unary operand */ +#define OP_PLU 24 /* + (draft ANSI standard) */ +#define OP_NEG 25 /* - */ +#define OP_COM 26 /* ~ */ +#define OP_NOT 27 /* ! */ +#define LAST_UNOP OP_NOT +#define OP_LPA 28 /* ( */ +#define OP_RPA 29 /* ) */ +#define OP_END 30 /* End of expression marker */ +#define OP_MAX (OP_END + 1) /* Number of operators */ +#define OP_FAIL (OP_END + 1) /* For error returns */ + +/* + * The following are for lexical scanning only. + */ + +#define QUO 65 /* Both flavors of quotation */ +#define DOT 66 /* . might start a number */ +#define SPA 67 /* Space and tab */ +#define BSH 68 /* Just a backslash */ +#define END 69 /* EOF */ + +/* + * These bits are set in ifstack[] + */ +#define WAS_COMPILING 1 /* TRUE if compile set at entry */ +#define ELSE_SEEN 2 /* TRUE when #else processed */ +#define TRUE_SEEN 4 /* TRUE when #if TRUE processed */ + +/* + * Define bits for the basic types and their adjectives + */ + +#define T_CHAR 1 +#define T_INT 2 +#define T_FLOAT 4 +#define T_DOUBLE 8 +#define T_SHORT 16 +#define T_LONG 32 +#define T_SIGNED 64 +#define T_UNSIGNED 128 +#define T_PTR 256 /* Pointer */ +#define T_FPTR 512 /* Pointer to functions */ + +/* + * The DEFBUF structure stores information about #defined + * macros. Note that the defbuf->repl information is always + * in malloc storage. + */ + +typedef struct defbuf { + struct defbuf *link; /* Next define in chain */ + char *repl; /* -> replacement */ + int hash; /* Symbol table hash */ + int nargs; /* For define(args) */ + char name[1]; /* #define name */ +} DEFBUF; + +/* + * The FILEINFO structure stores information about open files + * and macros being expanded. + */ + +typedef struct fileinfo { + char *bptr; /* Buffer pointer */ + int line; /* for include or macro */ + FILE *fp; /* File if non-null */ + struct fileinfo *parent; /* Link to includer */ + char *filename; /* File/macro name */ + char *progname; /* From #line statement */ + unsigned int unrecur; /* For macro recursion */ + char buffer[1]; /* current input line */ +} FILEINFO; + +/* + * The SIZES structure is used to store the values for #if sizeof + */ + +typedef struct sizes { + short bits; /* If this bit is set, */ + short size; /* this is the datum size value */ + short psize; /* this is the pointer size */ +} SIZES; +/* + * nomacarg is a built-in #define on Decus C. + */ + +#ifdef nomacarg +#define cput output /* cput concatenates tokens */ +#else +#if COMMENT_INVISIBLE +#define cput(c) { if (c != TOK_SEP && c != COM_SEP) putchar(c); } +#else +#define cput(c) { if (c != TOK_SEP) putchar(c); } +#endif +#endif + +#ifndef nomacarg +#define streq(s1, s2) (strcmp(s1, s2) == 0) +#endif + +/* + * Note: IO_NORMAL and IO_ERROR are defined in the Decus C stdio.h file + */ +#ifndef IO_NORMAL +#define IO_NORMAL 0 +#endif +#ifndef IO_ERROR +#define IO_ERROR 1 +#endif + +/* + * Externs + */ + +#include "fpp.h" /* structs and defines */ +#include "cppadd.h" /* Added prototypes for ANSI complience! */ + +#ifdef AMIGA +#include +extern int _OSERR; +#endif + +extern char type[]; /* Character classifier */ + +#define compiling global->ifstack[0] +#if DEBUG +extern int debug; /* Debug level */ +#endif +extern SIZES size_table[]; /* For #if sizeof sizes */ + +#define MAX_SPACE_SIZE 512 /* maximum number of whitespaces possible + to remember */ diff --git a/cpp1.c b/cpp1.c new file mode 100644 index 0000000..d00e4fc --- /dev/null +++ b/cpp1.c @@ -0,0 +1,767 @@ +#ifdef RCS +static char rcsid[]="$Id: cpp1.c,v 1.8 1994/06/02 09:10:34 start Exp $"; +#endif +/****************************************************************************** +Copyright (c) 1999 Daniel Stenberg + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE +SOFTWARE. +******************************************************************************/ +/****************************************************************************** + * FREXXWARE + * ---------------------------------------------------------------------------- + * + * Project: Frexx C Preprocessor + * $Source: /home/user/start/cpp/RCS/cpp1.c,v $ + * $Revision: 1.8 $ + * $Date: 1994/06/02 09:10:34 $ + * $Author: start $ + * $State: Exp $ + * $Locker: $ + * + * ---------------------------------------------------------------------------- + * $Log: cpp1.c,v $ + * Revision 1.8 1994/06/02 09:10:34 start + * Made the function definition prinout to be more verbose + * + * Revision 1.7 1994/06/02 08:48:55 start + * Made the initial function routine work + * Added initial function exclusion list + * Added function names output + * + * Revision 1.6 1994/01/24 09:32:22 start + * Fixed the #line-option a bit. + * + * Revision 1.5 1993/12/06 13:50:39 start + * A lot of new stuff (too much to mention) + * + * Revision 1.5 1993/12/06 13:50:39 start + * A lot of new stuff (too much to mention) + * + * Revision 1.4 1993/12/02 15:10:56 start + * Lots of new features. + * + * Revision 1.3 1993/11/29 14:00:32 start + * new + * + * Revision 1.2 1993/11/11 07:16:39 start + * New stuff + * + * Revision 1.1 1993/11/03 09:13:08 start + * Initial revision + * + * + *****************************************************************************/ +/* + * CPP main program. + * + * Edit history + * 21-May-84 MM "Field test" release + * 23-May-84 MM Some minor hacks. + * 30-May-84 ARF Didn't get enough memory for __DATE__ + * Added code to read stdin if no input + * files are provided. + * 29-Jun-84 MM Added ARF's suggestions, Unixifying cpp. + * 11-Jul-84 MM "Official" first release (that's what I thought!) + * 22-Jul-84 MM/ARF/SCK Fixed line number bugs, added cpp recognition + * of #line, fixed problems with #include. + * 23-Jul-84 MM More (minor) include hacking, some documentation. + * Also, redid cpp's #include files + * 25-Jul-84 MM #line filename isn't used for #include searchlist + * #line format is + * 25-Jul-84 ARF/MM Various bugs, mostly serious. Removed homemade doprint + * 01-Aug-84 MM Fixed recursion bug, remove extra newlines and + * leading whitespace from cpp output. + * 02-Aug-84 MM Hacked (i.e. optimized) out blank lines and unneeded + * whitespace in general. Cleaned up unget()'s. + * 03-Aug-84 Keie Several bug fixes from Ed Keizer, Vrije Universitet. + * -- corrected arg. count in -D and pre-defined + * macros. Also, allow \n inside macro actual parameter + * lists. + * 06-Aug-84 MM If debugging, dump the preset vector at startup. + * 12-Aug-84 MM/SCK Some small changes from Sam Kendall + * 15-Aug-84 Keie/MM cerror, cwarn, etc. take a single string arg. + * cierror, etc. take a single int. arg. + * changed LINE_PREFIX slightly so it can be + * changed in the makefile. + * 31-Aug-84 MM USENET net.sources release. + * 7-Sep-84 SCH/ado Lint complaints + * 10-Sep-84 Keie Char's can't be signed in some implementations + * 11-Sep-84 ado Added -C flag, pathological line number fix + * 13-Sep-84 ado Added -E flag (does nothing) and "-" file for stdin. + * 14-Sep-84 MM Allow # 123 as a synonym for #line 123 + * 19-Sep-84 MM scanid always reads to token, make sure #line is + * written to a new line, even if -C switch given. + * Also, cpp - - reads stdin, writes stdout. + * 03-Oct-84 ado/MM Several changes to line counting and keepcomments + * stuff. Also a rewritten control() hasher -- much + * simpler and no less "perfect". Note also changes + * in cpp3.c to fix numeric scanning. + * 04-Oct-84 MM Added recognition of macro formal parameters if + * they are the only thing in a string, per the + * draft standard. + * 08-Oct-84 MM One more attack on scannumber + * 15-Oct-84 MM/ado Added -N to disable predefined symbols. Fixed + * linecount if COMMENT_INVISIBLE enabled. + * 22-Oct-84 MM Don't evaluate the #if/#ifdef argument if + * compilation is supressed. This prevents + * unnecessary error messages in sequences such as + * #ifdef FOO -- undefined + * #if FOO == 10 -- shouldn't print warning + * 25-Oct-84 MM Fixed bug in false ifdef supression. On vms, + * #include should open foo.h -- this duplicates + * the behavior of Vax-C + * 31-Oct-84 ado/MM Parametized $ in indentifiers. Added a better + * token concatenator and took out the trial + * concatenation code. Also improved #ifdef code + * and cleaned up the macro recursion tester. + * 2-Nov-84 MM/ado Some bug fixes in token concatenation, also + * a variety of minor (uninteresting) hacks. + * 6-Nov-84 MM Happy Birthday. Broke into 4 files and added + * #if sizeof (basic_types) + * 9-Nov-84 MM Added -S* for pointer type sizes + * 13-Nov-84 MM Split cpp1.c, added vms defaulting + * 23-Nov-84 MM/ado -E supresses error exit, added CPP_INCLUDE, + * fixed strncpy bug. + * 3-Dec-84 ado/MM Added OLD_PREPROCESSOR + * 7-Dec-84 MM Stuff in Nov 12 Draft Standard + * 17-Dec-84 george Fixed problems with recursive macros + * 17-Dec-84 MM Yet another attack on #if's (f/t)level removed. + * 07-Jan-85 ado Init defines before doing command line options + * so -Uunix works. + * 21-Oct-85 RMS Rename `token' to `tokenbuf'. + * Allocate it dynamically, with size in `tokenbsize'. + * 23-Oct-85 RMS Do not print message about number of errors. + * 14-Mar-85 FNF Incorporate macro based C debugging package. + * Port to Commodore AMIGA. + * 20-Aug-88 Ois Changed format of documentation. + * Feb-93 DST + + Daniel Stenberg. Started enhancing the `cpp' in February 1993: + + o Allows C++ comments. + o Ported to ANSI C and to SAS/C 6.0. + o Changed entire indent- and statement- layout previously used! + o Changed hash sizing to any-number-hash-size. + o Removed every global variable. + o Made the cpp startable by creating a taglist and call the cpp. + o Made a shared library of it, called FPP: "Frexx PreProcessor" + o Changed the amiga version to use realloc(). + o Removed all VMS defines. Who wants such? + o Changed it from Public Domain to Freeware. + o Moved out the include directory assigning to only be a part of + the taglist and _no_ internal at all! + o Made `fpp' accept input from a user specified function instead + of always the stdin stream. This makes it possible to preprocess + almost anything. An output routine is also implemented. + o I have discovered that this program needs a lot of re-writing + since a amiga shared library can't exit() as this `cpp' + does on a fatal error... I made all necessary changes! Now most functions + leave a return code telling success/failure (*MAJOR* re-writing! :-(). + o The original 50-60 gotos in the source codes have been decreased + to only a few. I *HATE* gotos in C programs! + o Changed all cwarn(), cerror() cfatal(), ciwarn(), cierror() functions to + the one and all function `cerror()', which will accept a variable number + of arguments to build message from. + o Moved all error/warning/fatal texts to domsg(). + o All error output can be received in the error function (and have to in the + amiga library version!). + o Found out that my test.c caused 53 malloc() but only 25 free()... Inserted + my own Malloc(), Free(), FreeAll() and Realloc() to always remove alloced + memory when finishing the preprocessing (ok, malloc/free does that for us, + but I don't want to use/depend on them). + o Compiling into a shared library under AmigaDos still needs some changes. + fopen() and other similar function in SAS/C use symbols I don't want it + to... eg. _ProgramName and _XCEXIT! + */ + +#include +#include +#include "cppdef.h" +#include "cpp.h" + +#if defined(AMIGA) +#include +#if defined(SHARED) +int _OSERR=0; +char *_ProgramName="junk"; +void __stdargs _XCEXIT(long a) { return; } +#endif +#endif + +FILE_LOCAL ReturnCode output(struct Global *, int); /* Output one character */ +FILE_LOCAL void sharp(struct Global *); +INLINE FILE_LOCAL ReturnCode cppmain(struct Global *); + +int PREFIX fppPreProcess(REG(a0) struct fppTag *tags) +{ + int i=0; + ReturnCode ret; /* cpp return code */ + struct Global *global; + + global=(struct Global *)Malloc(sizeof(struct Global)); + if(!global) + return(FPP_OUT_OF_MEMORY); + + memset(global, 0, sizeof(struct Global)); + + global->infile=NULL; + global->line=0; + global->wrongline=0; + global->errors=0; + global->recursion=0; + global->rec_recover=TRUE; + global->instring=FALSE; + global->inmacro=FALSE; + global->workp=NULL; + global->keepcomments = FALSE; /* Write out comments flag */ + global->cflag = FALSE; /* -C option (keep comments) */ + global->eflag = FALSE; /* -E option (never fail) */ + global->nflag = 0; /* -N option (no predefines) */ + global->wflag = FALSE; /* -W option (write #defines) */ + + global->ifstack[0]=TRUE; /* #if information */ + global->ifptr = global->ifstack; + global->incend = global->incdir; + + /* names defined at cpp start */ + global->preset[0]="frexxcpp"; /* This is the Frexx cpp program */ +#if defined( amiga ) + global->preset[1]="amiga"; + global->preset[2]="m68000"; + global->preset[3]="amigados"; + global->preset[4]= NULL; /* Must be last */ +#elif defined( unix ) + global->preset[1]="unix"; + global->preset[2]= NULL; +#endif + + /* Note: order is important */ + global->magic[0] = "__LINE__"; + global->magic[1] = "__FILE__"; + global->magic[2] = "__FUNCTION__"; + global->magic[3] = "__FUNC_LINE__"; + global->magic[4] = NULL; /* Must be last */ + + global->funcline = 0; + + global->cplusplus=1; + global->sharpfilename=NULL; + + global->parmp=NULL; + global->nargs=0; + + global->macro=NULL; + global->evalue=0; + + global->input=NULL; + global->output=NULL; + global->error=NULL; + global->first_file=NULL; + global->userdata=NULL; + + global->linelines=TRUE; + global->warnillegalcpp = FALSE; + global->outputLINE = TRUE; + global->warnnoinclude = TRUE; + global->showversion = TRUE; + global->showincluded = FALSE; + global->showspace = FALSE; + global->nestcomments = FALSE; + global->warnnestcomments = FALSE; + global->outputfile = TRUE; + global->included = 0; + + global->comment = FALSE; + global->rightconcat = FALSE; + global->work[0] = '\0'; + global->initialfunc = NULL; + + memset(global->symtab, 0, SBSIZE * sizeof(DEFBUF *)); + + ret=initdefines(global); /* O.S. specific def's */ + if(ret) + return(ret); + dooptions(global, tags); /* Command line -flags */ + ret=addfile(global, stdin, global->work); /* "open" main input file */ + + global->out = global->outputfile; + + if(!ret) + ret=cppmain(global); /* Process main file */ + if ((i = (global->ifptr - global->ifstack)) != 0) { +#if OLD_PREPROCESSOR + cwarn(global, ERROR_IFDEF_DEPTH, i); +#else + cerror(global, ERROR_IFDEF_DEPTH, i); +#endif + } + fflush(stdout); + fclose(stdout); + + FreeAll(); /* free all unfreed memory! */ + + if (global->errors > 0 && !global->eflag) + return(IO_ERROR); + return(IO_NORMAL); /* No errors or -E option set */ +} + +INLINE FILE_LOCAL +ReturnCode cppmain(struct Global *global) +{ + /* + * Main process for cpp -- copies tokens from the current input + * stream (main file, include file, or a macro) to the output + * file. + */ + + int c; /* Current character */ + int counter; /* newlines and spaces */ + ReturnCode ret; /* return code variable type */ + + long bracelevel = 0; + long parenlevel = 0; + long bracketlevel = 0; + int fake = 0; + +#define MAX_FUNC_LENGTH 50 + + char tempfunc[MAX_FUNC_LENGTH + 1]; + char tempfunc2[MAX_FUNC_LENGTH + 1]; + char define = 0; /* probability of a function define phase in the program */ + char prev = 0; /* previous type */ + char go = 0; + char include = 0; + char initfunc = 0; + + /* Initialize for reading tokens */ + global->tokenbsize = 50; + global->tokenbuf = Getmem(global, global->tokenbsize + 1); + if(!global->tokenbuf) + return(FPP_OUT_OF_MEMORY); + + global->functionname = Getmem(global, global->tokenbsize + 1); + if(!global->functionname) + return(FPP_OUT_OF_MEMORY); + global->functionname[0] = '\0'; + + if(global->showspace) { + global->spacebuf = (char *)Getmem(global, MAX_SPACE_SIZE); + if(!global->spacebuf) + return(FPP_OUT_OF_MEMORY); + } + + if(global->showversion) + Error(global, VERSION_TEXT); + + /* + * Explicitly output a #line at the start of cpp output so + * that lint (etc.) knows the name of the original source + * file. If we don't do this explicitly, we may get + * the name of the first #include file instead. + */ + if(global->linelines) /* if #line lines are wanted! */ + sharp(global); + /* + * This loop is started "from the top" at the beginning of each line + * wrongline is set TRUE in many places if it is necessary to write + * a #line record. (But we don't write them when expanding macros.) + * + * The counter variable has two different uses: at + * the start of a line, it counts the number of blank lines that + * have been skipped over. These are then either output via + * #line records or by outputting explicit blank lines. + * When expanding tokens within a line, the counter remembers + * whether a blank/tab has been output. These are dropped + * at the end of the line, and replaced by a single blank + * within lines. + */ + + include = global->included; + + while(include--) { + openinclude(global, global->include[include], TRUE); + } + + for (;;) { + counter = 0; /* Count empty lines */ + for (;;) { /* For each line, ... */ + global->comment = FALSE; /* No comment yet! */ + global->chpos = 0; /* Count whitespaces */ + while (type[(c = get(global))] == SPA) /* Skip leading blanks */ + if(global->showspace) { + if(global->chposspacebuf[global->chpos++]=(char)c; + } + if (c == '\n') { /* If line's all blank, */ + if(global->comment) { + /* A comment was output! */ + Putchar(global, '\n'); + } + else + ++counter; /* Do nothing now */ + } + else if (c == '#') { /* Is 1st non-space '#' */ + global->keepcomments = FALSE; /* Don't pass comments */ + ret = control(global, &counter); /* Yes, do a #command */ + if(ret) + return(ret); + global->keepcomments = (global->cflag && compiling); + } + else if (c == EOF_CHAR) /* At end of file? */ + break; + else if (!compiling) { /* #ifdef false? */ + skipnl(global); /* Skip to newline */ + counter++; /* Count it, too. */ + } else { + break; /* Actual token */ + } + } + if (c == EOF_CHAR) /* Exit process at */ + break; /* End of file */ + /* + * If the loop didn't terminate because of end of file, we + * know there is a token to compile. First, clean up after + * absorbing newlines. counter has the number we skipped. + */ + if(global->linelines) { /* if #line lines are wanted! */ + if ((global->wrongline && global->infile->fp != NULL) || counter > 4) + sharp(global); /* Output # line number */ + else { /* If just a few, stuff */ + while (--counter >= 0) /* them out ourselves */ + Putchar(global, (int)'\n'); + } + } + if(global->showspace) { + /* Show all whitespaces! */ + global->spacebuf[global->chpos] = '\0'; + Putstring(global, global->spacebuf); + } + + /* + * Process each token on this line. + */ + unget(global); /* Reread the char. */ + for (;;) { /* For the whole line, */ + do { /* Token concat. loop */ + for (global->chpos = counter = 0; (type[(c = get(global))] == SPA);) { +#if COMMENT_INVISIBLE + if (c != COM_SEP) + counter++; +#else + if(global->showspace && global->chpos < MAX_SPACE_SIZE-1) { + global->spacebuf[global->chpos++]=(char)c; + } + counter++; /* Skip over blanks */ +#endif + } + if (c == EOF_CHAR || c == '\n') + break; /* Exit line loop */ + else if (counter > 0) { /* If we got any spaces */ + if(!global->showspace) /* We don't output all spaces */ + Putchar(global, (int)' ');/* Output one space */ + else { + global->spacebuf[global->chpos] = '\0'; + Putstring(global, global->spacebuf); /* Output all whitespaces */ + } + } + if(ret=macroid(global, &c)) /* Grab the token */ + return(ret); + } while (type[c] == LET && catenate(global, &ret) && !ret); + if(ret) + /* If the loop was broken because of a fatal error! */ + return(ret); + if (c == EOF_CHAR || c == '\n') /* From macro exp error */ + break; /* Exit line loop */ + go++; + switch (type[c]) { + case LET: + go =0; + /* Quite ordinary token */ + Putstring(global, global->tokenbuf); + + if(!define) { + /* Copy the name */ + strncpy(tempfunc, global->tokenbuf, MAX_FUNC_LENGTH); + tempfunc[MAX_FUNC_LENGTH]=0; + } + /* fputs(global->tokenbuf, stdout); */ + break; + case DIG: /* Output a number */ + case DOT: /* Dot may begin floats */ + go = 0; + ret=scannumber(global, c, (ReturnCode(*)(struct Global *, int))output); + if(ret) + return(ret); + break; + case QUO: /* char or string const */ + go = 0; + /* Copy it to output */ + if(!global->webmode) { + ret=scanstring(global, c, + (ReturnCode(*)(struct Global *, int))output); + if(ret) + return(ret); + break; + } + /* FALLTHROUGH */ + default: /* Some other character */ + + define++; + switch(c) { + case '{': + if(! bracelevel++ && define > 2) { + /* + * This is a starting brace. If there is a probability of a + * function defining, we copy the `tempfunc' function name to + * `global->functionname'. + */ + strcpy(global->functionname, tempfunc2); + global->funcline = global->line; + + if(global->outputfunctions) { + /* + * Output the discovered function name to stderr! + */ + Error(global, "#> Function defined at line %d: %s <#\n", + global->line, + global->functionname); + } + + if(global->initialfunc) { + int a; + for(a=0; aexcluded; a++) { + /* check for excluded functions */ + if(!strcmp(global->functionname, + global->excludedinit[a])) + break; + } + if(a==global->excluded) { + expstuff(global, "__brace__", "{"); + expstuff(global, "__init_func__", global->initialfunc); + initfunc = TRUE; + } + } + + } + break; + case '}': + go = 0; + if( (--bracelevel == initfunc) && + strcmp(global->infile->filename, "__init_func__") ) { + /* we just stepped out of the function! */ + global->functionname[0] = '\0'; + global->funcline = 0; + define = 1; + + if(initfunc) { + Putchar(global, '}'); + bracelevel--; + initfunc=0; + } + } + fake = 0; + break; + + case ';': + case ',': + if(go == 2) { + define = 1; + fake = 0; + go--; + break; + } + break; + case '(': + if(! parenlevel++ && !bracelevel) { + if(go == 2) { + /* foobar(text) -> "(" is found. This can't be a + function */ + go--; + define = 1; + break; + } + if( define < 2 && prev == LET) { + /* This is the first parenthesis on the ground brace + level, and we did previously not have a probable + function name */ + strncpy(tempfunc2, global->tokenbuf, MAX_FUNC_LENGTH); + tempfunc2[MAX_FUNC_LENGTH]=0; + define++; + } + else { + /* we have a fake start */ + fake++; + } + } + break; + case ')': + if(! --parenlevel && !bracelevel && define>1 && !fake) { + /* + * The starting parentheses level and + * the starting brace level. + * This might be the start of a function defining coming + * up! + */ + define++; /* increase probability */ + fake = 0; + go = 1; + } + break; + case '[': + bracketlevel++; + break; + case ']': + bracketlevel--; + break; + } + define--; /* decrease function probability */ + + Putchar(global, c); /* Just output it */ + break; + } /* Switch ends */ + prev = type[c]; + } /* Line for loop */ + + if (c == '\n') { /* Compiling at EOL? */ + Putchar(global, '\n'); /* Output newline, if */ + if (global->infile->fp == NULL) /* Expanding a macro, */ + global->wrongline = TRUE; /* Output # line later */ + } + } /* Continue until EOF */ + + if(global->showbalance) { + if(bracketlevel) { + cwarn(global, WARN_BRACKET_DEPTH, bracketlevel); + } + if(parenlevel) { + cwarn(global, WARN_PAREN_DEPTH, parenlevel); + } + if(bracelevel) { + cwarn(global, WARN_BRACE_DEPTH, bracelevel); + } + } + if (global->wflag) { + global->out = TRUE; /* enable output */ + outdefines(global); /* Write out #defines */ + } + return(FPP_OK); +} + +FILE_LOCAL +ReturnCode output(struct Global *global, int c) +{ + /* + * Output one character to stdout -- output() is passed as an + * argument to scanstring() + */ +#if COMMENT_INVISIBLE + if (c != TOK_SEP && c != COM_SEP) +#else + if (c != TOK_SEP) +#endif + Putchar(global, c); + return(FPP_OK); +} + +void Putchar(struct Global *global, int c) +{ + /* + * Output one character to stdout or to output function! + */ + if(!global->out) + return; +#if defined(UNIX) + if(global->output) + global->output(c, global->userdata); + else + putchar(c); +#else /* amiga */ + global->output(c, global->userdata); +#endif +} + +void Putstring(struct Global *global, char *string) +{ + /* + * Output a string! One letter at a time to the Putchar routine! + */ + + if(!string) + return; + + while(*string) + Putchar(global, *string++); +} + +void Putint(struct Global *global, int number) +{ + /* + * Output the number as a string. + */ + + char buffer[16]; /* an integer can't be that big! */ + char *point=buffer; + + sprintf(buffer, "%d", number); + + while(*point) + Putchar(global, *point++); +} + + +FILE_LOCAL +void sharp(struct Global *global) +{ + /* + * Output a line number line. + */ + + char *name; + if (global->keepcomments) /* Make sure # comes on */ + Putchar(global, '\n'); /* a fresh, new line. */ + /* printf("#%s %d", LINE_PREFIX, global->line); */ + + Putchar(global, '#'); + if(global->outputLINE) + Putstring(global, LINE_PREFIX); + Putchar(global, ' '); + Putint(global, global->line); + + if (global->infile->fp != NULL) { + name = (global->infile->progname != NULL) + ? global->infile->progname : global->infile->filename; + if (global->sharpfilename == NULL + || (global->sharpfilename != NULL && !streq(name, global->sharpfilename))) { + if (global->sharpfilename != NULL) + Freemem(global->sharpfilename); + global->sharpfilename = savestring(global, name); + /* printf(" \"%s\"", name); */ + Putstring(global, " \""); + Putstring(global, name); + Putchar(global, '\"'); + } + } + Putchar(global, '\n'); + global->wrongline = FALSE; + return; +} diff --git a/cpp2.c b/cpp2.c new file mode 100644 index 0000000..8e371a0 --- /dev/null +++ b/cpp2.c @@ -0,0 +1,875 @@ +#ifdef RCS +static char rcsid[]="$Id: cpp2.c,v 1.5 1994/01/24 09:32:54 start Exp start $"; +#endif +/****************************************************************************** +Copyright (c) 1999 Daniel Stenberg + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE +SOFTWARE. +******************************************************************************/ +/****************************************************************************** + * FREXXWARE + * ---------------------------------------------------------------------------- + * + * Project: Frexx C Preprocessor + * $Source: /home/user/start/cpp/RCS/cpp2.c,v $ + * $Revision: 1.5 $ + * $Date: 1994/01/24 09:32:54 $ + * $Author: start $ + * $State: Exp $ + * $Locker: start $ + * + * ---------------------------------------------------------------------------- + * $Log: cpp2.c,v $ + * Revision 1.5 1994/01/24 09:32:54 start + * Fixed AmigaDOS include file routine. + * + * Revision 1.4 1993/12/06 13:50:39 start + * A lot of new stuff (too much to mention) + * + * Revision 1.4 1993/12/06 13:50:39 start + * A lot of new stuff (too much to mention) + * + * Revision 1.3 1993/11/29 14:00:32 start + * new + * + * Revision 1.2 1993/11/11 07:16:39 start + * New stuff + * + * Revision 1.1 1993/11/03 09:13:08 start + * Initial revision + * + * + *****************************************************************************/ +/* + * C P P 2 . C + * + * Process #control lines + * + * Edit history + * 13-Nov-84 MM Split from cpp1.c + * 21-Oct-85 RMS Do not turn on `instring' while reading #include arg. + * Rename `token' to `tokenbuf'. + * Flush tabs at end of #include line, like spaces. + * 14-Mar-86 FNF Incorporate macro based C debugging package. + * Port to Commodore AMIGA. + * 25-May-86 FNF Change handling of fully qualified include file + * pathnames (like "/usr/include/stdio.h" for unix, + * or "df0:include/stdio.h" for the Amiga) to be + * used verbatum in the first open attempt. + * 20-Aug-88 Ois Added #error. Passed unrecognized # commands. + * Added \n when those lines are passed. + */ + +#include +#include +#include "cppdef.h" +#include "cpp.h" + +#ifdef _AMIGA +#include +#endif + +FILE_LOCAL void dump_line(struct Global *, int *); +FILE_LOCAL ReturnCode doif(struct Global *, int); +INLINE FILE_LOCAL ReturnCode doinclude(struct Global *); +INLINE FILE_LOCAL int hasdirectory(char *, char *); + + +/* + * Generate (by hand-inspection) a set of unique values for each control + * operator. Note that this is not guaranteed to work for non-Ascii + * machines. CPP won't compile if there are hash conflicts. + */ + +#define L_assert ('a' + ('s' << 1)) +#define L_define ('d' + ('f' << 1)) +#define L_elif ('e' + ('i' << 1)) +#define L_else ('e' + ('s' << 1)) +#define L_endif ('e' + ('d' << 1)) +#define L_error ('e' + ('r' << 1)) +#define L_if ('i' + (EOS << 1)) +#define L_ifdef ('i' + ('d' << 1)) +#define L_ifndef ('i' + ('n' << 1)) +#define L_include ('i' + ('c' << 1)) +#define L_line ('l' + ('n' << 1)) +#define L_nogood (EOS + (EOS << 1)) /* To catch #i */ +#define L_pragma ('p' + ('a' << 1)) +#define L_undef ('u' + ('d' << 1)) + +ReturnCode control( struct Global *global, + int *counter ) /* Pending newline counter */ +{ + /* + * Process #control lines. Simple commands are processed inline, + * while complex commands have their own subroutines. + * + * The counter is used to force out a newline before #line, and + * #pragma commands. This prevents these commands from ending up at + * the end of the previous line if cpp is invoked with the -C option. + */ + + int c; + char *tp; + int hash; + char *ep; + ReturnCode ret; + + c = skipws( global ); + + if( c == '\n' || c == EOF_CHAR ) + { + (*counter)++; + + return(FPP_OK); + } + + if( !isdigit(c) ) + scanid( global, c ); /* Get #word to tokenbuf */ + else + { + unget( global ); /* Hack -- allow #123 as a */ + + strcpy( global->tokenbuf, "line" ); /* synonym for #line 123 */ + } + + hash = (global->tokenbuf[1] == EOS) ? L_nogood : (global->tokenbuf[0] + (global->tokenbuf[2] << 1)); + + switch( hash ) + { + case L_assert: + tp = "assert"; + break; + case L_define: + tp = "define"; + break; + case L_elif: + tp = "elif"; + break; + case L_else: + tp = "else"; + break; + case L_endif: + tp = "endif"; + break; + case L_error: + tp = "error"; + break; + case L_if: + tp = "if"; + break; + case L_ifdef: + tp = "ifdef"; + break; + case L_ifndef: + tp = "ifndef"; + break; + case L_include: + tp = "include"; + break; + case L_line: + tp = "line"; + break; + case L_pragma: + tp = "pragma"; + break; + case L_undef: + tp = "undef"; + break; + default: + hash = L_nogood; + case L_nogood: + tp = ""; + break; + } + + if( !streq( tp, global->tokenbuf ) ) + hash = L_nogood; + + /* + * hash is set to a unique value corresponding to the + * control keyword (or L_nogood if we think it's nonsense). + */ + if( global->infile->fp == NULL ) + cwarn( global, WARN_CONTROL_LINE_IN_MACRO, global->tokenbuf ); + + if( !compiling ) + { /* Not compiling now */ + switch( hash ) + { + case L_if: /* These can't turn */ + case L_ifdef: /* compilation on, but */ + case L_ifndef: /* we must nest #if's */ + if( ++global->ifptr >= &global->ifstack[BLK_NEST] ) + { + cfatal( global, FATAL_TOO_MANY_NESTINGS, global->tokenbuf ); + + return( FPP_TOO_MANY_NESTED_STATEMENTS ); + } + + *global->ifptr = 0; /* !WAS_COMPILING */ + + case L_line: /* Many */ + /* + * Are pragma's always processed? + */ + case L_pragma: /* options */ + case L_include: /* are uninteresting */ + case L_define: /* if we */ + case L_undef: /* aren't */ + case L_assert: /* compiling. */ + case L_error: + dump_line( global, counter ); /* Ignore rest of line */ + return(FPP_OK); + } + } + /* + * Make sure that #line and #pragma are output on a fresh line. + */ + if( *counter > 0 && (hash == L_line || hash == L_pragma) ) + { + Putchar( global, '\n' ); + + (*counter)--; + } + + switch( hash ) + { + case L_line: + /* + * Parse the line to update the line number and "progname" + * field and line number for the next input line. + * Set wrongline to force it out later. + */ + c = skipws( global ); + + global->workp = global->work; /* Save name in work */ + + while( c != '\n' && c != EOF_CHAR ) + { + if( ret = save( global, c ) ) + return(ret); + + c = get( global ); + } + + unget( global ); + + if( ret = save( global, EOS ) ) + return(ret); + + /* + * Split #line argument into and + * We subtract 1 as we want the number of the next line. + */ + global->line = atoi(global->work) - 1; /* Reset line number */ + + for( tp = global->work; isdigit(*tp) || type[*tp] == SPA; tp++) + ; /* Skip over digits */ + + if( *tp != EOS ) + { + /* Got a filename, so: */ + + if( *tp == '"' && (ep = strrchr(tp + 1, '"')) != NULL ) + { + tp++; /* Skip over left quote */ + + *ep = EOS; /* And ignore right one */ + } + + if( global->infile->progname != NULL ) + /* Give up the old name if it's allocated. */ + Freemem( global->infile->progname ); + + global->infile->progname = savestring( global, tp ); + } + + global->wrongline = TRUE; /* Force output later */ + break; + + case L_include: + ret = doinclude( global ); + if( ret ) + return(ret); + break; + + case L_define: + ret = dodefine( global ); + if( ret ) + return(ret); + break; + + case L_undef: + doundef( global ); + break; + + case L_else: + if( global->ifptr == &global->ifstack[0] ) + { + cerror( global, ERROR_STRING_MUST_BE_IF, global->tokenbuf ); + + dump_line( global, counter ); + + return( FPP_OK ); + } + else if( (*global->ifptr & ELSE_SEEN) != 0 ) + { + cerror( global, ERROR_STRING_MAY_NOT_FOLLOW_ELSE, global->tokenbuf ); + + dump_line( global, counter ); + + return( FPP_OK ); + } + + *global->ifptr |= ELSE_SEEN; + + if( (*global->ifptr & WAS_COMPILING) != 0 ) + { + if( compiling || (*global->ifptr & TRUE_SEEN) != 0 ) + compiling = FALSE; + else + { + compiling = TRUE; + } + } + break; + + case L_elif: + if( global->ifptr == &global->ifstack[0] ) + { + cerror( global, ERROR_STRING_MUST_BE_IF, global->tokenbuf ); + + dump_line( global, counter ); + + return( FPP_OK ); + } + else if( (*global->ifptr & ELSE_SEEN) != 0 ) + { + cerror( global, ERROR_STRING_MAY_NOT_FOLLOW_ELSE, global->tokenbuf ); + + dump_line( global, counter ); + + return( FPP_OK ); + } + + if( (*global->ifptr & (WAS_COMPILING | TRUE_SEEN)) != WAS_COMPILING ) + { + compiling = FALSE; /* Done compiling stuff */ + + dump_line( global, counter ); /* Skip this clause */ + + return( FPP_OK ); + } + + ret = doif( global, L_if ); + + if( ret ) + return(ret); + + break; + + case L_error: + cerror(global, ERROR_ERROR); + break; + + case L_if: + case L_ifdef: + case L_ifndef: + if( ++global->ifptr < &global->ifstack[BLK_NEST] ) + { + *global->ifptr = WAS_COMPILING; + + ret = doif( global, hash ); + + if( ret ) + return(ret); + + break; + } + + cfatal( global, FATAL_TOO_MANY_NESTINGS, global->tokenbuf ); + + return( FPP_TOO_MANY_NESTED_STATEMENTS ); + + case L_endif: + if( global->ifptr == &global->ifstack[0] ) + { + cerror( global, ERROR_STRING_MUST_BE_IF, global->tokenbuf ); + + dump_line( global, counter ); + + return(FPP_OK); + } + + if( !compiling && (*global->ifptr & WAS_COMPILING) != 0 ) + global->wrongline = TRUE; + + compiling = ((*global->ifptr & WAS_COMPILING) != 0); + + --global->ifptr; + + break; + + case L_assert: + { + int result; + + ret = eval( global, &result ); + + if(ret) + return(ret); + + if( result == 0 ) + cerror( global, ERROR_PREPROC_FAILURE ); + } + break; + + case L_pragma: + /* + * #pragma is provided to pass "options" to later + * passes of the compiler. cpp doesn't have any yet. + */ + Putstring( global, "#pragma " ); + + while( (c = get( global ) ) != '\n' && c != EOF_CHAR ) + Putchar( global, c ); + + unget( global ); + + Putchar( global, '\n' ); + + break; + + default: + /* + * Undefined #control keyword. + * Note: the correct behavior may be to warn and + * pass the line to a subsequent compiler pass. + * This would allow #asm or similar extensions. + */ + if( global->warnillegalcpp ) + cwarn( global, WARN_ILLEGAL_COMMAND, global->tokenbuf ); + + Putchar( global, '#' ); + Putstring( global, global->tokenbuf ); + Putchar( global, ' ' ); + + while( (c = get( global ) ) != '\n' && c != EOF_CHAR ) + Putchar( global, c ); + + unget( global ); + + Putchar( global, '\n' ); + + break; + } + + if( hash != L_include ) + { + #if OLD_PREPROCESSOR + /* + * Ignore the rest of the #control line so you can write + * #if foo + * #endif foo + */ + dump_line( global, counter ); /* Take common exit */ + + return( FPP_OK ); + #else + if( skipws( global ) != '\n' ) + { + cwarn( global, WARN_UNEXPECTED_TEXT_IGNORED ); + + skipnl( global ); + } + #endif + } + + (*counter)++; + + return( FPP_OK ); +} + +FILE_LOCAL +void dump_line(struct Global *global, int *counter) +{ + skipnl( global ); /* Ignore rest of line */ + + (*counter)++; +} + +FILE_LOCAL +ReturnCode doif(struct Global *global, int hash) +{ + /* + * Process an #if, #ifdef, or #ifndef. The latter two are straightforward, + * while #if needs a subroutine of its own to evaluate the expression. + * + * doif() is called only if compiling is TRUE. If false, compilation + * is always supressed, so we don't need to evaluate anything. This + * supresses unnecessary warnings. + */ + + int c; + int found; + ReturnCode ret; + + if( (c = skipws( global ) ) == '\n' || c == EOF_CHAR ) + { + unget( global ); + + cerror( global, ERROR_MISSING_ARGUMENT ); + + #if !OLD_PREPROCESSOR + skipnl( global ); /* Prevent an extra */ + + unget( global ); /* Error message */ + #endif + + return(FPP_OK); + } + + if( hash == L_if ) + { + unget( global ); + + ret = eval( global, &found ); + + if( ret ) + return( ret ); + + found = (found != 0); /* Evaluate expr, != 0 is TRUE */ + + hash = L_ifdef; /* #if is now like #ifdef */ + } + else + { + if( type[c] != LET ) + { /* Next non-blank isn't letter */ + /* ... is an error */ + cerror( global, ERROR_MISSING_ARGUMENT ); + + #if !OLD_PREPROCESSOR + skipnl( global ); /* Prevent an extra */ + + unget( global ); /* Error message */ + #endif + + return(FPP_OK); + } + + found = ( lookid( global, c ) != NULL ); /* Look for it in symbol table */ + } + + if( found == (hash == L_ifdef) ) + { + compiling = TRUE; + + *global->ifptr |= TRUE_SEEN; + } + else + compiling = FALSE; + + return(FPP_OK); +} + +INLINE FILE_LOCAL +ReturnCode doinclude( struct Global *global ) +{ + /* + * Process the #include control line. + * There are three variations: + * + * #include "file" search somewhere relative to the + * current source file, if not found, + * treat as #include . + * + * #include Search in an implementation-dependent + * list of places. + * + * #include token Expand the token, it must be one of + * "file" or , process as such. + * + * Note: the November 12 draft forbids '>' in the #include format. + * This restriction is unnecessary and not implemented. + */ + + int c; + int delim; + ReturnCode ret; + + delim = skipws( global ); + + if( ret = macroid( global, &delim ) ) + return(ret); + + if( delim != '<' && delim != '"' ) + { + cerror( global, ERROR_INCLUDE_SYNTAX ); + + return( FPP_OK ); + } + + if( delim == '<' ) + delim = '>'; + + global->workp = global->work; + + while( (c = get(global)) != '\n' && c != EOF_CHAR ) + if( ret = save( global, c ) ) /* Put it away. */ + return( ret ); + + unget( global ); /* Force nl after include */ + + /* + * The draft is unclear if the following should be done. + */ + while( --global->workp >= global->work && + (*global->workp == ' ' || *global->workp == '\t') ) + ; /* Trim blanks from filename */ + + if( *global->workp != delim ) + { + cerror( global, ERROR_INCLUDE_SYNTAX ); + + return(FPP_OK); + } + + *global->workp = EOS; /* Terminate filename */ + + ret = openinclude( global, global->work, (delim == '"') ); + + if( ret && global->warnnoinclude ) + { + /* + * Warn if #include file isn't there. + */ + cwarn( global, WARN_CANNOT_OPEN_INCLUDE, global->work ); + } + + return( FPP_OK ); +} + +#ifdef _AMIGA +ReturnCode MultiAssignLoad( struct Global *global, char *incptr, char *filename, char *tmpname ); +#endif + +ReturnCode openinclude( struct Global *global, + char *filename, /* Input file name */ + int searchlocal ) /* TRUE if #include "file" */ +{ + /* + * Actually open an include file. This routine is only called from + * doinclude() above, but was written as a separate subroutine for + * programmer convenience. It searches the list of directories + * and actually opens the file, linking it into the list of + * active files. Returns ReturnCode. No error message is printed. + */ + + char **incptr; + char tmpname[NWORK]; /* Filename work area */ + int len; + ReturnCode ret; + + #if HOST == SYS_AMIGADOS + if( strchr (filename, ':') != NULL ) + { + if( ! openfile( global, filename ) ) + return(FPP_OK); + } + #else + if( filename[0] == '/' ) + { + if( ! openfile( global, filename ) ) + return(FPP_OK); + } + #endif + + if( searchlocal ) + { + /* + * Look in local directory first. + * Try to open filename relative to the directory of the current + * source file (as opposed to the current directory). (ARF, SCK). + * Note that the fully qualified pathname is always built by + * discarding the last pathname component of the source file + * name then tacking on the #include argument. + */ + if( hasdirectory( global->infile->filename, tmpname ) ) + strcat( tmpname, filename ); + else + strcpy( tmpname, filename ); + + if( ! openfile( global, tmpname ) ) + return(FPP_OK); + } + + /* + * Look in any directories specified by -I command line + * arguments, then in the builtin search list. + */ + for( incptr = global->incdir; incptr < global->incend; incptr++ ) + { + len = strlen(*incptr); + + if( len + strlen(filename) >= sizeof(tmpname) ) + { + cfatal( global, FATAL_FILENAME_BUFFER_OVERFLOW ); + + return( FPP_FILENAME_BUFFER_OVERFLOW ); + } + else + { + #if HOST == SYS_AMIGADOS + if( (*incptr)[len-1] != '/' && (*incptr)[len-1] != ':' ) + sprintf( tmpname, "%s/%s", *incptr, filename ); + #else + if( (*incptr)[len-1] != '/' ) + sprintf( tmpname, "%s/%s", *incptr, filename ); + #endif + else + sprintf( tmpname, "%s%s", *incptr, filename ); + + #if HOST == SYS_AMIGADOS + // + // amp July 9, 1997 + // + // OK, hack in multiassign support for the buitin + // search directories... + // + if( (*incptr)[len-1] == ':' ) + { + if( ! MultiAssignLoad( global, *incptr, filename, tmpname ) ) + return(FPP_OK); + } + else + #endif + if( !openfile( global, tmpname ) ) + return(FPP_OK); + } + } + + return( FPP_NO_INCLUDE ); +} + +INLINE FILE_LOCAL +int hasdirectory( char *source, /* Directory to examine */ + char *result ) /* Put directory stuff here */ +{ + /* + * If a device or directory is found in the source filename string, the + * node/device/directory part of the string is copied to result and + * hasdirectory returns TRUE. Else, nothing is copied and it returns FALSE. + */ + + char *tp2; + + #if HOST == SYS_AMIGADOS + char *tp1; + + if( (tp1 = strrchr( source, ':' ) ) == NULL ) + tp1 = source; + + if( (tp2 = strrchr( tp1, '/' ) ) == NULL ) + tp2 = tp1; + + if( tp2 == source ) + return (FALSE); + + #else + if( (tp2 = strrchr( source, '/' ) ) == NULL ) + return(FALSE); + #endif + + strncpy( result, source, tp2 - source + 1 ); + + result[tp2 - source + 1] = EOS; + + return( TRUE ); +} + +#ifdef _AMIGA +// +// amp July 9, 1997 +// +// Use the OS Luke... +// +// We do the sneaky version and let the OS do all +// the hard work so we don't have to mess around +// a lot ;) +// +ReturnCode MultiAssignLoad( struct Global *global, char *incptr, char *filename, char *tmpname ) + +{ /* MultiAssignLoad */ + + struct MsgPort *FSTask; + struct DevProc *DevProc = NULL; + LONG RtnCode = FPP_NO_INCLUDE; + + FSTask = GetFileSysTask(); + + do + { + // + // This should not bring up a requester. + // check to see if cpp does in fact tweek + // the process WindowPtr. + // + DevProc = GetDeviceProc( incptr, DevProc ); + + if( DevProc ) + { + SetFileSysTask( DevProc->dvp_Port ); + + // + // Normally we would pass the lock and filename + // to the Load() routine, which would CD to the + // directory and Open(filename), but in order to + // satisfy the exisiting openfile() function, we + // bite the bullet and build the complete pathspec + // rather than add the standard Load() routine. + // + if( NameFromLock( DevProc->dvp_Lock, tmpname, NWORK ) ) + { + AddPart( tmpname, filename, NWORK ); + + RtnCode = openfile( global, tmpname ); + + if( ! RtnCode ) + break; + } + } + + } while ( RtnCode && + DevProc && + (DevProc->dvp_Flags & DVPF_ASSIGN) && + IoErr() == ERROR_OBJECT_NOT_FOUND); /* repeat if multi-assign */ + + SetFileSysTask( FSTask ); + + if( DevProc ) + FreeDeviceProc( DevProc ); + + return RtnCode; + +} /* MultiAssignLoad */ +#endif //_AMIGA diff --git a/cpp3.c b/cpp3.c new file mode 100644 index 0000000..263eee3 --- /dev/null +++ b/cpp3.c @@ -0,0 +1,451 @@ +#ifdef RCS +static char rcsid[]="$Id: cpp3.c,v 1.6 1994/06/02 08:50:08 start Exp $"; +#endif +/****************************************************************************** +Copyright (c) 1999 Daniel Stenberg + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE +SOFTWARE. +******************************************************************************/ +/****************************************************************************** + * FREXXWARE + * ---------------------------------------------------------------------------- + * + * Project: Frexx C Preprocessor + * $Source: /home/user/start/cpp/RCS/cpp3.c,v $ + * $Revision: 1.6 $ + * $Date: 1994/06/02 08:50:08 $ + * $Author: start $ + * $State: Exp $ + * $Locker: $ + * + * ---------------------------------------------------------------------------- + * $Log: cpp3.c,v $ + * Revision 1.6 1994/06/02 08:50:08 start + * Added the new command line options + * + * Revision 1.5 1994/01/24 09:33:15 start + * Added the FPPTAG_RIGHTCONCAT tag. + * + * Revision 1.4 1993/12/06 13:50:39 start + * A lot of new stuff (too much to mention) + * + * Revision 1.4 1993/12/06 13:50:39 start + * A lot of new stuff (too much to mention) + * + * Revision 1.3 1993/11/29 14:00:32 start + * new + * + * Revision 1.2 1993/11/11 07:16:39 start + * New stuff + * + * Revision 1.1 1993/11/03 09:13:08 start + * Initial revision + * + * + *****************************************************************************/ +/* + * C P P 3 . C + * + * File open and command line options + * + * Edit history + * 13-Nov-84 MM Split from cpp1.c + * 21-Oct-85 rms Make -g command arg not cause an error. + * 14-Mar-86 FNF Incorporate macro based C debugging package. + * Port to the Commodore AMIGA. + * 20-Aug-88 Ois Added __TIME__, and changed __DATE__ to standard. + */ + +#include +#include +#include /*OIS*0.92*/ +#include "cppdef.h" +#include "cpp.h" + +ReturnCode openfile(struct Global *global, char *filename) +{ + /* + * Open a file, add it to the linked list of open files. + * This is called only from openfile() in cpp2.c. + */ + + FILE *fp; + ReturnCode ret; + + if ((fp = fopen(filename, "r")) == NULL) + ret=FPP_OPEN_ERROR; + else + ret=addfile(global, fp, filename); + + if(!ret && global->showincluded) { + /* no error occured! */ + Error(global, "cpp: included \""); + Error(global, filename); + Error(global, "\"\n"); + } + return(ret); +} + +ReturnCode addfile(struct Global *global, + FILE *fp, /* Open file pointer */ + char *filename) /* Name of the file */ +{ + /* + * Initialize tables for this open file. This is called from openfile() + * above (for #include files), and from the entry to cpp to open the main + * input file. It calls a common routine, getfile() to build the FILEINFO + * structure which is used to read characters. (getfile() is also called + * to setup a macro replacement.) + */ + + FILEINFO *file; + ReturnCode ret; + + ret = getfile(global, NBUFF, filename, &file); + if(ret) + return(ret); + file->fp = fp; /* Better remember FILE * */ + file->buffer[0] = EOS; /* Initialize for first read */ + global->line = 1; /* Working on line 1 now */ + global->wrongline = TRUE; /* Force out initial #line */ + return(FPP_OK); +} + +int dooptions(struct Global *global, struct fppTag *tags) +{ + /* + * dooptions is called to process command line arguments (-Detc). + * It is called only at cpp startup. + */ + DEFBUF *dp; + char end=FALSE; /* end of taglist */ + + while(tags && !end) { + switch(tags->tag) { + case FPPTAG_END: + end=TRUE; + break; + case FPPTAG_INITFUNC: + global->initialfunc = (char *) tags->data; + break; + case FPPTAG_DISPLAYFUNCTIONS: + global->outputfunctions = tags->data?1:0; + break; + case FPPTAG_RIGHTCONCAT: + global->rightconcat = tags->data?1:0; + break; + case FPPTAG_OUTPUTMAIN: + global->outputfile = tags->data?1:0; + break; + case FPPTAG_NESTED_COMMENTS: + global->nestcomments = tags->data?1:0; + break; + case FPPTAG_WARNMISSINCLUDE: + global->warnnoinclude = tags->data?1:0; + break; + case FPPTAG_WARN_NESTED_COMMENTS: + global->warnnestcomments = tags->data?1:0; + break; + case FPPTAG_OUTPUTSPACE: + global->showspace = tags->data?1:0; + break; + case FPPTAG_OUTPUTBALANCE: + global->showbalance = tags->data?1:0; + break; + case FPPTAG_OUTPUTINCLUDES: + global->showincluded = tags->data?1:0; + break; + case FPPTAG_IGNOREVERSION: + global->showversion = tags->data?1:0; + break; + case FPPTAG_WARNILLEGALCPP: + global->warnillegalcpp = tags->data?1:0; + break; + case FPPTAG_OUTPUTLINE: + global->outputLINE = tags->data?1:0; + break; + case FPPTAG_KEEPCOMMENTS: + if(tags->data) { + global->cflag = TRUE; + global->keepcomments = TRUE; + } + break; + case FPPTAG_DEFINE: + /* + * If the option is just "-Dfoo", make it -Dfoo=1 + */ + { + char *symbol=(char *)tags->data; + char *text=symbol; + while (*text != EOS && *text != '=') + text++; + if (*text == EOS) + text = "1"; + else + *text++ = EOS; + /* + * Now, save the word and its definition. + */ + dp = defendel(global, symbol, FALSE); + if(!dp) + return(FPP_OUT_OF_MEMORY); + dp->repl = savestring(global, text); + dp->nargs = DEF_NOARGS; + } + break; + case FPPTAG_IGNORE_NONFATAL: + global->eflag = TRUE; + break; + case FPPTAG_INCLUDE_DIR: + if (global->incend >= &global->incdir[NINCLUDE]) { + cfatal(global, FATAL_TOO_MANY_INCLUDE_DIRS); + return(FPP_TOO_MANY_INCLUDE_DIRS); + } + *global->incend++ = (char *)tags->data; + break; + case FPPTAG_INCLUDE_FILE: + case FPPTAG_INCLUDE_MACRO_FILE: + if (global->included >= NINCLUDE) { + cfatal(global, FATAL_TOO_MANY_INCLUDE_FILES); + return(FPP_TOO_MANY_INCLUDE_FILES); + } + global->include[global->included] = (char *)tags->data; + + global->includeshow[global->included] = + (tags->tag == FPPTAG_INCLUDE_FILE); + + global->included++; + break; + case FPPTAG_BUILTINS: + global->nflag|=(tags->data?NFLAG_BUILTIN:0); + break; + case FPPTAG_PREDEFINES: + global->nflag|=(tags->data?NFLAG_PREDEFINE:0); + break; + case FPPTAG_IGNORE_CPLUSPLUS: + global->cplusplus=!tags->data; + break; + case FPPTAG_SIZEOF_TABLE: + { + SIZES *sizp; /* For -S */ + int size; /* For -S */ + int isdatum; /* FALSE for -S* */ + int endtest; /* For -S */ + + char *text=(char *)tags->data; + + sizp = size_table; + if (isdatum = (*text != '*')) /* If it's just -S, */ + endtest = T_FPTR; /* Stop here */ + else { /* But if it's -S* */ + text++; /* Step over '*' */ + endtest = 0; /* Stop at end marker */ + } + while (sizp->bits != endtest && *text != EOS) { + if (!isdigit(*text)) { /* Skip to next digit */ + text++; + continue; + } + size = 0; /* Compile the value */ + while (isdigit(*text)) { + size *= 10; + size += (*text++ - '0'); + } + if (isdatum) + sizp->size = size; /* Datum size */ + else + sizp->psize = size; /* Pointer size */ + sizp++; + } + if (sizp->bits != endtest) + cwarn(global, WARN_TOO_FEW_VALUES_TO_SIZEOF, NULL); + else if (*text != EOS) + cwarn(global, WARN_TOO_MANY_VALUES_TO_SIZEOF, NULL); + } + break; + case FPPTAG_UNDEFINE: + if (defendel(global, (char *)tags->data, TRUE) == NULL) + cwarn(global, WARN_NOT_DEFINED, tags->data); + break; + case FPPTAG_OUTPUT_DEFINES: + global->wflag++; + break; + case FPPTAG_INPUT_NAME: + strcpy(global->work, tags->data); /* Remember input filename */ + global->first_file=tags->data; + break; + case FPPTAG_INPUT: + global->input=(char *(*)(char *, int, void *))tags->data; + break; + case FPPTAG_OUTPUT: + global->output=(void (*)(int, void *))tags->data; + break; + case FPPTAG_ERROR: + global->error=(void (*)(void *, char *, va_list))tags->data; + break; + case FPPTAG_USERDATA: + global->userdata=tags->data; + break; + case FPPTAG_LINE: + global->linelines= tags->data?1:0; + break; + case FPPTAG_EXCLFUNC: + global->excludedinit[ global->excluded++ ] = (char *)tags->data; + break; + case FPPTAG_WEBMODE: + global->webmode=(tags->data?1:0); + break; + default: + cwarn(global, WARN_INTERNAL_ERROR, NULL); + break; + } + tags++; + } + return(0); +} + +ReturnCode initdefines(struct Global *global) +{ + /* + * Initialize the built-in #define's. There are two flavors: + * #define decus 1 (static definitions) + * #define __FILE__ ?? (dynamic, evaluated by magic) + * Called only on cpp startup. + * + * Note: the built-in static definitions are supressed by the -N option. + * __LINE__, __FILE__, __TIME__ and __DATE__ are always present. + */ + + char **pp; + char *tp; + DEFBUF *dp; + struct tm *tm; + + int i; + time_t tvec; + + static char months[12][4] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + + /* + * Predefine the built-in symbols. Allow the + * implementor to pre-define a symbol as "" to + * eliminate it. + */ + if (!(global->nflag & NFLAG_BUILTIN)) { + for (pp = global->preset; *pp != NULL; pp++) { + if (*pp[0] != EOS) { + dp = defendel(global, *pp, FALSE); + if(!dp) + return(FPP_OUT_OF_MEMORY); + dp->repl = savestring(global, "1"); + dp->nargs = DEF_NOARGS; + } + } + } + /* + * The magic pre-defines (__FILE__ and __LINE__ are + * initialized with negative argument counts. expand() + * notices this and calls the appropriate routine. + * DEF_NOARGS is one greater than the first "magic" definition. + */ + if (!(global->nflag & NFLAG_PREDEFINE)) { + for (pp = global->magic, i = DEF_NOARGS; *pp != NULL; pp++) { + dp = defendel(global, *pp, FALSE); + if(!dp) + return(FPP_OUT_OF_MEMORY); + dp->nargs = --i; + } +#if OK_DATE + /* + * Define __DATE__ as today's date. + */ + dp = defendel(global, "__DATE__", FALSE); + tp = Getmem(global, 14); + if(!tp || !dp) + return(FPP_OUT_OF_MEMORY); + dp->repl = tp; + dp->nargs = DEF_NOARGS; + time(&tvec); + tm = localtime(&tvec); + sprintf(tp, "\"%3s %2d %4d\"", /* "Aug 20 1988" */ + months[tm->tm_mon], + tm->tm_mday, + tm->tm_year + 1900); + + /* + * Define __TIME__ as this moment's time. + */ + dp = defendel(global, "__TIME__", FALSE); + tp = Getmem(global, 11); + if(!tp || !dp) + return(FPP_OUT_OF_MEMORY); + dp->repl = tp; + dp->nargs = DEF_NOARGS; + sprintf(tp, "\"%2d:%02d:%02d\"", /* "20:42:31" */ + tm->tm_hour, + tm->tm_min, + tm->tm_sec); +#endif + } + return(FPP_OK); +} + +void deldefines(struct Global *global) +{ + /* + * Delete the built-in #define's. + */ + char **pp; + int i; + + + /* + * Delete the built-in symbols, unless -WW. + */ + if (global->wflag < 2) { + for (pp = global->preset; *pp != NULL; pp++) { + defendel(global, *pp, TRUE); + } + } + /* + * The magic pre-defines __FILE__ and __LINE__ + */ + for (pp = global->magic, i = DEF_NOARGS; *pp != NULL; pp++) { + defendel(global, *pp, TRUE); + } +#if OK_DATE + /* + * Undefine __DATE__. + */ + defendel(global, "__DATE__", TRUE); + + /* + * Undefine __TIME__. + */ + defendel(global, "__TIME__", TRUE); +#endif + return; +} + diff --git a/cpp4.c b/cpp4.c new file mode 100644 index 0000000..fc20bd1 --- /dev/null +++ b/cpp4.c @@ -0,0 +1,686 @@ +#ifdef RCS +static char rcsid[]="$Id: cpp4.c,v 1.3 1994/06/02 08:50:52 start Exp $"; +#endif +/****************************************************************************** +Copyright (c) 1999 Daniel Stenberg + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE +SOFTWARE. +******************************************************************************/ +/****************************************************************************** + * FREXXWARE + * ---------------------------------------------------------------------------- + * + * Project: Frexx C Preprocessor + * $Source: /home/user/start/cpp/RCS/cpp4.c,v $ + * $Revision: 1.3 $ + * $Date: 1994/06/02 08:50:52 $ + * $Author: start $ + * $State: Exp $ + * $Locker: $ + * + * ---------------------------------------------------------------------------- + * $Log: cpp4.c,v $ + * Revision 1.3 1994/06/02 08:50:52 start + * Changed a few things to make the initial function routine to run + * + * Revision 1.2 1994/01/24 09:34:03 start + * Made a bunch of functions FILE_LOCAL and INLINE. + * + * Revision 1.1 1993/11/03 09:13:08 start + * Initial revision + * + * + *****************************************************************************/ +/* + * C P P 4 . C + * M a c r o D e f i n i t i o n s + * + * Edit History + * 31-Aug-84 MM USENET net.sources release + * 04-Oct-84 MM __LINE__ and __FILE__ must call ungetstring() + * so they work correctly with token concatenation. + * Added string formal recognition. + * 25-Oct-84 MM "Short-circuit" evaluate #if's so that we + * don't print unnecessary error messages for + * #if !defined(FOO) && FOO != 0 && 10 / FOO ... + * 31-Oct-84 ado/MM Added token concatenation + * 6-Nov-84 MM Split off eval stuff + * 21-Oct-85 RMS Rename `token' to `tokenbuf'. + * In doundef, don't complain if arg already not defined. + * 14-Mar-86 FNF Incorporate macro based C debugging package. + * Port to Commodore AMIGA. + * 21-Aug-88 Ois Changed concatenation operator to ##. Changed hand- + * ling of tokens following ##. Added new meaning of #. + */ + +#include +#include +#include "cppdef.h" +#include "cpp.h" + +INLINE FILE_LOCAL ReturnCode checkparm(struct Global *, int, DEFBUF *, int); +INLINE FILE_LOCAL ReturnCode stparmscan(struct Global *, int); +INLINE FILE_LOCAL ReturnCode textput(struct Global *, char *); +FILE_LOCAL ReturnCode charput(struct Global *, int); +INLINE FILE_LOCAL ReturnCode expcollect(struct Global *); +INLINE FILE_LOCAL char *doquoting(char *, char *); + + +ReturnCode dodefine(struct Global *global) +{ + /* + * Called from control when a #define is scanned. This module + * parses formal parameters and the replacement string. When + * the formal parameter name is encountered in the replacement + * string, it is replaced by a character in the range 128 to + * 128+NPARAM (this allows up to 32 parameters within the + * Dec Multinational range). If cpp is ported to an EBCDIC + * machine, you will have to make other arrangements. + * + * There is some special case code to distinguish + * #define foo bar + * from #define foo() bar + * + * Also, we make sure that + * #define foo foo + * expands to "foo" but doesn't put cpp into an infinite loop. + * + * A warning message is printed if you redefine a symbol to a + * different text. I.e, + * #define foo 123 + * #define foo 123 + * is ok, but + * #define foo 123 + * #define foo +123 + * is not. + * + * The following subroutines are called from define(): + * checkparm called when a token is scanned. It checks through the + * array of formal parameters. If a match is found, the + * token is replaced by a control byte which will be used + * to locate the parameter when the macro is expanded. + * textput puts a string in the macro work area (parm[]), updating + * parmp to point to the first free byte in parm[]. + * textput() tests for work buffer overflow. + * charput puts a single character in the macro work area (parm[]) + * in a manner analogous to textput(). + */ + int c; + DEFBUF *dp; /* -> new definition */ + int isredefine; /* TRUE if redefined */ + char *old; /* Remember redefined */ + ReturnCode ret; +#if OK_CONCAT + int quoting; /* Remember we saw a # */ +#endif + + if (type[(c = skipws(global))] != LET) { + cerror(global, ERROR_DEFINE_SYNTAX); + global->inmacro = FALSE; /* Stop hack */ + return(FPP_OK); + } + isredefine = FALSE; /* Set if redefining */ + if ((dp = lookid(global, c)) == NULL) { /* If not known now */ + dp = defendel(global, global->tokenbuf, FALSE); /* Save the name */ + if(!dp) + return(FPP_OUT_OF_MEMORY); + } else { /* It's known: */ + isredefine = TRUE; /* Remember this fact */ + old = dp->repl; /* Remember replacement */ + dp->repl = NULL; /* No replacement now */ + } + global->parlist[0] = global->parmp = global->parm; /* Setup parm buffer */ + if ((c = get(global)) == '(') { /* With arguments? */ + global->nargs = 0; /* Init formals counter */ + do { /* Collect formal parms */ + if (global->nargs >= LASTPARM) { + cfatal(global, FATAL_TOO_MANY_ARGUMENTS_MACRO); + return(FPP_TOO_MANY_ARGUMENTS); + } else if ((c = skipws(global)) == ')') + break; /* Got them all */ + else if (type[c] != LET) { /* Bad formal syntax */ + cerror(global, ERROR_DEFINE_SYNTAX); + global->inmacro = FALSE; /* Stop hack */ + return(FPP_OK); + } + scanid(global, c); /* Get the formal param */ + global->parlist[global->nargs++] = global->parmp; /* Save its start */ + ret=textput(global, global->tokenbuf); /* Save text in parm[] */ + if(ret) + return(ret); + } while ((c = skipws(global)) == ','); /* Get another argument */ + if (c != ')') { /* Must end at ) */ + cerror(global, ERROR_DEFINE_SYNTAX); + global->inmacro = FALSE; /* Stop hack */ + return(FPP_OK); + } + c = ' '; /* Will skip to body */ + } + else { + /* + * DEF_NOARGS is needed to distinguish between + * "#define foo" and "#define foo()". + */ + global->nargs = DEF_NOARGS; /* No () parameters */ + } + if (type[c] == SPA) /* At whitespace? */ + c = skipws(global); /* Not any more. */ + global->workp = global->work; /* Replacement put here */ + global->inmacro = TRUE; /* Keep \ now */ + quoting = 0; /* No # seen yet. */ + while (c != EOF_CHAR && c != '\n') { /* Compile macro body */ +#if OK_CONCAT + if (c == '#') { /* Token concatenation? */ + if ((c = get(global)) != '#') { /* No, not really */ + quoting = 1; /* Maybe quoting op. */ + continue; + } + while (global->workp > global->work && type[global->workp[-1]] == SPA) + --global->workp; /* Erase leading spaces */ + if(ret=save(global, TOK_SEP)) /* Stuff a delimiter */ + return(ret); + c = skipws(global); /* Eat whitespace */ + continue; + } +#endif + switch (type[c]) { + case LET: +#if OK_CONCAT + ret=checkparm(global, c, dp, quoting); /* Might be a formal */ +#else + ret=checkparm(c, dp); /* Might be a formal */ +#endif + if(ret) + return(ret); + break; + + case DIG: /* Number in mac. body */ + case DOT: /* Maybe a float number */ + ret=scannumber(global, c, save); /* Scan it off */ + if(ret) + return(ret); + break; + + case QUO: /* String in mac. body */ + ret=stparmscan(global, c); + if(ret) + return(ret); + break; + + case BSH: /* Backslash */ + ret=save(global, '\\'); + if(ret) + return(ret); + if ((c = get(global)) == '\n') + global->wrongline = TRUE; + ret=save(global, c); + if(ret) + return(ret); + break; + + case SPA: /* Absorb whitespace */ + /* + * Note: the "end of comment" marker is passed on + * to allow comments to separate tokens. + */ + if (global->workp[-1] == ' ') /* Absorb multiple */ + break; /* spaces */ + else if (c == '\t') + c = ' '; /* Normalize tabs */ + /* Fall through to store character */ + default: /* Other character */ + ret=save(global, c); + if(ret) + return(ret); + break; + } + c = get(global); + quoting = 0; /* Only when immediately*/ + /* preceding a formal */ + } + global->inmacro = FALSE; /* Stop newline hack */ + unget(global); /* For control check */ + if (global->workp > global->work && global->workp[-1] == ' ') /* Drop trailing blank */ + global->workp--; + *global->workp = EOS; /* Terminate work */ + dp->repl = savestring(global, global->work); /* Save the string */ + dp->nargs = global->nargs; /* Save arg count */ + if (isredefine) { /* Error if redefined */ + if ((old != NULL && dp->repl != NULL && !streq(old, dp->repl)) + || (old == NULL && dp->repl != NULL) + || (old != NULL && dp->repl == NULL)) { + cerror(global, ERROR_REDEFINE, dp->name); + } + if (old != NULL) /* We don't need the */ + Freemem(old); /* old definition now. */ + } + return(FPP_OK); +} + +INLINE FILE_LOCAL +ReturnCode checkparm(struct Global *global, + int c, + DEFBUF *dp, + int quoting) /* Preceded by a # ? */ +{ + /* + * Replace this param if it's defined. Note that the macro name is a + * possible replacement token. We stuff DEF_MAGIC in front of the token + * which is treated as a LETTER by the token scanner and eaten by + * the output routine. This prevents the macro expander from + * looping if someone writes "#define foo foo". + */ + + int i; + char *cp; + ReturnCode ret=FPP_OK; + + scanid(global, c); /* Get parm to tokenbuf */ + for (i = 0; i < global->nargs; i++) { /* For each argument */ + if (streq(global->parlist[i], global->tokenbuf)) { /* If it's known */ +#if OK_CONCAT + if (quoting) { /* Special handling of */ + ret=save(global, QUOTE_PARM); /* #formal inside defn */ + if(ret) + return(ret); + } +#endif + ret=save(global, i + MAC_PARM); /* Save a magic cookie */ + return(ret); /* And exit the search */ + } + } + if (streq(dp->name, global->tokenbuf)) /* Macro name in body? */ + ret=save(global, DEF_MAGIC); /* Save magic marker */ + for (cp = global->tokenbuf; *cp != EOS;) /* And save */ + ret=save(global, *cp++); /* The token itself */ + return(ret); +} + +INLINE FILE_LOCAL +ReturnCode stparmscan(struct Global *global, int delim) +{ + /* + * Normal string parameter scan. + */ + + unsigned char *wp; + int i; + ReturnCode ret; + + wp = (unsigned char *)global->workp; /* Here's where it starts */ + ret=scanstring(global, delim, save); + if(ret) + return(ret); /* Exit on scanstring error */ + global->workp[-1] = EOS; /* Erase trailing quote */ + wp++; /* -> first string content byte */ + for (i = 0; i < global->nargs; i++) { + if (streq(global->parlist[i], (char *)wp)) { + *wp++ = MAC_PARM + PAR_MAC; /* Stuff a magic marker */ + *wp++ = (i + MAC_PARM); /* Make a formal marker */ + *wp = wp[-3]; /* Add on closing quote */ + global->workp = (char *)wp + 1; /* Reset string end */ + return(FPP_OK); + } + } + global->workp[-1] = wp[-1]; /* Nope, reset end quote. */ + return(FPP_OK); +} + +void doundef(struct Global *global) + /* + * Remove the symbol from the defined list. + * Called from the #control processor. + */ +{ + int c; + if (type[(c = skipws(global))] != LET) + cerror(global, ERROR_ILLEGAL_UNDEF); + else { + scanid(global, c); /* Get name to tokenbuf */ + (void) defendel(global, global->tokenbuf, TRUE); + } +} + +INLINE FILE_LOCAL +ReturnCode textput(struct Global *global, char *text) +{ + /* + * Put the string in the parm[] buffer. + */ + + int size; + + size = strlen(text) + 1; + if ((global->parmp + size) >= &global->parm[NPARMWORK]) { + cfatal(global, FATAL_MACRO_AREA_OVERFLOW); + return(FPP_WORK_AREA_OVERFLOW); + } else { + strcpy(global->parmp, text); + global->parmp += size; + } + return(FPP_OK); +} + +FILE_LOCAL +ReturnCode charput(struct Global *global, int c) +{ + /* + * Put the byte in the parm[] buffer. + */ + + if (global->parmp >= &global->parm[NPARMWORK]) { + cfatal(global, FATAL_MACRO_AREA_OVERFLOW); + return(FPP_WORK_AREA_OVERFLOW); + } + *global->parmp++ = c; + return(FPP_OK); +} + +/* + * M a c r o E x p a n s i o n + */ + +ReturnCode expand(struct Global *global, DEFBUF *tokenp) +{ + /* + * Expand a macro. Called from the cpp mainline routine (via subroutine + * macroid()) when a token is found in the symbol table. It calls + * expcollect() to parse actual parameters, checking for the correct number. + * It then creates a "file" containing a single line containing the + * macro with actual parameters inserted appropriately. This is + * "pushed back" onto the input stream. (When the get() routine runs + * off the end of the macro line, it will dismiss the macro itself.) + */ + int c; + FILEINFO *file; + ReturnCode ret=FPP_OK; + + /* + * If no macro is pending, save the name of this macro + * for an eventual error message. + */ + if (global->recursion++ == 0) + global->macro = tokenp; + else if (global->recursion == RECURSION_LIMIT) { + cerror(global, ERROR_RECURSIVE_MACRO, tokenp->name, global->macro->name); + if (global->rec_recover) { + do { + c = get(global); + } while (global->infile != NULL && global->infile->fp == NULL); + unget(global); + global->recursion = 0; + return(FPP_OK); + } + } + /* + * Here's a macro to expand. + */ + global->nargs = 0; /* Formals counter */ + global->parmp = global->parm; /* Setup parm buffer */ + switch (tokenp->nargs) { + case (-2): /* __LINE__ */ + if(global->infile->fp) + /* This is a file */ + sprintf(global->work, "%d", global->line); + else + /* This is a macro! Find out the file line number! */ + for (file = global->infile; file != NULL; file = file->parent) { + if (file->fp != NULL) { + sprintf(global->work, "%d", file->line); + break; + } + } + ret=ungetstring(global, global->work); + if(ret) + return(ret); + break; + + case (-3): /* __FILE__ */ + for (file = global->infile; file != NULL; file = file->parent) { + if (file->fp != NULL) { + sprintf(global->work, "\"%s\"", (file->progname != NULL) + ? file->progname : file->filename); + ret=ungetstring(global, global->work); + if(ret) + return(ret); + break; + } + } + break; + + case (-4): /* __FUNC__ */ + sprintf(global->work, "\"%s\"", global->functionname[0]? + global->functionname : ""); + ret=ungetstring(global, global->work); + if(ret) + return(ret); + break; + + case (-5): /* __FUNC_LINE__ */ + sprintf(global->work, "%d", global->funcline); + ret=ungetstring(global, global->work); + if(ret) + return(ret); + break; + + default: + /* + * Nothing funny about this macro. + */ + if (tokenp->nargs < 0) { + cfatal(global, FATAL_ILLEGAL_MACRO, tokenp->name); + return(FPP_ILLEGAL_MACRO); + } + while ((c = skipws(global)) == '\n') /* Look for (, skipping */ + global->wrongline = TRUE; /* spaces and newlines */ + if (c != '(') { + /* + * If the programmer writes + * #define foo() ... + * ... + * foo [no ()] + * just write foo to the output stream. + */ + unget(global); + cwarn(global, WARN_MACRO_NEEDS_ARGUMENTS, tokenp->name); + + /* fputs(tokenp->name, stdout); */ + Putstring(global, tokenp->name); + return(FPP_OK); + } else if (!(ret=expcollect(global))) { /* Collect arguments */ + if (tokenp->nargs != global->nargs) { /* Should be an error? */ + cwarn(global, WARN_WRONG_NUMBER_ARGUMENTS, tokenp->name); + } + } else { /* Collect arguments */ + return(ret); /* We failed in argument colleting! */ + } + case DEF_NOARGS: /* No parameters just stuffs */ + ret=expstuff(global, tokenp->name, tokenp->repl); /* expand macro */ + } /* nargs switch */ + return(ret); +} + +INLINE FILE_LOCAL +ReturnCode expcollect(struct Global *global) +{ + /* + * Collect the actual parameters for this macro. + */ + + int c; + int paren; /* For embedded ()'s */ + ReturnCode ret; + + for (;;) { + paren = 0; /* Collect next arg. */ + while ((c = skipws(global)) == '\n')/* Skip over whitespace */ + global->wrongline = TRUE; /* and newlines. */ + if (c == ')') { /* At end of all args? */ + /* + * Note that there is a guard byte in parm[] + * so we don't have to check for overflow here. + */ + *global->parmp = EOS; /* Make sure terminated */ + break; /* Exit collection loop */ + } + else if (global->nargs >= LASTPARM) { + cfatal(global, FATAL_TOO_MANY_ARGUMENTS_EXPANSION); + return(FPP_TOO_MANY_ARGUMENTS); + } + global->parlist[global->nargs++] = global->parmp; /* At start of new arg */ + for (;; c = cget(global)) { /* Collect arg's bytes */ + if (c == EOF_CHAR) { + cerror(global, ERROR_EOF_IN_ARGUMENT); + return(FPP_EOF_IN_MACRO); /* Sorry. */ + } + else if (c == '\\') { /* Quote next character */ + charput(global, c); /* Save the \ for later */ + charput(global, cget(global)); /* Save the next char. */ + continue; /* And go get another */ + } + else if (type[c] == QUO) { /* Start of string? */ + ret=scanstring(global, c, (ReturnCode (*)(struct Global *, int))charput); /* Scan it off */ + if(ret) + return(ret); + continue; /* Go get next char */ + } + else if (c == '(') /* Worry about balance */ + paren++; /* To know about commas */ + else if (c == ')') { /* Other side too */ + if (paren == 0) { /* At the end? */ + unget(global); /* Look at it later */ + break; /* Exit arg getter. */ + } + paren--; /* More to come. */ + } + else if (c == ',' && paren == 0) /* Comma delimits args */ + break; + else if (c == '\n') /* Newline inside arg? */ + global->wrongline = TRUE; /* We'll need a #line */ + charput(global, c); /* Store this one */ + } /* Collect an argument */ + charput(global, EOS); /* Terminate argument */ + } /* Collect all args. */ + return(FPP_OK); /* Normal return */ +} + + +#if OK_CONCAT + +INLINE FILE_LOCAL +char *doquoting(char *to, char *from) +{ + *to++ = '"'; + while (*from) { + if (*from == '\\' || *from == '"') + *to++ = '\\'; + *to++ = *from++; + } + *to++ = '"'; + + return to; +} + +#endif + +ReturnCode expstuff(struct Global *global, + char *MacroName, + char *MacroReplace) +{ + /* + * Stuff the macro body, replacing formal parameters by actual parameters. + */ + int c; /* Current character */ + char *inp; /* -> repl string */ + char *defp; /* -> macro output buff */ + int size; /* Actual parm. size */ + char *defend; /* -> output buff end */ + int string_magic; /* String formal hack */ + FILEINFO *file; /* Funny #include */ + ReturnCode ret; +#if OK_CONCAT + char quoting; /* Quote macro argument */ +#endif + + ret = getfile(global, NBUFF, MacroName, &file); + if(ret) + return(ret); + inp = MacroReplace; /* -> macro replacement */ + defp = file->buffer; /* -> output buffer */ + defend = defp + (NBUFF - 1); /* Note its end */ + if (inp != NULL) { + quoting = 0; + while ((c = (*inp++ & 0xFF)) != EOS) { +#if OK_CONCAT + if (c == QUOTE_PARM) { /* Special token for # */ + quoting = 1; /* set flag, for later */ + continue; /* Get next character */ + } +#endif + if (c >= MAC_PARM && c <= (MAC_PARM + PAR_MAC)) { + string_magic = (c == (MAC_PARM + PAR_MAC)); + if (string_magic) + c = (*inp++ & 0xFF); + /* + * Replace formal parameter by actual parameter string. + */ + if ((c -= MAC_PARM) < global->nargs) { + size = strlen(global->parlist[c]); +#if OK_CONCAT + if (quoting) { + size++; + size *= 2; /* worst case condition */ + } +#endif + if ((defp + size) >= defend) { + cfatal(global, FATAL_OUT_OF_SPACE_IN_ARGUMENT, MacroName); + return(FPP_OUT_OF_SPACE_IN_MACRO_EXPANSION); + } + /* + * Erase the extra set of quotes. + */ + if (string_magic && defp[-1] == global->parlist[c][0]) { + strcpy(defp-1, global->parlist[c]); + defp += (size - 2); + } +#if OK_CONCAT +else if (quoting) + defp = doquoting(defp, global->parlist[c]); +#endif +else { + strcpy(defp, global->parlist[c]); + defp += size; +} + } + } + else if (defp >= defend) { + cfatal(global, FATAL_OUT_OF_SPACE_IN_ARGUMENT, MacroName); + return(FPP_OUT_OF_SPACE_IN_MACRO_EXPANSION); + } else + *defp++ = c; + quoting = 0; + } + } + *defp = EOS; + return(FPP_OK); +} + diff --git a/cpp5.c b/cpp5.c new file mode 100644 index 0000000..031b468 --- /dev/null +++ b/cpp5.c @@ -0,0 +1,953 @@ +#ifdef RCS +static char rcsid[]="$Id: cpp5.c,v 1.2 1994/01/24 09:35:02 start Exp $"; +#endif +/****************************************************************************** +Copyright (c) 1999 Daniel Stenberg + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE +SOFTWARE. +******************************************************************************/ +/****************************************************************************** + * FREXXWARE + * ---------------------------------------------------------------------------- + * + * Project: Frexx C Preprocessor + * $Source: /home/user/start/cpp/RCS/cpp5.c,v $ + * $Revision: 1.2 $ + * $Date: 1994/01/24 09:35:02 $ + * $Author: start $ + * $State: Exp $ + * $Locker: $ + * + * ---------------------------------------------------------------------------- + * $Log: cpp5.c,v $ + * Revision 1.2 1994/01/24 09:35:02 start + * Made a bunch of functions FILE_LOCAL and INLINE. + * + * Revision 1.1 1993/11/03 09:13:08 start + * Initial revision + * + * + *****************************************************************************/ +/* + * C P P 5 . C + * E x p r e s s i o n E v a l u a t i o n + * + * Edit History + * 31-Aug-84 MM USENET net.sources release + * 04-Oct-84 MM __LINE__ and __FILE__ must call ungetstring() + * so they work correctly with token concatenation. + * Added string formal recognition. + * 25-Oct-84 MM "Short-circuit" evaluate #if's so that we + * don't print unnecessary error messages for + * #if !defined(FOO) && FOO != 0 && 10 / FOO ... + * 31-Oct-84 ado/MM Added token concatenation + * 6-Nov-84 MM Split from #define stuff, added sizeof stuff + * 19-Nov-84 ado #if error returns TRUE for (sigh) compatibility + * 21-Oct-85 RMS Rename `token' to `tokenbuf' + * 23-Oct-85 RMS Treat undefined symbols as having value zero. + * 14-Mar-86 FNF Incorporate macro based C debugging package. + * Port to Commodore Amiga. + * 20-Aug-88 Ois Conditionally compile sizeof stuff. + */ + +#include +#include +#include "cppdef.h" +#include "cpp.h" + +INLINE FILE_LOCAL ReturnCode evallex(struct Global *, int, int *); +INLINE FILE_LOCAL ReturnCode dosizeof(struct Global *, int *); +INLINE FILE_LOCAL int bittest(int); +INLINE FILE_LOCAL int evalnum(struct Global *, int); +INLINE FILE_LOCAL int evalchar(struct Global *, int); +INLINE FILE_LOCAL int *evaleval(struct Global *, int *, int, int); + +/* + * Evaluate an #if expression. + */ + +static char *opname[] = { /* For debug and error messages */ + "end of expression", "val", "id", + "+", "-", "*", "/", "%", + "<<", ">>", "&", "|", "^", + "==", "!=", "<", "<=", ">=", ">", + "&&", "||", "?", ":", ",", + "unary +", "unary -", "~", "!", "(", ")", "(none)", +}; + +/* + * opdope[] has the operator precedence: + * Bits + * 7 Unused (so the value is always positive) + * 6-2 Precedence (000x .. 017x) + * 1-0 Binary op. flags: + * 01 The binop flag should be set/cleared when this op is seen. + * 10 The new value of the binop flag. + * Note: Expected, New binop + * constant 0 1 Binop, end, or ) should follow constants + * End of line 1 0 End may not be preceeded by an operator + * binary 1 0 Binary op follows a value, value follows. + * unary 0 0 Unary op doesn't follow a value, value follows + * ( 0 0 Doesn't follow value, value or unop follows + * ) 1 1 Follows value. Op follows. + */ + +static char opdope[OP_MAX] = { + 0001, /* End of expression */ + 0002, /* Digit */ + 0000, /* Letter (identifier) */ + 0141, 0141, 0151, 0151, 0151, /* ADD, SUB, MUL, DIV, MOD */ + 0131, 0131, 0101, 0071, 0071, /* ASL, ASR, AND, OR, XOR */ + 0111, 0111, 0121, 0121, 0121, 0121, /* EQ, NE, LT, LE, GE, GT */ + 0061, 0051, 0041, 0041, 0031, /* ANA, ORO, QUE, COL, CMA */ + /* + * Unary op's follow + */ + 0160, 0160, 0160, 0160, /* NEG, PLU, COM, NOT */ + 0170, 0013, 0023, /* LPA, RPA, END */ +}; +/* + * OP_QUE and OP_RPA have alternate precedences: + */ +#define OP_RPA_PREC 0013 +#define OP_QUE_PREC 0034 + +/* + * S_ANDOR and S_QUEST signal "short-circuit" boolean evaluation, so that + * #if FOO != 0 && 10 / FOO ... + * doesn't generate an error message. They are stored in optab.skip. + */ +#define S_ANDOR 2 +#define S_QUEST 1 + +typedef struct optab { + char op; /* Operator */ + char prec; /* Its precedence */ + char skip; /* Short-circuit: TRUE to skip */ +} OPTAB; + +#ifdef nomacargs + FILE_LOCAL int + isbinary(op) + int op; +{ + return (op >= FIRST_BINOP && op <= LAST_BINOP); +} + +FILE_LOCAL int + isunary(op) +int op; +{ + return (op >= FIRST_UNOP && op <= LAST_UNOP); +} +#else +#define isbinary(op) (op >= FIRST_BINOP && op <= LAST_BINOP) +#define isunary(op) (op >= FIRST_UNOP && op <= LAST_UNOP) +#endif + +/* + * The following definitions are used to specify basic variable sizes. + */ + +#if OK_SIZEOF + +#ifndef S_CHAR +#define S_CHAR (sizeof (char)) +#endif +#ifndef S_SINT +#ifdef manx /* Aztec/Manx C does not like "short int" */ +#define S_SINT (sizeof (short)) +#else +#define S_SINT (sizeof (short int)) +#endif +#endif +#ifndef S_INT +#define S_INT (sizeof (int)) +#endif +#ifndef S_LINT +#define S_LINT (sizeof (long int)) +#endif +#ifndef S_FLOAT +#define S_FLOAT (sizeof (float)) +#endif +#ifndef S_DOUBLE +#define S_DOUBLE (sizeof (double)) +#endif +#ifndef S_PCHAR +#define S_PCHAR (sizeof (char *)) +#endif +#ifndef S_PSINT +#ifdef manx /* Aztec/Manx C does not like "short int" */ +#define S_PSINT (sizeof (short *)) +#else +#define S_PSINT (sizeof (short int *)) +#endif +#endif +#ifndef S_PINT +#define S_PINT (sizeof (int *)) +#endif +#ifndef S_PLINT +#define S_PLINT (sizeof (long int *)) +#endif +#ifndef S_PFLOAT +#define S_PFLOAT (sizeof (float *)) +#endif +#ifndef S_PDOUBLE +#define S_PDOUBLE (sizeof (double *)) +#endif +#ifndef S_PFPTR +#define S_PFPTR (sizeof (int (*)())) +#endif + + +typedef struct types { + short type; /* This is the bit if */ + char *name; /* this is the token word */ +} TYPES; + +static TYPES basic_types[] = { + { T_CHAR, "char", }, + { T_INT, "int", }, + { T_FLOAT, "float", }, + { T_DOUBLE, "double", }, + { T_SHORT, "short", }, + { T_LONG, "long", }, + { T_SIGNED, "signed", }, + { T_UNSIGNED, "unsigned", }, + { 0, NULL, }, /* Signal end */ +}; + +/* + * Test_table[] is used to test for illegal combinations. + */ +static short test_table[] = { + T_FLOAT | T_DOUBLE | T_LONG | T_SHORT, + T_FLOAT | T_DOUBLE | T_CHAR | T_INT, + T_FLOAT | T_DOUBLE | T_SIGNED | T_UNSIGNED, + T_LONG | T_SHORT | T_CHAR, + 0 /* end marker */ + }; + +/* + * The order of this table is important -- it is also referenced by + * the command line processor to allow run-time overriding of the + * built-in size values. The order must not be changed: + * char, short, int, long, float, double (func pointer) + */ +SIZES size_table[] = { + { T_CHAR, S_CHAR, S_PCHAR }, /* char */ + { T_SHORT, S_SINT, S_PSINT }, /* short int */ + { T_INT, S_INT, S_PINT }, /* int */ + { T_LONG, S_LINT, S_PLINT }, /* long */ + { T_FLOAT, S_FLOAT, S_PFLOAT }, /* float */ + { T_DOUBLE, S_DOUBLE, S_PDOUBLE }, /* double */ + { T_FPTR, 0, S_PFPTR }, /* int (*()) */ + { 0, 0, 0 }, /* End of table */ +}; + +#endif /* OK_SIZEOF */ + +ReturnCode eval(struct Global *global, int *eval) +{ + /* + * Evaluate an expression. Straight-forward operator precedence. + * This is called from control() on encountering an #if statement. + * It calls the following routines: + * evallex Lexical analyser -- returns the type and value of + * the next input token. + * evaleval Evaluate the current operator, given the values on + * the value stack. Returns a pointer to the (new) + * value stack. + * For compatiblity with older cpp's, this return returns 1 (TRUE) + * if a syntax error is detected. + */ + int op; /* Current operator */ + int *valp; /* -> value vector */ + OPTAB *opp; /* Operator stack */ + int prec; /* Op precedence */ + int binop; /* Set if binary op. needed */ + int op1; /* Operand from stack */ + int skip; /* For short-circuit testing */ + int value[NEXP]; /* Value stack */ + OPTAB opstack[NEXP]; /* Operand stack */ + ReturnCode ret; + char again=TRUE; + + valp = value; + opp = opstack; + opp->op = OP_END; /* Mark bottom of stack */ + opp->prec = opdope[OP_END]; /* And its precedence */ + opp->skip = 0; /* Not skipping now */ + binop = 0; + + while(again) { + ret=evallex(global, opp->skip, &op); + if(ret) + return(ret); + if (op == OP_SUB && binop == 0) + op = OP_NEG; /* Unary minus */ + else if (op == OP_ADD && binop == 0) + op = OP_PLU; /* Unary plus */ + else if (op == OP_FAIL) { + *eval=1; /* Error in evallex */ + return(FPP_OK); + } + if (op == DIG) { /* Value? */ + if (binop != 0) { + cerror(global, ERROR_MISPLACED_CONSTANT); + *eval=1; + return(FPP_OK); + } else if (valp >= &value[NEXP-1]) { + cerror(global, ERROR_IF_OVERFLOW); + *eval=1; + return(FPP_OK); + } else { + *valp++ = global->evalue; + binop = 1; + } + again=TRUE; + continue; + } else if (op > OP_END) { + cerror(global, ERROR_ILLEGAL_IF_LINE); + *eval=1; + return(FPP_OK); + } + prec = opdope[op]; + if (binop != (prec & 1)) { + cerror(global, ERROR_OPERATOR, opname[op]); + *eval=1; + return(FPP_OK); + } + binop = (prec & 2) >> 1; + do { + if (prec > opp->prec) { + if (op == OP_LPA) + prec = OP_RPA_PREC; + else if (op == OP_QUE) + prec = OP_QUE_PREC; + op1 = opp->skip; /* Save skip for test */ + /* + * Push operator onto op. stack. + */ + opp++; + if (opp >= &opstack[NEXP]) { + cerror(global, ERROR_EXPR_OVERFLOW, opname[op]); + *eval=1; + return(FPP_OK); + } + opp->op = op; + opp->prec = prec; + skip = (valp[-1] != 0); /* Short-circuit tester */ + /* + * Do the short-circuit stuff here. Short-circuiting + * stops automagically when operators are evaluated. + */ + if ((op == OP_ANA && !skip) + || (op == OP_ORO && skip)) + opp->skip = S_ANDOR; /* And/or skip starts */ + else if (op == OP_QUE) /* Start of ?: operator */ + opp->skip = (op1 & S_ANDOR) | ((!skip) ? S_QUEST : 0); + else if (op == OP_COL) { /* : inverts S_QUEST */ + opp->skip = (op1 & S_ANDOR) + | (((op1 & S_QUEST) != 0) ? 0 : S_QUEST); + } + else { /* Other ops leave */ + opp->skip = op1; /* skipping unchanged. */ + } + again=TRUE; + continue; + } + /* + * Pop operator from op. stack and evaluate it. + * End of stack and '(' are specials. + */ + skip = opp->skip; /* Remember skip value */ + switch ((op1 = opp->op)) { /* Look at stacked op */ + case OP_END: /* Stack end marker */ + if (op == OP_EOE) { + *eval=valp[-1]; /* Finished ok. */ + return(FPP_OK); + } + /* Read another op. */ + again=TRUE; + continue; + case OP_LPA: /* ( on stack */ + if (op != OP_RPA) { /* Matches ) on input */ + cerror(global, ERROR_UNBALANCED_PARENS, opname[op]); + *eval=1; + return(FPP_OK); + } + opp--; /* Unstack it */ + /* -- Fall through */ + case OP_QUE: + /* Evaluate true expr. */ + again=TRUE; + continue; + case OP_COL: /* : on stack. */ + opp--; /* Unstack : */ + if (opp->op != OP_QUE) { /* Matches ? on stack? */ + cerror(global, ERROR_MISPLACED, opname[opp->op]); + *eval=1; + return(FPP_OK); + } + /* + * Evaluate op1. + */ + default: /* Others: */ + opp--; /* Unstack the operator */ + valp = evaleval(global, valp, op1, skip); + again=FALSE; + } /* op1 switch end */ + } while (!again); /* Stack unwind loop */ + } + return(FPP_OK); +} + +INLINE FILE_LOCAL +ReturnCode evallex(struct Global *global, + int skip, /* TRUE if short-circuit evaluation */ + int *op) +{ + /* + * Set *op to next eval operator or value. Called from eval(). It + * calls a special-purpose routines for 'char' strings and + * numeric values: + * evalchar called to evaluate 'x' + * evalnum called to evaluate numbers. + */ + + int c, c1, t; + ReturnCode ret; + char loop; + + do { /* while(loop); */ + /* again: */ + loop=FALSE; + do { /* Collect the token */ + c = skipws(global); + if(ret=macroid(global, &c)) + return(ret); + if (c == EOF_CHAR || c == '\n') { + unget(global); + *op=OP_EOE; /* End of expression */ + return(FPP_OK); + } + } while ((t = type[c]) == LET && catenate(global, &ret) && !ret); + if(ret) + /* If the loop was broken because of a fatal error! */ + return(ret); + if (t == INV) { /* Total nonsense */ + if (!skip) { + if (isascii(c) && isprint(c)) + cerror(global, ERROR_ILLEGAL_CHARACTER, c); + else + cerror(global, ERROR_ILLEGAL_CHARACTER2, c); + } + return(FPP_ILLEGAL_CHARACTER); + } else if (t == QUO) { /* ' or " */ + if (c == '\'') { /* Character constant */ + global->evalue = evalchar(global, skip); /* Somewhat messy */ + *op=DIG; /* Return a value */ + return(FPP_OK); + } + cerror(global, ERROR_STRING_IN_IF); + return(FPP_CANT_USE_STRING_IN_IF); + } else if (t == LET) { /* ID must be a macro */ + if (streq(global->tokenbuf, "defined")) { /* Or defined name */ + c1 = c = skipws(global); + if (c == '(') /* Allow defined(name) */ + c = skipws(global); + if (type[c] == LET) { + global->evalue = (lookid(global, c) != NULL); + if (c1 != '(' /* Need to balance */ + || skipws(global) == ')') { /* Did we balance? */ + *op=DIG; + return(FPP_OK); /* Parsed ok */ + } + } + cerror(global, ERROR_DEFINED_SYNTAX); + return(FPP_BAD_IF_DEFINED_SYNTAX); + } +#if OK_SIZEOF +else if (streq(global->tokenbuf, "sizeof")) { /* New sizeof hackery */ + ret=dosizeof(global, op); /* Gets own routine */ + return(ret); +} +#endif + global->evalue = 0; + *op=DIG; + return(FPP_OK); + } + else if (t == DIG) { /* Numbers are harder */ + global->evalue = evalnum(global, c); + } + else if (strchr("!=<>&|\\", c) != NULL) { + /* + * Process a possible multi-byte lexeme. + */ + c1 = cget(global); /* Peek at next char */ + switch (c) { + case '!': + if (c1 == '=') { + *op=OP_NE; + return(FPP_OK); + } + break; + + case '=': + if (c1 != '=') { /* Can't say a=b in #if */ + unget(global); + cerror(global, ERROR_ILLEGAL_ASSIGN); + return (FPP_IF_ERROR); + } + *op=OP_EQ; + return(FPP_OK); + + case '>': + case '<': + if (c1 == c) { + *op= ((c == '<') ? OP_ASL : OP_ASR); + return(FPP_OK); + } else if (c1 == '=') { + *op= ((c == '<') ? OP_LE : OP_GE); + return(FPP_OK); + } + break; + + case '|': + case '&': + if (c1 == c) { + *op= ((c == '|') ? OP_ORO : OP_ANA); + return(FPP_OK); + } + break; + + case '\\': + if (c1 == '\n') { /* Multi-line if */ + loop=TRUE; + break; + } + cerror(global, ERROR_ILLEGAL_BACKSLASH); + return(FPP_IF_ERROR); + } + if(!loop) + unget(global); + } + } while(loop); + *op=t; + return(FPP_OK); +} + +#if OK_SIZEOF + +INLINE FILE_LOCAL +ReturnCode dosizeof(struct Global *global, int *result) +{ + /* + * Process the sizeof (basic type) operation in an #if string. + * Sets evalue to the size and returns + * DIG success + * OP_FAIL bad parse or something. + */ + int c; + TYPES *tp; + SIZES *sizp; + short *testp; + short typecode; + ReturnCode ret; + + if ((c = skipws(global)) != '(') { + unget(global); + cerror(global, ERROR_SIZEOF_SYNTAX); + return(FPP_SIZEOF_ERROR); + } + /* + * Scan off the tokens. + */ + typecode = 0; + while ((c = skipws(global))) { + if(ret=macroid(global, &c)) + return(ret); + /* (I) return on fail! */ + if (c == EOF_CHAR || c == '\n') { + /* End of line is a bug */ + unget(global); + cerror(global, ERROR_SIZEOF_SYNTAX); + return(FPP_SIZEOF_ERROR); + } else if (c == '(') { /* thing (*)() func ptr */ + if (skipws(global) == '*' + && skipws(global) == ')') { /* We found (*) */ + if (skipws(global) != '(') /* Let () be optional */ + unget(global); + else if (skipws(global) != ')') { + unget(global); + cerror(global, ERROR_SIZEOF_SYNTAX); + return(FPP_SIZEOF_ERROR); + } + typecode |= T_FPTR; /* Function pointer */ + } else { /* Junk is a bug */ + unget(global); + cerror(global, ERROR_SIZEOF_SYNTAX); + return(FPP_SIZEOF_ERROR); + } + } + else if (type[c] != LET) /* Exit if not a type */ + break; + else if (!catenate(global, &ret) && !ret) { /* Maybe combine tokens */ + /* + * Look for this unexpandable token in basic_types. + * The code accepts "int long" as well as "long int" + * which is a minor bug as bugs go (and one shared with + * a lot of C compilers). + */ + for (tp = basic_types; tp->name != NULLST; tp++) { + if (streq(global->tokenbuf, tp->name)) + break; + } + if (tp->name == NULLST) { + cerror(global, ERROR_SIZEOF_UNKNOWN, global->tokenbuf); + return(FPP_SIZEOF_ERROR); + } + typecode |= tp->type; /* Or in the type bit */ + } else if(ret) + return(ret); + } + /* + * We are at the end of the type scan. Chew off '*' if necessary. + */ + if (c == '*') { + typecode |= T_PTR; + c = skipws(global); + } + if (c == ')') { /* Last syntax check */ + for (testp = test_table; *testp != 0; testp++) { + if (!bittest(typecode & *testp)) { + cerror(global, ERROR_SIZEOF_ILLEGAL_TYPE); + return(FPP_SIZEOF_ERROR); + } + } + /* + * We assume that all function pointers are the same size: + * sizeof (int (*)()) == sizeof (float (*)()) + * We assume that signed and unsigned don't change the size: + * sizeof (signed int) == (sizeof unsigned int) + */ + if ((typecode & T_FPTR) != 0) /* Function pointer */ + typecode = T_FPTR | T_PTR; + else { /* Var or var * datum */ + typecode &= ~(T_SIGNED | T_UNSIGNED); + if ((typecode & (T_SHORT | T_LONG)) != 0) + typecode &= ~T_INT; + } + if ((typecode & ~T_PTR) == 0) { + cerror(global, ERROR_SIZEOF_NO_TYPE); + return(FPP_SIZEOF_ERROR); + } + /* + * Exactly one bit (and possibly T_PTR) may be set. + */ + for (sizp = size_table; sizp->bits != 0; sizp++) { + if ((typecode & ~T_PTR) == sizp->bits) { + global->evalue = ((typecode & T_PTR) != 0) + ? sizp->psize : sizp->size; + *result=DIG; + return(FPP_OK); + } + } /* We shouldn't fail */ + cerror(global, ERROR_SIZEOF_BUG, typecode); + return(FPP_SIZEOF_ERROR); + } + unget(global); + cerror(global, ERROR_SIZEOF_SYNTAX); + return(FPP_SIZEOF_ERROR); +} + +INLINE FILE_LOCAL +int bittest(int value) +{ + /* + * TRUE if value is zero or exactly one bit is set in value. + */ + +#if (4096 & ~(-4096)) == 0 + return ((value & ~(-value)) == 0); +#else + /* + * Do it the hard way (for non 2's complement machines) + */ + return (value == 0 || value ^ (value - 1) == (value * 2 - 1)); +#endif +} + +#endif /* OK_SIZEOF */ + +INLINE FILE_LOCAL +int evalnum(struct Global *global, int c) +{ + /* + * Expand number for #if lexical analysis. Note: evalnum recognizes + * the unsigned suffix, but only returns a signed int value. + */ + + int value; + int base; + int c1; + + if (c != '0') + base = 10; + else if ((c = cget(global)) == 'x' || c == 'X') { + base = 16; + c = cget(global); + } + else base = 8; + value = 0; + for (;;) { + c1 = c; + if (isascii(c) && isupper(c1)) + c1 = tolower(c1); + if (c1 >= 'a') + c1 -= ('a' - 10); + else c1 -= '0'; + if (c1 < 0 || c1 >= base) + break; + value *= base; + value += c1; + c = cget(global); + } + if (c == 'u' || c == 'U') /* Unsigned nonsense */ + c = cget(global); + unget(global); + return (value); +} + +INLINE FILE_LOCAL +int evalchar(struct Global *global, + int skip) /* TRUE if short-circuit evaluation */ + /* + * Get a character constant + */ +{ + int c; + int value; + int count; + + global->instring = TRUE; + if ((c = cget(global)) == '\\') { + switch ((c = cget(global))) { + case 'a': /* New in Standard */ +#if ('a' == '\a' || '\a' == ALERT) + value = ALERT; /* Use predefined value */ +#else + value = '\a'; /* Use compiler's value */ +#endif + break; + + case 'b': + value = '\b'; + break; + + case 'f': + value = '\f'; + break; + + case 'n': + value = '\n'; + break; + + case 'r': + value = '\r'; + break; + + case 't': + value = '\t'; + break; + + case 'v': /* New in Standard */ +#if ('v' == '\v' || '\v' == VT) + value = VT; /* Use predefined value */ +#else + value = '\v'; /* Use compiler's value */ +#endif + break; + + case 'x': /* '\xFF' */ + count = 3; + value = 0; + while ((((c = get(global)) >= '0' && c <= '9') + || (c >= 'a' && c <= 'f') + || (c >= 'A' && c <= 'F')) + && (--count >= 0)) { + value *= 16; + value += (c <= '9') ? (c - '0') : ((c & 0xF) + 9); + } + unget(global); + break; + + default: + if (c >= '0' && c <= '7') { + count = 3; + value = 0; + while (c >= '0' && c <= '7' && --count >= 0) { + value *= 8; + value += (c - '0'); + c = get(global); + } + unget(global); + } else + value = c; + break; + } + } else if (c == '\'') + value = 0; + else value = c; + /* + * We warn on multi-byte constants and try to hack + * (big|little)endian machines. + */ +#if BIG_ENDIAN + count = 0; +#endif + while ((c = get(global)) != '\'' && c != EOF_CHAR && c != '\n') { + if (!skip) + cwarn(global, WARN_MULTIBYTE_NOT_PORTABLE, c); +#if BIG_ENDIAN + count += BITS_CHAR; + value += (c << count); +#else + value <<= BITS_CHAR; + value += c; +#endif + } + global->instring = FALSE; + return (value); +} + +INLINE FILE_LOCAL +int *evaleval(struct Global *global, + int *valp, + int op, + int skip) /* TRUE if short-circuit evaluation */ +{ + /* + * Apply the argument operator to the data on the value stack. + * One or two values are popped from the value stack and the result + * is pushed onto the value stack. + * + * OP_COL is a special case. + * + * evaleval() returns the new pointer to the top of the value stack. + */ + int v1, v2; + + if (isbinary(op)) + v2 = *--valp; + v1 = *--valp; + switch (op) { + case OP_EOE: + break; + case OP_ADD: + v1 += v2; + break; + case OP_SUB: + v1 -= v2; + break; + case OP_MUL: + v1 *= v2; + break; + case OP_DIV: + case OP_MOD: + if (v2 == 0) { + if (!skip) { + cwarn(global, WARN_DIVISION_BY_ZERO, + (op == OP_DIV) ? "divide" : "mod"); + } + v1 = 0; + } + else if (op == OP_DIV) + v1 /= v2; + else + v1 %= v2; + break; + case OP_ASL: + v1 <<= v2; + break; + case OP_ASR: + v1 >>= v2; + break; + case OP_AND: + v1 &= v2; + break; + case OP_OR: + v1 |= v2; + break; + case OP_XOR: + v1 ^= v2; + break; + case OP_EQ: + v1 = (v1 == v2); + break; + case OP_NE: + v1 = (v1 != v2); + break; + case OP_LT: + v1 = (v1 < v2); + break; + case OP_LE: + v1 = (v1 <= v2); + break; + case OP_GE: + v1 = (v1 >= v2); + break; + case OP_GT: + v1 = (v1 > v2); + break; + case OP_ANA: + v1 = (v1 && v2); + break; + case OP_ORO: + v1 = (v1 || v2); + break; + case OP_COL: + /* + * v1 has the "true" value, v2 the "false" value. + * The top of the value stack has the test. + */ + v1 = (*--valp) ? v1 : v2; + break; + case OP_NEG: + v1 = (-v1); + break; + case OP_PLU: + break; + case OP_COM: + v1 = ~v1; + break; + case OP_NOT: + v1 = !v1; + break; + default: + cerror(global, ERROR_IF_OPERAND, op); + v1 = 0; + } + *valp++ = v1; + return (valp); +} diff --git a/cpp6.c b/cpp6.c new file mode 100644 index 0000000..4f3a6d2 --- /dev/null +++ b/cpp6.c @@ -0,0 +1,1246 @@ +#ifdef RCS +static char rcsid[]="$Id: cpp6.c,v 1.5 1994/01/24 09:35:17 start Exp $"; +#endif +/****************************************************************************** +Copyright (c) 1999 Daniel Stenberg + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE +SOFTWARE. +******************************************************************************/ +/****************************************************************************** + * FREXXWARE + * ---------------------------------------------------------------------------- + * + * Project: Frexx C Preprocessor + * $Source: /home/user/start/cpp/RCS/cpp6.c,v $ + * $Revision: 1.5 $ + * $Date: 1994/01/24 09:35:17 $ + * $Author: start $ + * $State: Exp $ + * $Locker: $ + * + * ---------------------------------------------------------------------------- + * $Log: cpp6.c,v $ + * Revision 1.5 1994/01/24 09:35:17 start + * Made the FPPTAG_RIGHTCONCAT work. + * + * Revision 1.4 1993/12/06 13:50:39 start + * A lot of new stuff (too much to mention) + * + * Revision 1.4 1993/12/06 13:50:39 start + * A lot of new stuff (too much to mention) + * + * Revision 1.3 1993/11/29 14:00:32 start + * new + * + * Revision 1.2 1993/11/11 07:16:39 start + * New stuff + * + * Revision 1.1 1993/11/03 09:13:08 start + * Initial revision + * + * + *****************************************************************************/ +/* + * C P P 6 . C + * S u p p o r t R o u t i n e s + * + * Edit History + * 25-May-84 MM Added 8-bit support to type table. + * 30-May-84 ARF sharp() should output filename in quotes + * 02-Aug-84 MM Newline and #line hacking. sharp() now in cpp1.c + * 31-Aug-84 MM USENET net.sources release + * 11-Sep-84 ado/MM Keepcomments, also line number pathological + * 12-Sep-84 ado/MM bug if comment changes to space and we unget later. + * 03-Oct-84 gkr/MM Fixed scannumber bug for '.e' (as in struct.element). + * 04-Oct-84 MM Added ungetstring() for token concatenation + * 08-Oct-84 MM Yet another attack on number scanning + * 31-Oct-84 ado Parameterized $ in identifiers + * 2-Nov-84 MM Token concatenation is messier than I thought + * 6-Dec-84 MM \ is everywhere invisible. + * 21-Oct-85 RMS Rename `token' to `tokenbuf'. + * Dynamically allocate it, and make it as big as needed. + * 23-Oct-85 RMS Fix bugs storing into tokenbuf as it gets bigger. + * Change error msg to cpp: "FILE", line LINE: MSG + * 24-Oct-85 RMS Turn off warnings about / then * inside a comment. + * 16-Mar-86 FNF Incorporate macro based C debugging package. + * Port to Commodore Amiga. + * 20-Aug-88 Ois Added time routines (or actually deleted stubs). + * 20-Aug-88 Ois Changed handling of token following ## to match Cpp4. + * 16-Feb-93 DSt Changed case of getmem() to Getmem(). + */ + +#include +#include +#include "cppdef.h" +#include "cpp.h" + +INLINE FILE_LOCAL void outadefine(struct Global *, DEFBUF *); +INLINE FILE_LOCAL void domsg(struct Global *, ErrorCode, va_list); +FILE_LOCAL char *incmem(struct Global *, char *, int); + +/* + * skipnl() skips over input text to the end of the line. + * skipws() skips over "whitespace" (spaces or tabs), but + * not skip over the end of the line. It skips over + * TOK_SEP, however (though that shouldn't happen). + * scanid() reads the next token (C identifier) into tokenbuf. + * The caller has already read the first character of + * the identifier. Unlike macroid(), the token is + * never expanded. + * macroid() reads the next token (C identifier) into tokenbuf. + * If it is a #defined macro, it is expanded, and + * macroid() returns TRUE, otherwise, FALSE. + * catenate() Does the dirty work of token concatenation, TRUE if it did. + * scanstring() Reads a string from the input stream, calling + * a user-supplied function for each character. + * This function may be output() to write the + * string to the output file, or save() to save + * the string in the work buffer. + * scannumber() Reads a C numeric constant from the input stream, + * calling the user-supplied function for each + * character. (output() or save() as noted above.) + * save() Save one character in the work[] buffer. + * savestring() Saves a string in malloc() memory. + * getfile() Initialize a new FILEINFO structure, called when + * #include opens a new file, or a macro is to be + * expanded. + * Getmem() Get a specified number of bytes from malloc memory. + * output() Write one character to stdout (calling Putchar) -- + * implemented as a function so its address may be + * passed to scanstring() and scannumber(). + * lookid() Scans the next token (identifier) from the input + * stream. Looks for it in the #defined symbol table. + * Returns a pointer to the definition, if found, or NULL + * if not present. The identifier is stored in tokenbuf. + * defnedel() Define enter/delete subroutine. Updates the + * symbol table. + * get() Read the next byte from the current input stream, + * handling end of (macro/file) input and embedded + * comments appropriately. Note that the global + * instring is -- essentially -- a parameter to get(). + * cget() Like get(), but skip over TOK_SEP. + * unget() Push last gotten character back on the input stream. + * cerror() This routine format an print messages to the user. + */ + +/* + * This table must be rewritten for a non-Ascii machine. + * + * Note that several "non-visible" characters have special meaning: + * Hex 1C QUOTE_PARM --a flag for # stringifying + * Hex 1D DEF_MAGIC -- a flag to prevent #define recursion. + * Hex 1E TOK_SEP -- a delimiter for ## token concatenation + * Hex 1F COM_SEP -- a zero-width whitespace for comment concatenation + */ + +#ifndef OS9 +#if (TOK_SEP != 0x1E || COM_SEP != 0x1F || DEF_MAGIC != 0x1D) +#error "<< error type table isn't correct >>" +#endif +#endif + +#if OK_DOLLAR +#define DOL LET +#else +#define DOL 000 +#endif + +char type[256] = { /* Character type codes Hex */ + END, 000, 000, 000, 000, 000, 000, 000, /* 00 */ + 000, SPA, 000, 000, 000, 000, 000, 000, /* 08 */ + 000, 000, 000, 000, 000, 000, 000, 000, /* 10 */ + 000, 000, 000, 000, 000, LET, 000, SPA, /* 18 */ + SPA, OP_NOT, QUO, 000, DOL, OP_MOD,OP_AND,QUO, /* 20 !"#$%&' */ + OP_LPA,OP_RPA,OP_MUL,OP_ADD, 000,OP_SUB, DOT,OP_DIV, /* 28 ()*+,-./ */ + DIG, DIG, DIG, DIG, DIG, DIG, DIG, DIG, /* 30 01234567 */ + DIG, DIG,OP_COL, 000, OP_LT, OP_EQ, OP_GT,OP_QUE, /* 38 89:;<=>? */ + 000, LET, LET, LET, LET, LET, LET, LET, /* 40 @ABCDEFG */ + LET, LET, LET, LET, LET, LET, LET, LET, /* 48 HIJKLMNO */ + LET, LET, LET, LET, LET, LET, LET, LET, /* 50 PQRSTUVW */ + LET, LET, LET, 000, BSH, 000,OP_XOR, LET, /* 58 XYZ[\]^_ */ + 000, LET, LET, LET, LET, LET, LET, LET, /* 60 `abcdefg */ + LET, LET, LET, LET, LET, LET, LET, LET, /* 68 hijklmno */ + LET, LET, LET, LET, LET, LET, LET, LET, /* 70 pqrstuvw */ + LET, LET, LET, 000, OP_OR, 000,OP_NOT, 000, /* 78 xyz{|}~ */ + 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ + 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ + 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ + 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ + 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ + 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ + 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ + 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ +}; + +void skipnl(struct Global *global) +{ + /* + * Skip to the end of the current input line. + */ + int c; + + do { /* Skip to newline */ + c = get(global); + } while (c != '\n' && c != EOF_CHAR); + return; +} + +int skipws(struct Global *global) +{ + /* + * Skip over whitespace + */ + int c; + + do { /* Skip whitespace */ + c = get(global); +#if COMMENT_INVISIBLE + } while (type[c] == SPA || c == COM_SEP); +#else +} while (type[c] == SPA); +#endif + return(c); +} + +void scanid(struct Global *global, + int c) /* First char of id */ +{ + /* + * Get the next token (an id) into the token buffer. + * Note: this code is duplicated in lookid(). + * Change one, change both. + */ + + int ct; + + if (c == DEF_MAGIC) /* Eat the magic token */ + c = get(global); /* undefiner. */ + ct = 0; + do + { + if (ct == global->tokenbsize) + global->tokenbuf = incmem (global, global->tokenbuf, 1 + + (global->tokenbsize *= 2)); + global->tokenbuf[ct++] = c; + c = get(global); + } + while (type[c] == LET || type[c] == DIG); + unget(global); + global->tokenbuf[ct] = EOS; +} + +ReturnCode macroid(struct Global *global, int *c) +{ + /* + * If c is a letter, scan the id. if it's #defined, expand it and scan + * the next character and try again. + * + * Else, return the character. If type[c] is a LET, the token is in tokenbuf. + */ + DEFBUF *dp; + ReturnCode ret=FPP_OK; + + if (global->infile != NULL && global->infile->fp != NULL) + global->recursion = 0; + while (type[*c] == LET && (dp = lookid(global, *c)) != NULL) { + if(ret=expand(global, dp)) + return(ret); + *c = get(global); + } + return(FPP_OK); +} + +int catenate(struct Global *global, ReturnCode *ret) +{ + /* + * A token was just read (via macroid). + * If the next character is TOK_SEP, concatenate the next token + * return TRUE -- which should recall macroid after refreshing + * macroid's argument. If it is not TOK_SEP, unget() the character + * and return FALSE. + */ + +#if OK_CONCAT + int c; + char *token1; +#endif + +#if OK_CONCAT + if (get(global) != TOK_SEP) { /* Token concatenation */ + unget(global); + return (FALSE); + } + else { + token1 = savestring(global, global->tokenbuf); /* Save first token */ + c=get(global); + if(global->rightconcat) { + *ret=macroid(global, &c); /* Scan next token */ + if(*ret) + return(FALSE); + } else + lookid(global, c); + switch(type[c]) { /* What was it? */ + case LET: /* An identifier, ... */ + if ((int)strlen(token1) + (int)strlen(global->tokenbuf) >= NWORK) { + cfatal(global, FATAL_WORK_AREA_OVERFLOW, token1); + *ret=FPP_WORK_AREA_OVERFLOW; + return(FALSE); + } + sprintf(global->work, "%s%s", token1, global->tokenbuf); + break; + case DIG: /* A number */ + case DOT: /* Or maybe a float */ + strcpy(global->work, token1); + global->workp = global->work + strlen(global->work); + *ret=scannumber(global, c, save); + if(*ret) + return(FALSE); + *ret=save(global, EOS); + if(*ret) + return(FALSE); + break; + default: /* An error, ... */ + if (isprint(c)) + cerror(global, ERROR_STRANG_CHARACTER, c); + else + cerror(global, ERROR_STRANG_CHARACTER2, c); + strcpy(global->work, token1); + unget(global); + break; + } + /* + * work has the concatenated token and token1 has + * the first token (no longer needed). Unget the + * new (concatenated) token after freeing token1. + * Finally, setup to read the new token. + */ + Freemem(token1); /* Free up memory */ + *ret=ungetstring(global, global->work); /* Unget the new thing, */ + if(*ret) + return(FALSE); + return(TRUE); + } +#else + return(FALSE); /* Not supported */ +#endif +} + +ReturnCode scanstring(struct Global *global, + int delim, /* ' or " */ + /* Output function: */ + ReturnCode (*outfun)(struct Global *, int)) +{ + /* + * Scan off a string. Warning if terminated by newline or EOF. + * outfun() outputs the character -- to a buffer if in a macro. + * TRUE if ok, FALSE if error. + */ + + int c; + ReturnCode ret; + + global->instring = TRUE; /* Don't strip comments */ + ret=(*outfun)(global, delim); + if(ret) + return(ret); + while ((c = get(global)) != delim + && c != '\n' + && c != EOF_CHAR) { + ret=(*outfun)(global, c); + if(ret) + return(ret); + if (c == '\\') { + ret=(*outfun)(global, get(global)); + if(ret) + return(ret); + } + } + global->instring = FALSE; + if (c == delim) { + ret=(*outfun)(global, c); + return(ret); + } else { + cerror(global, ERROR_UNTERMINATED_STRING); + unget(global); + return(FPP_UNTERMINATED_STRING); + } +} + +ReturnCode scannumber(struct Global *global, + int c, /* First char of number */ + /* Output/store func: */ + ReturnCode (*outfun)(struct Global *, int)) +{ + /* + * Process a number. We know that c is from 0 to 9 or dot. + * Algorithm from Dave Conroy's Decus C. + */ + + int radix; /* 8, 10, or 16 */ + int expseen; /* 'e' seen in floater */ + int signseen; /* '+' or '-' seen */ + int octal89; /* For bad octal test */ + int dotflag; /* TRUE if '.' was seen */ + ReturnCode ret; + char done=FALSE; + + expseen = FALSE; /* No exponent seen yet */ + signseen = TRUE; /* No +/- allowed yet */ + octal89 = FALSE; /* No bad octal yet */ + radix = 10; /* Assume decimal */ + if ((dotflag = (c == '.')) != FALSE) {/* . something? */ + ret=(*outfun)(global, '.'); /* Always out the dot */ + if(ret) + return(ret); + if (type[(c = get(global))] != DIG) { /* If not a float numb, */ + unget(global); /* Rescan strange char */ + return(FPP_OK); /* All done for now */ + } + } /* End of float test */ + else if (c == '0') { /* Octal or hex? */ + ret=(*outfun)(global, c); /* Stuff initial zero */ + if(ret) + return(ret); + radix = 8; /* Assume it's octal */ + c = get(global); /* Look for an 'x' */ + if (c == 'x' || c == 'X') { /* Did we get one? */ + radix = 16; /* Remember new radix */ + ret=(*outfun)(global, c); /* Stuff the 'x' */ + if(ret) + return(ret); + c = get(global); /* Get next character */ + } + } + while (!done) { /* Process curr. char. */ + /* + * Note that this algorithm accepts "012e4" and "03.4" + * as legitimate floating-point numbers. + */ + if (radix != 16 && (c == 'e' || c == 'E')) { + if (expseen) /* Already saw 'E'? */ + break; /* Exit loop, bad nbr. */ + expseen = TRUE; /* Set exponent seen */ + signseen = FALSE; /* We can read '+' now */ + radix = 10; /* Decimal exponent */ + } + else if (radix != 16 && c == '.') { + if (dotflag) /* Saw dot already? */ + break; /* Exit loop, two dots */ + dotflag = TRUE; /* Remember the dot */ + radix = 10; /* Decimal fraction */ + } + else if (c == '+' || c == '-') { /* 1.0e+10 */ + if (signseen) /* Sign in wrong place? */ + break; /* Exit loop, not nbr. */ + /* signseen = TRUE; */ /* Remember we saw it */ + } else { /* Check the digit */ + switch (c) { + case '8': case '9': /* Sometimes wrong */ + octal89 = TRUE; /* Do check later */ + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + break; /* Always ok */ + + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + if (radix == 16) /* Alpha's are ok only */ + break; /* if reading hex. */ + default: /* At number end */ + done=TRUE; /* Break from for loop */ + continue; + } /* End of switch */ + } /* End general case */ + ret=(*outfun)(global, c); /* Accept the character */ + if(ret) + return(ret); + signseen = TRUE; /* Don't read sign now */ + c = get(global); /* Read another char */ + } /* End of scan loop */ + /* + * When we break out of the scan loop, c contains the first + * character (maybe) not in the number. If the number is an + * integer, allow a trailing 'L' for long and/or a trailing 'U' + * for unsigned. If not those, push the trailing character back + * on the input stream. Floating point numbers accept a trailing + * 'L' for "long double". + */ + + if (dotflag || expseen) { /* Floating point? */ + if (c == 'l' || c == 'L') { + ret=(*outfun)(global, c); + if(ret) + return(ret); + c = get(global); /* Ungotten later */ + } + } else { /* Else it's an integer */ + /* + * We know that dotflag and expseen are both zero, now: + * dotflag signals "saw 'L'", and + * expseen signals "saw 'U'". + */ + char done=TRUE; + while(done) { + switch (c) { + case 'l': + case 'L': + if (dotflag) { + done=FALSE; + continue; + } + dotflag = TRUE; + break; + case 'u': + case 'U': + if (expseen) { + done=FALSE; + continue; + } + expseen = TRUE; + break; + default: + done=FALSE; + continue; + } + ret=(*outfun)(global, c); /* Got 'L' or 'U'. */ + if(ret) + return(ret); + c = get(global); /* Look at next, too. */ + } + } + unget(global); /* Not part of a number */ + if(!(global->webmode)) { + if (octal89 && radix == 8) + cwarn(global, WARN_ILLEGAL_OCTAL); + } + return(FPP_OK); +} + +ReturnCode save(struct Global *global, int c) +{ + if (global->workp >= &global->work[NWORK]) { + cfatal(global, FATAL_WORK_BUFFER_OVERFLOW); + return(FPP_WORK_AREA_OVERFLOW); + } else + *global->workp++ = c; + return(FPP_OK); +} + +char *savestring(struct Global *global, char *text) +{ + /* + * Store a string into free memory. + */ + + char *result; + + result = Getmem(global, strlen(text) + 1); + strcpy(result, text); + return (result); +} + +ReturnCode getfile(struct Global *global, + int bufsize, /* Line or define buffer size */ + char *name, + FILEINFO **file) /* File or macro name string */ +{ + /* + * Common FILEINFO buffer initialization for a new file or macro. + */ + + int size; + + size = strlen(name); /* File/macro name */ + + if(!size) { + name = "[stdin]"; + size = strlen(name); + } + + *file = (FILEINFO *) Getmem(global, (int)(sizeof (FILEINFO) + bufsize + size)); + if(!*file) + return(FPP_OUT_OF_MEMORY); + (*file)->parent = global->infile; /* Chain files together */ + (*file)->fp = NULL; /* No file yet */ + (*file)->filename = savestring(global, name); /* Save file/macro name */ + (*file)->progname = NULL; /* No #line seen yet */ + (*file)->unrecur = 0; /* No macro fixup */ + (*file)->bptr = (*file)->buffer; /* Initialize line ptr */ + (*file)->buffer[0] = EOS; /* Force first read */ + (*file)->line = 0; /* (Not used just yet) */ + if (global->infile != NULL) /* If #include file */ + global->infile->line = global->line; /* Save current line */ + global->infile = (*file); /* New current file */ + global->line = 1; /* Note first line */ + return(FPP_OK); /* All done. */ +} + +void Freemem(void *ptr) +{ + /* + * Free a block of memory! + */ + + Free(ptr); +} + + +char *Getmem(struct Global *global, int size) +{ + /* + * Get a block of free memory. + */ + + char *result; + if ((result = (char *)Malloc((unsigned) size)) == NULL) + cfatal(global, FATAL_OUT_OF_MEMORY); + return(result); +} + +FILE_LOCAL +char *incmem(struct Global *global, char *obj, int size) +{ + /* + * Get a block of free memory. + */ + + char *result; + if ((result = Realloc(obj, (unsigned) size)) == NULL) + cfatal(global, FATAL_OUT_OF_MEMORY); + return(result); +} + +/* + * C P P S y m b o l T a b l e s + */ + +DEFBUF *lookid(struct Global *global, + int c) /* First character of token */ +{ + /* + * Look for the next token in the symbol table. Returns token in tokenbuf. + * If found, returns the table pointer; Else returns NULL. + */ + + int nhash; + DEFBUF *dp; + int ct; + int temp; + int isrecurse; /* For #define foo foo */ + + nhash = 0; + if ((isrecurse = (c == DEF_MAGIC))) /* If recursive macro */ + c = get(global); /* hack, skip DEF_MAGIC */ + ct = 0; + do { + if (ct == global->tokenbsize) + global->tokenbuf = incmem(global, global->tokenbuf, 1 + (global->tokenbsize *= 2)); + global->tokenbuf[ct++] = c; /* Store token byte */ + nhash += c; /* Update hash value */ + c = get(global); + } while (type[c] == LET || type[c] == DIG); + unget(global); /* Rescan terminator */ + global->tokenbuf[ct] = EOS; /* Terminate token */ + if (isrecurse) /* Recursive definition */ + return(NULL); /* undefined just now */ + nhash += ct; /* Fix hash value */ + dp = global->symtab[nhash % SBSIZE]; /* Starting bucket */ + while (dp != (DEFBUF *) NULL) { /* Search symbol table */ + if (dp->hash == nhash /* Fast precheck */ + && (temp = strcmp(dp->name, global->tokenbuf)) >= 0) + break; + dp = dp->link; /* Nope, try next one */ + } + return((temp == 0) ? dp : NULL); +} + +DEFBUF *defendel(struct Global *global, + char *name, + int delete) /* TRUE to delete a symbol */ +{ + /* + * Enter this name in the lookup table (delete = FALSE) + * or delete this name (delete = TRUE). + * Returns a pointer to the define block (delete = FALSE) + * Returns NULL if the symbol wasn't defined (delete = TRUE). + */ + + DEFBUF *dp; + DEFBUF **prevp; + char *np; + int nhash; + int temp; + int size; + + for (nhash = 0, np = name; *np != EOS;) + nhash += *np++; + size = (np - name); + nhash += size; + prevp = &global->symtab[nhash % SBSIZE]; + while ((dp = *prevp) != (DEFBUF *) NULL) { + if (dp->hash == nhash + && (temp = strcmp(dp->name, name)) >= 0) { + if (temp > 0) + dp = NULL; /* Not found */ + else { + *prevp = dp->link; /* Found, unlink and */ + if (dp->repl != NULL) /* Free the replacement */ + Freemem(dp->repl); /* if any, and then */ + Freemem((char *) dp); /* Free the symbol */ + } + break; + } + prevp = &dp->link; + } + if (!delete) { + dp = (DEFBUF *) Getmem(global, (int) (sizeof (DEFBUF) + size)); + dp->link = *prevp; + *prevp = dp; + dp->hash = nhash; + dp->repl = NULL; + dp->nargs = 0; + strcpy(dp->name, name); + } + return(dp); +} + + +void outdefines(struct Global *global) +{ + DEFBUF *dp; + DEFBUF **syp; + + deldefines(global); /* Delete built-in #defines */ + for (syp = global->symtab; syp < &global->symtab[SBSIZE]; syp++) { + if ((dp = *syp) != (DEFBUF *) NULL) { + do { + outadefine(global, dp); + } while ((dp = dp->link) != (DEFBUF *) NULL); + } + } +} + +INLINE FILE_LOCAL +void outadefine(struct Global *global, DEFBUF *dp) +{ + char *cp; + int c; + + /* printf("#define %s", dp->name); */ + Putstring(global, "#define "); + Putstring(global, dp->name); + + if (dp->nargs > 0) { + int i; + Putchar(global, '('); + for (i = 1; i < dp->nargs; i++) { + /* printf("__%d,", i); */ + Putstring(global, "__"); + Putint(global, i); + Putchar(global, ','); + } + /* printf("__%d)", i); */ + Putstring(global, "__"); + Putint(global, i); + Putchar(global, ')'); + + } else if (dp->nargs == 0) { + Putstring(global, "()"); + } + if (dp->repl != NULL) { + Putchar(global, '\t'); + for (cp = dp->repl; (c = *cp++ & 0xFF) != EOS;) { + if (c >= MAC_PARM && c < (MAC_PARM + PAR_MAC)) { + /* printf("__%d", c - MAC_PARM + 1); */ + Putstring(global, "__"); + Putint(global, c - MAC_PARM + 1); + } else if (isprint(c) || c == '\t' || c == '\n') + Putchar(global, c); + else switch (c) { + case QUOTE_PARM: + Putchar(global, '#'); + break; + case DEF_MAGIC: /* Special anti-recursion */ + case MAC_PARM + PAR_MAC: /* Special "arg" marker */ + break; + case COM_SEP: +#if COMMENT_INVISIBLE + Putstring(global, "/**/"); +#else + Putchar(global, ' '); +#endif + break; + case TOK_SEP: + Putstring(global, "##"); + break; + default: + { + /* Octal output! */ + char buffer[32]; + sprintf(buffer, "\\0%o", c); + Putstring(global, buffer); + } + } + } + } + Putchar(global, '\n'); +} + +/* + * G E T + */ + +int get(struct Global *global) +{ + /* + * Return the next character from a macro or the current file. + * Handle end of file from #include files. + */ + + int c; + FILEINFO *file; + int popped; /* Recursion fixup */ + long comments=0; + + popped = 0; + get_from_file: + if ((file = global->infile) == NULL) + return (EOF_CHAR); + newline: + /* + * Read a character from the current input line or macro. + * At EOS, either finish the current macro (freeing temp. + * storage) or read another line from the current input file. + * At EOF, exit the current file (#include) or, at EOF from + * the cpp input file, return EOF_CHAR to finish processing. + */ + if ((c = *file->bptr++ & 0xFF) == EOS) { + /* + * Nothing in current line or macro. Get next line (if + * input from a file), or do end of file/macro processing. + * In the latter case, jump back to restart from the top. + */ + if (file->fp == NULL) { /* NULL if macro */ + popped++; + global->recursion -= file->unrecur; + if (global->recursion < 0) + global->recursion = 0; + global->infile = file->parent; /* Unwind file chain */ + } else { /* Else get from a file */ + /* + * If a input routine has been specified in the initial taglist, + * we should get the next line from that function IF we're reading + * from that certain file! + */ + + if(global->input && global->first_file && !strcmp(global->first_file, file->filename)) + file->bptr = global->input(file->buffer, NBUFF, global->userdata); + else + file->bptr = fgets(file->buffer, NBUFF, file->fp); + if(file->bptr != NULL) { + goto newline; /* process the line */ + } else { + if(!(global->input && global->first_file && !strcmp(global->first_file, file->filename))) + /* If the input function isn't user supplied, close the file! */ + fclose(file->fp); /* Close finished file */ + if ((global->infile = file->parent) != NULL) { + /* + * There is an "ungotten" newline in the current + * infile buffer (set there by doinclude() in + * cpp1.c). Thus, we know that the mainline code + * is skipping over blank lines and will do a + * #line at its convenience. + */ + global->wrongline = TRUE; /* Need a #line now */ + } + } + } + /* + * Free up space used by the (finished) file or macro and + * restart input from the parent file/macro, if any. + */ + Freemem(file->filename); /* Free name and */ + if (file->progname != NULL) /* if a #line was seen, */ + Freemem(file->progname); /* free it, too. */ + Freemem(file); /* Free file space */ + if (global->infile == NULL) /* If at end of file */ + return (EOF_CHAR); /* Return end of file */ + global->line = global->infile->line; /* Reset line number */ + goto get_from_file; /* Get from the top. */ + } + /* + * Common processing for the new character. + */ + if (c == DEF_MAGIC && file->fp != NULL) /* Don't allow delete */ + goto newline; /* from a file */ + if (file->parent != NULL) { /* Macro or #include */ + if (popped != 0) + file->parent->unrecur += popped; + else { + global->recursion -= file->parent->unrecur; + if (global->recursion < 0) + global->recursion = 0; + file->parent->unrecur = 0; + } + } + if (c == '\n') /* Maintain current */ + ++global->line; /* line counter */ + if (global->instring) /* Strings just return */ + return (c); /* the character. */ + else if (c == '/') { /* Comment? */ + global->instring = TRUE; /* So get() won't loop */ + + /* Check next byte for '*' and if(cplusplus) also '/' */ + if ( (c = get(global)) != '*' ) + if(!global->cplusplus || (global->cplusplus && c!='/')) { + global->instring = FALSE; /* Nope, no comment */ + unget(global); /* Push the char. back */ + return ('/'); /* Return the slash */ + } + + comments = 1; + + if (global->keepcomments) { /* If writing comments */ + + global->comment = TRUE; /* information that a comment has been output */ + if(global->showspace) { + /* Show all whitespaces! */ + global->spacebuf[global->chpos] = '\0'; + Putstring(global, global->spacebuf); + } + + if(c=='*') { + Putchar(global, '/'); /* Write out the */ + Putchar(global, '*'); /* initializer */ + } else { + /* C++ style comment */ + Putchar(global, '/'); /* Write out the */ + Putchar(global, '/'); /* initializer */ + } + } + + if(global->cplusplus && c=='/') { /* Eat C++ comment! */ + do { + c=get(global); + if(global->keepcomments) + Putchar(global, c); + } while(c!='\n' && c!=EOF_CHAR); /* eat all to EOL or EOF */ + global->instring = FALSE; /* End of comment */ + return(c); /* Return the end char */ + } + + for (;;) { /* Eat a comment */ + c = get(global); + test: + if (global->keepcomments && c != EOF_CHAR) + Putchar(global, c); + switch (c) { + case EOF_CHAR: + cerror(global, ERROR_EOF_IN_COMMENT); + return (EOF_CHAR); + + case '/': + if(global->nestcomments || global->warnnestcomments) { + if((c = get(global)) != '*') + goto test; + if(global->warnnestcomments) { + cwarn(global, WARN_NESTED_COMMENT); + } + if(global->nestcomments) + comments++; + } + break; + + case '*': + if ((c = get(global)) != '/') /* If comment doesn't */ + goto test; /* end, look at next */ + if (global->keepcomments) { /* Put out the comment */ + Putchar(global, c); /* terminator, too */ + } + if(--comments) + /* nested comment, continue! */ + break; + + global->instring = FALSE; /* End of comment, */ + /* + * A comment is syntactically "whitespace" -- + * however, there are certain strange sequences + * such as + * #define foo(x) (something) + * foo|* comment *|(123) + * these are '/' ^ ^ + * where just returning space (or COM_SEP) will cause + * problems. This can be "fixed" by overwriting the + * '/' in the input line buffer with ' ' (or COM_SEP) + * but that may mess up an error message. + * So, we peek ahead -- if the next character is + * "whitespace" we just get another character, if not, + * we modify the buffer. All in the name of purity. + */ + if (*file->bptr == '\n' + || type[*file->bptr & 0xFF] == SPA) + goto newline; +#if COMMENT_INVISIBLE + /* + * Return magic (old-fashioned) syntactic space. + */ + return ((file->bptr[-1] = COM_SEP)); +#else + return ((file->bptr[-1] = ' ')); +#endif + + case '\n': /* we'll need a #line */ + if (!global->keepcomments) + global->wrongline = TRUE; /* later... */ + default: /* Anything else is */ + break; /* Just a character */ + } /* End switch */ + } /* End comment loop */ + } /* End if in comment */ + else if (!global->inmacro && c == '\\') { /* If backslash, peek */ + if ((c = get(global)) == '\n') { /* for a . If so, */ + global->wrongline = TRUE; + goto newline; + } else { /* Backslash anything */ + unget(global); /* Get it later */ + return ('\\'); /* Return the backslash */ + } + } else if (c == '\f' || c == VT) /* Form Feed, Vertical */ + c = ' '; /* Tab are whitespace */ + return (c); /* Just return the char */ +} + +void unget(struct Global *global) +{ + /* + * Backup the pointer to reread the last character. Fatal error + * (code bug) if we backup too far. unget() may be called, + * without problems, at end of file. Only one character may + * be ungotten. If you need to unget more, call ungetstring(). + */ + + FILEINFO *file; + if ((file = global->infile) == NULL) + return; /* Unget after EOF */ + if (--file->bptr < file->buffer) { + cfatal(global, FATAL_TOO_MUCH_PUSHBACK); + /* This happens only if used the wrong way! */ + return; + } + if (*file->bptr == '\n') /* Ungetting a newline? */ + --global->line; /* Unget the line number, too */ +} + +ReturnCode ungetstring(struct Global *global, char *text) +{ + /* + * Push a string back on the input stream. This is done by treating + * the text as if it were a macro. + */ + + FILEINFO *file; + ReturnCode ret; + + ret = getfile(global, strlen(text) + 1, "", &file); + if(!ret) + strcpy(file->buffer, text); + return(ret); +} + +int cget(struct Global *global) +{ + /* + * Get one character, absorb "funny space" after comments or + * token concatenation + */ + + int c; + do { + c = get(global); +#if COMMENT_INVISIBLE + } while (c == TOK_SEP || c == COM_SEP); +#else + } while (c == TOK_SEP); +#endif + return (c); +} + +/* + * Error messages and other hacks. + */ + +INLINE FILE_LOCAL +void domsg(struct Global *global, + ErrorCode error, /* error message number */ + va_list arg) /* Something for the message */ +{ + /* + * Print filenames, macro names, and line numbers for error messages. + */ + + static char *ErrorMessage[]={ + /* + * ERRORS: + */ + "#%s must be in an #if", + "#%s may not follow #else", + "#error directive encountered", + "Preprocessor assertion failure", + "#if, #ifdef, or #ifndef without an argument", + "#include syntax error", + "#define syntax error", + "Redefining defined variable \"%s\"", + "Illegal #undef argument", + "Recursive macro definition of \"%s\"(Defined by \"%s\")", + "end of file within macro argument", + "misplaced constant in #if", + "#if value stack overflow", + "Illegal #if line", + "Operator %s in incorrect context", + "expression stack overflow at op \"%s\"", + "unbalanced paren's, op is \"%s\"", + "Misplaced '?' or ':', previous operator is %s", + "Can't use a string in an #if", + "Bad #if ... defined() syntax", + "= not allowed in #if", + "Unexpected \\ in #if", + "#if ... sizeof() syntax error", + "#if sizeof, unknown type \"%s\"", + "#if ... sizeof: illegal type combination", + "#if sizeof() error, no type specified", + "Unterminated string", + "EOF in comment", + "Inside #ifdef block at end of input, depth = %d", + "illegal character '%c' in #if", + "illegal character (%d decimal) in #if", + "#if ... sizeof: bug, unknown type code 0x%x", + "#if bug, operand = %d.", + "Strange character '%c' after ##", + "Strange character (%d.) after ##", + + "", /* Dummy, to visualize the border between errors and warnings */ + /* + * WARNINGS: + */ + "Control line \"%s\" within macro expansion", + "Illegal # command \"%s\"", + "Unexpected text in #control line ignored", + "too few values specified to sizeof", + "too many values specified to sizeof! Not used.", + "\"%s\" wasn't defined", + "Internal error!", + "Macro \"%s\" needs arguments", + "Wrong number of macro arguments for \"%s\"", + "%s by zero in #if, zero result assumed", + "Illegal digit in octal number", + "multi-byte constant '%c' isn't portable", + "Cannot open include file \"%s\"", + "Illegal bracket '[]' balance, depth = %d", + "Illegal parentheses '()' balance, depth = %d", + "Illegal brace '{}' balance, depth = %d", + "Nested comment", + + "", /* Dummy, to visualize the border between warnings and fatals */ + + /* + * FATALS: + */ + "Too many nested #%s statements", + "Filename work buffer overflow", + "Too many include directories", + "Too many include files", + "Too many arguments for macro", + "Macro work area overflow", + "Bug: Illegal __ macro \"%s\"", + "Too many arguments in macro expansion", + "Out of space in macro \"%s\" arg expansion", + "work buffer overflow doing %s ##", + "Work buffer overflow", + "Out of memory", + "Too much pushback", /* internal */ + }; + + char *tp; + FILEINFO *file; + char *severity=errorinfile; file && !file->fp; file = file->parent) + ; + tp = file ? file->filename : 0; + Error(global, "%s\"%s\", line %d: %s: ", + MSG_PREFIX, tp, global->infile->fp?global->line:file->line, severity); + if(global->error) + global->error(global->userdata, ErrorMessage[error], arg); +#if defined(UNIX) + else + vfprintf(stderr, ErrorMessage[error], arg); +#elif defined(AMIGA) + else + return; +#endif + Error(global, "\n"); + + if (file) /*OIS*0.92*/ + while ((file = file->parent) != NULL) { /* Print #includes, too */ + tp = file->parent ? "," : "."; + if (file->fp == NULL) + Error(global, " from macro %s%s\n", file->filename, tp); + else + Error(global, " from file %s, line %d%s\n", + (file->progname != NULL) ? file->progname : file->filename, + file->line, tp); + } + + if(errorerrors++; +} + +void cerror(struct Global *global, + ErrorCode message, + ...) /* arguments */ +{ + /* + * Print a normal error message, string argument. + */ + va_list arg; + va_start(arg, message); + domsg(global, message, arg); +} + +void Error(struct Global *global, char *format, ...) +{ + /* + * Just get the arguments and send a decent string to the user error + * string handler or to stderr. + */ + + va_list arg; + va_start(arg, format); + if(global->error) + global->error(global->userdata, format, arg); +#if defined(UNIX) + else + vfprintf(stderr, format, arg); +#endif +} diff --git a/cppadd.h b/cppadd.h new file mode 100644 index 0000000..a088af3 --- /dev/null +++ b/cppadd.h @@ -0,0 +1,411 @@ +/****************************************************************************** + * FREXXWARE + * ---------------------------------------------------------------------------- + * + * Project: Frexx C Preprocessor + * $Source: /home/user/start/cpp/RCS/cppadd.h,v $ + * $Revision: 1.5 $ + * $Date: 1994/01/24 09:38:12 $ + * $Author: start $ + * $State: Exp $ + * $Locker: start $ + * + * ---------------------------------------------------------------------------- + * $Log: cppadd.h,v $ + * Revision 1.5 1994/01/24 09:38:12 start + * Added the 'rightconcat' in the global structure. + * + * Revision 1.4 1993/12/06 13:51:20 start + * A lot of new stuff (too much to mention) + * + * Revision 1.3 1993/11/29 14:01:13 start + * New features added + * + * Revision 1.2 1993/11/11 07:16:39 start + * New stuff + * + * Revision 1.1 1993/11/03 09:15:59 start + * Initial revision + * + * + *****************************************************************************/ +/********************************************************************** + * + * cppadd.h + * + * Prototypes and structures added by Daniel Stenberg. + * + *******/ + +#include +#include "memory.h" + +struct Global { + + /* + * Commonly used global variables: + * line is the current input line number. + * wrongline is set in many places when the actual output + * line is out of sync with the numbering, e.g, + * when expanding a macro with an embedded newline. + * + * tokenbuf holds the last identifier scanned (which might + * be a candidate for macro expansion). + * errors is the running cpp error counter. + * infile is the head of a linked list of input files (extended by + * #include and macros being expanded). infile always points + * to the current file/macro. infile->parent to the includer, + * etc. infile->fd is NULL if this input stream is a macro. + */ + int line; /* Current line number */ + int wrongline; /* Force #line to compiler */ + char *tokenbuf; /* Buffer for current input token */ + char *functionname; /* Buffer for current function */ + int funcline; /* Line number of current function */ + int tokenbsize; /* Allocated size of tokenbuf, */ + /* not counting zero at end. */ + int errors; /* cpp error counter */ + FILEINFO *infile; /* Current input file */ +#if DEBUG + int debug; /* TRUE if debugging now */ +#endif + /* + * This counter is incremented when a macro expansion is initiated. + * If it exceeds a built-in value, the expansion stops -- this tests + * for a runaway condition: + * #define X Y + * #define Y X + * X + * This can be disabled by falsifying rec_recover. (Nothing does this + * currently: it is a hook for an eventual invocation flag.) + */ + int recursion; /* Infinite recursion counter */ + int rec_recover; /* Unwind recursive macros */ + + /* + * instring is set TRUE when a string is scanned. It modifies the + * behavior of the "get next character" routine, causing all characters + * to be passed to the caller (except ). Note especially that + * comments and \ are not removed from the source. (This + * prevents cpp output lines from being arbitrarily long). + * + * inmacro is set by #define -- it absorbs comments and converts + * form-feed and vertical-tab to space, but returns \ + * to the caller. Strictly speaking, this is a bug as \ + * shouldn't delimit tokens, but we'll worry about that some other + * time -- it is more important to prevent infinitly long output lines. + * + * instring and inmarcor are parameters to the get() routine which + * were made global for speed. + */ + int instring; /* TRUE if scanning string */ + int inmacro; /* TRUE if #defining a macro */ + + /* + * work[] and workp are used to store one piece of text in a temporay + * buffer. To initialize storage, set workp = work. To store one + * character, call save(c); (This will fatally exit if there isn't + * room.) To terminate the string, call save(EOS). Note that + * the work buffer is used by several subroutines -- be sure your + * data won't be overwritten. The extra byte in the allocation is + * needed for string formal replacement. + */ + char work[NWORK + 1]; /* Work buffer */ + char *workp; /* Work buffer pointer */ + + /* + * keepcomments is set TRUE by the -C option. If TRUE, comments + * are written directly to the output stream. This is needed if + * the output from cpp is to be passed to lint (which uses commands + * embedded in comments). cflag contains the permanent state of the + * -C flag. keepcomments is always falsified when processing #control + * commands and when compilation is supressed by a false #if + * + * If eflag is set, CPP returns "success" even if non-fatal errors + * were detected. + * + * If nflag is non-zero, no symbols are predefined except __LINE__. + * __FILE__, and __DATE__. If nflag > 1, absolutely no symbols + * are predefined. + */ + char keepcomments; /* Write out comments flag */ + char cflag; /* -C option (keep comments) */ + char eflag; /* -E option (never fail) */ + char nflag; /* -N option (no predefines) */ + char wflag; /* -W option (write #defines) */ + + /* + * ifstack[] holds information about nested #if's. It is always + * accessed via *ifptr. The information is as follows: + * WAS_COMPILING state of compiling flag at outer level. + * ELSE_SEEN set TRUE when #else seen to prevent 2nd #else. + * TRUE_SEEN set TRUE when #if or #elif succeeds + * ifstack[0] holds the compiling flag. It is TRUE if compilation + * is currently enabled. Note that this must be initialized TRUE. + */ + char ifstack[BLK_NEST]; /* #if information */ + char *ifptr; /* -> current ifstack[] */ + + /* + * incdir[] stores the -i directories (and the system-specific + * #include <...> directories. + */ + char *incdir[NINCLUDE]; /* -i directories */ + char **incend; /* -> free space in incdir[] */ + + /* + * include[] stores the -X and -x files. + */ + char *include[NINCLUDE]; + char includeshow[NINCLUDE]; /* show it or not! */ + char included; + + /* + * This is the table used to predefine target machine and operating + * system designators. It may need hacking for specific circumstances. + * Note: it is not clear that this is part of the Ansi Standard. + * The -B option supresses preset definitions. + */ + char *preset[5]; /* names defined at cpp start */ + + /* + * The value of these predefined symbols must be recomputed whenever + * they are evaluated. The order must not be changed. + */ + char *magic[5]; /* Note: order is important */ + + /* + * This is the variable saying if Cpp should remove C++ style comments from + * the output. Default is... TRUE, yes, pronto, do it!!! + */ + + char cplusplus; + + char *sharpfilename; + + + /* + * parm[], parmp, and parlist[] are used to store #define() argument + * lists. nargs contains the actual number of parameters stored. + */ + char parm[NPARMWORK + 1]; /* define param work buffer */ + char *parmp; /* Free space in parm */ + char *parlist[LASTPARM]; /* -> start of each parameter */ + int nargs; /* Parameters for this macro */ + + DEFBUF *macro; /* Catches start of infinite macro */ + + DEFBUF *symtab[SBSIZE]; /* Symbol table queue headers */ + + int evalue; /* Current value from evallex() */ + + char *(*input)(char *, int, void *); /* Input function */ + + char *first_file; /* Preprocessed file. */ + + void *userdata; /* Data sent to input function */ + + void (*output)(int, void *); /* output function */ + + void (*error)(void *, char *, va_list); /* error function */ + + char linelines; + + char warnillegalcpp; /* warn for illegal preprocessor instructions? */ + + char outputLINE; /* output 'line' in #line instructions */ + + char showversion; /* display version */ + + char showincluded; /* display included files */ + + char showbalance; /* display paren balance */ + + char showspace; /* display all whitespaces as they are */ + + char comment; /* TRUE if a comment just has been written to output */ + + char *spacebuf; /* Buffer to store whitespaces in if -H */ + + long chpos; /* Number of whitespaces in buffer */ + + char nestcomments; /* Allow nested comments */ + + char warnnestcomments; /* Warn at nested comments */ + + char warnnoinclude; /* Warn at missing include file */ + + char outputfile; /* output the main file */ + + char out; /* should we output anything now? */ + + char rightconcat; /* should the right part of a concatenation be avaluated + before the concat (TRUE) or after (FALSE) */ + char *initialfunc; /* file to include first in all functions */ + + char *excludedinit[20]; /* functions (names) excluded from the initfunc */ + int excluded; + + char outputfunctions; /* output all discovered functions to stderr! */ + + char webmode; /* WWW process mode */ +}; + +typedef enum { + ERROR_STRING_MUST_BE_IF, + ERROR_STRING_MAY_NOT_FOLLOW_ELSE, + ERROR_ERROR, + ERROR_PREPROC_FAILURE, + ERROR_MISSING_ARGUMENT, + ERROR_INCLUDE_SYNTAX, + ERROR_DEFINE_SYNTAX, + ERROR_REDEFINE, + ERROR_ILLEGAL_UNDEF, + ERROR_RECURSIVE_MACRO, + ERROR_EOF_IN_ARGUMENT, + ERROR_MISPLACED_CONSTANT, + ERROR_IF_OVERFLOW, + ERROR_ILLEGAL_IF_LINE, + ERROR_OPERATOR, + ERROR_EXPR_OVERFLOW, + ERROR_UNBALANCED_PARENS, + ERROR_MISPLACED, + ERROR_STRING_IN_IF, + ERROR_DEFINED_SYNTAX, + ERROR_ILLEGAL_ASSIGN, + ERROR_ILLEGAL_BACKSLASH, + ERROR_SIZEOF_SYNTAX, + ERROR_SIZEOF_UNKNOWN, + ERROR_SIZEOF_ILLEGAL_TYPE, + ERROR_SIZEOF_NO_TYPE, + ERROR_UNTERMINATED_STRING, + ERROR_EOF_IN_COMMENT, + ERROR_IFDEF_DEPTH, + ERROR_ILLEGAL_CHARACTER, + ERROR_ILLEGAL_CHARACTER2, + ERROR_SIZEOF_BUG, + ERROR_IF_OPERAND, + ERROR_STRANG_CHARACTER, + ERROR_STRANG_CHARACTER2, + + BORDER_ERROR_WARN, /* below this number: errors, above: warnings */ + + WARN_CONTROL_LINE_IN_MACRO, + WARN_ILLEGAL_COMMAND, + WARN_UNEXPECTED_TEXT_IGNORED, + WARN_TOO_FEW_VALUES_TO_SIZEOF, + WARN_TOO_MANY_VALUES_TO_SIZEOF, + WARN_NOT_DEFINED, + WARN_INTERNAL_ERROR, + WARN_MACRO_NEEDS_ARGUMENTS, + WARN_WRONG_NUMBER_ARGUMENTS, + WARN_DIVISION_BY_ZERO, + WARN_ILLEGAL_OCTAL, + WARN_MULTIBYTE_NOT_PORTABLE, + WARN_CANNOT_OPEN_INCLUDE, + WARN_BRACKET_DEPTH, + WARN_PAREN_DEPTH, + WARN_BRACE_DEPTH, + WARN_NESTED_COMMENT, + + BORDER_WARN_FATAL, /* below this number: warnings, above: fatals */ + + FATAL_TOO_MANY_NESTINGS, + FATAL_FILENAME_BUFFER_OVERFLOW, + FATAL_TOO_MANY_INCLUDE_DIRS, + FATAL_TOO_MANY_INCLUDE_FILES, + FATAL_TOO_MANY_ARGUMENTS_MACRO, + FATAL_MACRO_AREA_OVERFLOW, + FATAL_ILLEGAL_MACRO, + FATAL_TOO_MANY_ARGUMENTS_EXPANSION, + FATAL_OUT_OF_SPACE_IN_ARGUMENT, + FATAL_WORK_AREA_OVERFLOW, + FATAL_WORK_BUFFER_OVERFLOW, + FATAL_OUT_OF_MEMORY, + FATAL_TOO_MUCH_PUSHBACK + + + } ErrorCode; + +/********************************************************************** + * RETURN CODES: + *********************************************************************/ + +typedef enum { + FPP_OK, + FPP_OUT_OF_MEMORY, + FPP_TOO_MANY_NESTED_STATEMENTS, + FPP_FILENAME_BUFFER_OVERFLOW, + FPP_NO_INCLUDE, + FPP_OPEN_ERROR, + FPP_TOO_MANY_ARGUMENTS, + FPP_WORK_AREA_OVERFLOW, + FPP_ILLEGAL_MACRO, + FPP_EOF_IN_MACRO, + FPP_OUT_OF_SPACE_IN_MACRO_EXPANSION, + FPP_ILLEGAL_CHARACTER, + FPP_CANT_USE_STRING_IN_IF, + FPP_BAD_IF_DEFINED_SYNTAX, + FPP_IF_ERROR, + FPP_SIZEOF_ERROR, + FPP_UNTERMINATED_STRING, + FPP_TOO_MANY_INCLUDE_DIRS, + FPP_TOO_MANY_INCLUDE_FILES, + FPP_INTERNAL_ERROR, + + FPP_LAST_ERROR +} ReturnCode; + +/* Nasty defines to make them appear as three different functions! */ +#define cwarn cerror +#define cfatal cerror + + +/********************************************************************** + * PROTOTYPES: + *********************************************************************/ +int PREFIX fppPreProcess(REG(a0) struct fppTag *); +void Freemem(void *); +void Error(struct Global *, char *, ...); +void Putchar(struct Global *, int); +void Putstring(struct Global *, char *); +void Putint(struct Global *, int); +char *savestring(struct Global *, char *); +ReturnCode addfile(struct Global *, FILE *, char *); +int catenate(struct Global *, ReturnCode *); +void cerror(struct Global *, ErrorCode, ...); +ReturnCode control(struct Global *, int *); +ReturnCode dodefine(struct Global *); +int dooptions(struct Global *, struct fppTag *); +void doundef(struct Global *); +void dumpparm(char *); +ReturnCode expand(struct Global *, DEFBUF *); +int get(struct Global *); +ReturnCode initdefines(struct Global *); +void outdefines(struct Global *); +ReturnCode save(struct Global *, int); +void scanid(struct Global *, int); +ReturnCode scannumber(struct Global *, int, ReturnCode(*)(struct Global *, int)); +ReturnCode scanstring(struct Global *, int, ReturnCode(*)(struct Global *, int)); +void unget(struct Global *); +ReturnCode ungetstring(struct Global *, char *); +ReturnCode eval(struct Global *, int *); +#ifdef DEBUG_EVAL +void dumpstack(OPTAB[NEXP], register OPTAB *, int [NEXP], register int *); +#endif +void skipnl(struct Global *); +int skipws(struct Global *); +ReturnCode macroid(struct Global *, int *); +ReturnCode getfile(struct Global *, int, char *, FILEINFO **); +DEFBUF *lookid(struct Global *, int ); +DEFBUF *defendel(struct Global *, char *, int); +#if DEBUG +void dumpdef(char *); +void dumpadef(char *, register DEFBUF *); +#endif +ReturnCode openfile(struct Global *,char *); +int cget(struct Global *); +void deldefines(struct Global *); +char *Getmem(struct Global *, int); +ReturnCode openinclude(struct Global *, char *, int); +ReturnCode expstuff(struct Global *, char *, char *); diff --git a/cppdef.h b/cppdef.h new file mode 100644 index 0000000..c188a22 --- /dev/null +++ b/cppdef.h @@ -0,0 +1,383 @@ +/****************************************************************************** + * FREXXWARE + * ---------------------------------------------------------------------------- + * + * Project: Frexx C Preprocessor + * $Source: /home/user/start/cpp/RCS/cppdef.h,v $ + * $Revision: 1.4 $ + * $Date: 1993/12/06 13:51:20 $ + * $Author: start $ + * $State: Exp $ + * $Locker: start $ + * + * ---------------------------------------------------------------------------- + * $Log: cppdef.h,v $ + * Revision 1.4 1993/12/06 13:51:20 start + * A lot of new stuff (too much to mention) + * + * Revision 1.3 1993/11/29 14:01:13 start + * New features added + * + * Revision 1.2 1993/11/11 07:16:39 start + * New stuff + * + * Revision 1.1 1993/11/03 09:15:59 start + * Initial revision + * + * + *****************************************************************************/ +#ifdef EMACS + +/* Use the Emacs config file to find out what type of machine */ + +#define NO_SHORTNAMES + +/* Convert Emacs's conventions for BIG_ENDIAN to cpp's convention. */ +#ifdef BIG_ENDIAN +#undef BIG_ENDIAN +#define BIG_ENDIAN TRUE +#else /* not BIG_ENDIAN */ +#define BIG_ENDIAN FALSE +#endif /* BIG_ENDIAN */ + +/* Emacs uses the names index and rindex and defines them as str(r)chr if nec; + cpp uses the opposite convention. Here we flush the macro definitions for + Emacs and add the ones cpp wants. */ + +#ifdef index +#undef index +#undef rindex +#else /* index is not defined as a macro */ +#define strchr index +#define strrchr rindex +#endif /* index is not defined as a macro */ + +#define NBUFF 2048 +#define NWORK 2048 + +#endif /* EMACS */ + +/* + * S y s t e m D e p e n d e n t + * D e f i n i t i o n s f o r C P P + * + * Definitions in this file may be edited to configure CPP for particular + * host operating systems and target configurations. + * + * NOTE: cpp assumes it is compiled by a compiler that supports macros + * with arguments. If this is not the case (as for Decus C), #define + * nomacarg -- and provide function equivalents for all macros. + * + * cpp also assumes the host and target implement the Ascii character set. + * If this is not the case, you will have to do some editing here and there. + */ + +/* + * This redundant definition of TRUE and FALSE works around + * a limitation of Decus C. + */ +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +/* + * Define the HOST operating system. This is needed so that + * cpp can use appropriate filename conventions. + */ +#define SYS_UNKNOWN 0 +#define SYS_UNIX 1 +#define SYS_VMS 2 +#define SYS_RSX 3 +#define SYS_RT11 4 +#define SYS_LATTICE 5 +#define SYS_ONYX 6 +#define SYS_68000 7 +#define SYS_AMIGADOS 8 + +#ifndef HOST +#ifdef unix +#define HOST SYS_UNIX +#else +#ifdef amiga +#define HOST SYS_AMIGADOS +#endif +#endif +#endif + +/* + * We assume that the target is the same as the host system + */ +#ifndef TARGET +#define TARGET HOST +#endif + +/* + * In order to predefine machine-dependent constants, + * several strings are defined here: + * + * MACHINE defines the target cpu (by name) + * SYSTEM defines the target operating system + * COMPILER defines the target compiler + * + * The above may be #defined as "" if they are not wanted. + * They should not be #defined as NULL. + * + * LINE_PREFIX defines the # output line prefix, if not "line" + * This should be defined as "" if cpp is to replace + * the "standard" C pre-processor. + */ +#define LINE_PREFIX "line" +/* + * FILE_LOCAL marks functions which are referenced only in the + * file they reside. Some C compilers allow these + * to be marked "static" even though they are referenced + * by "extern" statements elsewhere. + * + * OK_DOLLAR Should be set TRUE if $ is a valid alphabetic character + * in identifiers (default), or zero if $ is invalid. + * Default is TRUE. + * + * OK_CONCAT Should be set TRUE if # may be used to concatenate + * tokens in macros (per the Ansi Draft Standard) or + * FALSE for old-style # processing (needed if cpp is + * to process assembler source code). + */ +#define OK_CONCAT TRUE +/* + * OK_DATE Predefines the compilation date if set TRUE. + * Not permitted by the Nov. 12, 1984 Draft Standard. + */ +#define OK_DATE TRUE +/* + * + * OK_SIZEOF Permits sizeof in #if preprocessor expressions. + * According to K&R V2 (page 232), this is not allowed. + */ +#define OK_SIZEOF TRUE +/* + * S_CHAR etc. Define the sizeof the basic TARGET machine word types. + * By default, sizes are set to the values for the HOST + * computer. If this is inappropriate, see the code in + * cpp3.c for details on what to change. Also, if you + * have a machine where sizeof (signed int) differs from + * sizeof (unsigned int), you will have to edit code and + * tables in cpp3.c (and extend the -S option definition.) + * + * CPP_LIBRARY May be defined if you have a site-specific include directory + * which is to be searched *before* the operating-system + * specific directories. + */ + +#define MACHINE "amiga", "m68000" +#define SYSTEM "amigados" + + +/* + * defaults + */ + +#ifndef MSG_PREFIX +#define MSG_PREFIX "cpp: " +#endif + +/* + * OLD_PREPROCESSOR forces the definition of OK_DOLLAR, OK_CONCAT, + * COMMENT_INVISIBLE to values appropriate for + * an old-style preprocessor. + */ + +#if OLD_PREPROCESSOR +#define OK_DOLLAR FALSE +#define OK_CONCAT FALSE +#define COMMENT_INVISIBLE TRUE +#endif + +/* + * RECURSION_LIMIT may be set to -1 to disable the macro recursion test. + */ +#ifndef RECURSION_LIMIT +#define RECURSION_LIMIT 1000 +#endif + +/* + * BITS_CHAR may be defined to set the number of bits per character. + * it is needed only for multi-byte character constants. + */ +#ifndef BITS_CHAR +#define BITS_CHAR 8 +#endif + +/* + * BIG_ENDIAN is set TRUE on machines (such as the IBM 360 series) + * where 'ab' stores 'a' in the high-bits and 'b' in the low-bits. + * It is set FALSE on machines (such as the PDP-11 and Vax-11) + * where 'ab' stores 'a' in the low-bits and 'b' in the high-bits. + * (Or is it the other way around?) -- Warning: BIG_ENDIAN code is untested. + * [I *seems* to be the other way around, according to the code /OIS] + */ +#ifndef BIG_ENDIAN +#define BIG_ENDIAN FALSE +#endif + +/* + * COMMENT_INVISIBLE may be defined to allow "old-style" comment + * processing, whereby the comment becomes a zero-length token + * delimiter. This permitted tokens to be concatenated in macro + * expansions. This was removed from the Draft Ansi Standard. + */ +#ifndef COMMENT_INVISIBLE +#define COMMENT_INVISIBLE FALSE +#endif + +/* + * OK_DOLLAR enables use of $ as a valid "letter" in identifiers. + * This is a permitted extension to the Ansi Standard and is required + * for e.g., VMS, RSX-11M, etc. It should be set FALSE if cpp is + * used to preprocess assembler source on Unix systems. OLD_PREPROCESSOR + * sets OK_DOLLAR FALSE for that reason. + */ +#ifndef OK_DOLLAR +#define OK_DOLLAR TRUE +#endif + +/* + * OK_CONCAT enables (one possible implementation of) token concatenation. + * If cpp is used to preprocess Unix assembler source, this should be + * set FALSE as the concatenation character, #, is used by the assembler. + */ +#ifndef OK_CONCAT +#define OK_CONCAT TRUE +#endif + +/* + * OK_DATE may be enabled to predefine today's date as a string + * at the start of each compilation. This is apparently not permitted + * by the Draft Ansi Standard. + */ +#ifndef OK_DATE +#define OK_DATE TRUE +#endif + +/* + * OK_SIZEOF may be defined to allow sizeof(type) in #if expressions. + * Actually, it is none of the preprocessors business how large these + * things are, as they might be different with different compiler + * options. Also, according to K&R V2, page 232, it is nonstandard. + * This option was added in the PDC process, under no. *OIS*0.92*. + */ +#ifndef OK_SIZEOF +#define OK_SIZEOF FALSE +#endif + +/* + * Some common definitions. + */ + +#ifndef DEBUG +#define DEBUG FALSE +#endif + +/* + * The following definitions are used to allocate memory for + * work buffers. In general, they should not be modified + * by implementors. + * + * PAR_MAC The maximum number of #define parameters (31 per Standard) + * Note: we need another one for strings. + * NBUFF Input buffer size + * NWORK Work buffer size -- the longest macro + * must fit here after expansion. + * NEXP The nesting depth of #if expressions + * NINCLUDE The number of directories that may be specified + * on a per-system basis, or by the -I option. + * BLK_NEST The number of nested #if's permitted. + */ + +#ifndef PAR_MAC +#define PAR_MAC (31 + 1) +#endif + +#ifndef NBUFF +#define NBUFF 512 +#endif + +#ifndef NWORK +#define NWORK 512 +#endif + +#ifndef NEXP +#define NEXP 128 +#endif + +#ifndef NINCLUDE +#define NINCLUDE 20 +#endif + +#ifndef NPARMWORK +#define NPARMWORK (NWORK * 2) +#endif + +#ifndef BLK_NEST +#define BLK_NEST 32 +#endif + + +/* + * Some special constants. These may need to be changed if cpp + * is ported to a wierd machine. + * + * NOTE: if cpp is run on a non-ascii machine, ALERT and VT may + * need to be changed. They are used to implement the proposed + * ANSI standard C control characters '\a' and '\v' only. + * DEL is used to tag macro tokens to prevent #define foo foo + * from looping. Note that we don't try to prevent more elaborate + * #define loops from occurring. + */ + +#ifndef ALERT +#define ALERT '\007' /* '\a' is "Bell" */ +#endif + +#ifndef VT +#define VT '\013' /* Vertical Tab CTRL/K */ +#endif + +/* + * Functions can be declared/defined static to only become in the + * scope for functions of the same source file. + */ + +#ifndef FILE_LOCAL +#define FILE_LOCAL static /* file-unique globals */ +#endif + +/* + * For compilers supporting inlining, the INLINE macro has been added to + * functions called from only one place. There might still be some + * functions that should have this macro. + */ +#ifdef AMIGA +#define INLINE __inline /* Amiga compiler SAS/C 6.x supports this! */ +#else +#define INLINE /* don't support that kind of stuff */ +#endif + +#if defined(AMIGA) && defined(SHARED) +#define PREFIX __asm __saveds +#define REG(x) register __ ## x +#else +#define PREFIX +#define REG(x) +#endif + +/* + * SBSIZE defines the number of hash-table slots for the symbol table. + */ +#ifndef SBSIZE +#define SBSIZE 64 +#endif + +#define VERSION_TEXT "Frexx C Preprocessor v1.5.1 " \ +"Copyright (C) by FrexxWare 1993 - 2002.\n" \ +"Compiled " __DATE__ "\n" diff --git a/fpp.exp b/fpp.exp new file mode 100644 index 0000000..c004e42 --- /dev/null +++ b/fpp.exp @@ -0,0 +1,2 @@ +#! +fppPreProcess diff --git a/fpp.fd b/fpp.fd new file mode 100644 index 0000000..db0ac52 --- /dev/null +++ b/fpp.fd @@ -0,0 +1,4 @@ +##base _FPPBase +##bias 30 +fppPreProcess(a)(A0) +##end diff --git a/fpp.h b/fpp.h new file mode 100644 index 0000000..f772996 --- /dev/null +++ b/fpp.h @@ -0,0 +1,159 @@ +/****************************************************************************** + * FREXXWARE + * ---------------------------------------------------------------------------- + * + * Project: Frexx C Preprocessor + * $Source: /home/user/start/cpp/RCS/fpp.h,v $ + * $Revision: 1.5 $ + * $Date: 1994/01/24 09:38:45 $ + * $Author: start $ + * $State: Exp $ + * $Locker: start $ + * + * ---------------------------------------------------------------------------- + * $Log: fpp.h,v $ + * Revision 1.5 1994/01/24 09:38:45 start + * Added FPPTAG_RIGHTCONCAT. + * + * Revision 1.4 1993/12/06 13:51:20 start + * A lot of new stuff (too much to mention) + * + * Revision 1.3 1993/11/29 14:01:13 start + * New features added + * + * Revision 1.2 1993/11/11 07:16:39 start + * New stuff + * + * Revision 1.1 1993/11/03 09:15:59 start + * Initial revision + * + * + *****************************************************************************/ +/********************************************************************** + * + * fpp.h + * + */ + + +struct fppTag { + int tag; + void *data; +}; + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#define NFLAG_BUILTIN 1 +#define NFLAG_PREDEFINE 2 + +/* end of taglist: */ +#define FPPTAG_END 0 + +/* To make the preprocessed output keep the comments: */ +#define FPPTAG_KEEPCOMMENTS 1 /* data is TRUE or FALSE */ + +/* To define symbols to the preprocessor: */ +#define FPPTAG_DEFINE 2 /* data is the string "symbol" or "symbol=" */ + +/* To make the preprocessor ignore all non-fatal errors: */ +#define FPPTAG_IGNORE_NONFATAL 3 /* data is TRUE or FALSE */ + +/* To add an include directory to the include directory list: */ +#define FPPTAG_INCLUDE_DIR 4 /* data is directory name ending with a '/' (on + amiga a ':' is also valid) */ + +/* To define all machine specific built-in #defines, default is TRUE: */ +#define FPPTAG_BUILTINS 5 /* data is TRUE or FALSE */ + +/* To define predefines like __LINE__, __DATE__, etc. default is TRUE: */ +#define FPPTAG_PREDEFINES 6 /* data is TRUE or FALSE */ + +/* To make fpp leave C++ comments in the output: */ +#define FPPTAG_IGNORE_CPLUSPLUS 7 /* data is TRUE or FALSE */ + +/* To define new sizes to #if sizeof: */ +#define FPPTAG_SIZEOF_TABLE 8 /* data is sizeof table string */ + +/* To undefine symbols: */ +#define FPPTAG_UNDEFINE 9 /* data is symbol name */ + +/* Output all #defines: */ +#define FPPTAG_OUTPUT_DEFINES 10 /* data is TRUE or FALSE */ + +/* Initial input file name: */ +#define FPPTAG_INPUT_NAME 11 /* data is string */ + +/* Input function: */ +#define FPPTAG_INPUT 12 /* data is an input funtion */ + +/* Output function: */ +#define FPPTAG_OUTPUT 13 /* data is an output function */ + +/* User data, sent in the last argument to the input function: */ +#define FPPTAG_USERDATA 14 /* data is user data */ + +/* Whether to exclude #line instructions in the output, default is FALSE */ +#define FPPTAG_LINE 15 /* data is TRUE or FALSE */ + +/* Error function. This is called when FPP finds any warning/error/fatal: */ +#define FPPTAG_ERROR 16 /* data is function pointer to a + "void (*)(void *, char *, va_list)" */ + +/* Whether to warn for illegal cpp instructions */ +#define FPPTAG_WARNILLEGALCPP 17 /* data is boolean, default is FALSE */ + +/* Output the 'line' keyword on #line-lines? */ +#define FPPTAG_OUTPUTLINE 18 /* data is boolean, default is TRUE */ + +/* Do not output the version information string */ +#define FPPTAG_IGNOREVERSION 19 /* data is boolean, default is FALSE */ + +/* Output all included file names to stderr */ +#define FPPTAG_OUTPUTINCLUDES 20 /* data is boolean, default is FALSE */ + +/* Display warning if there is any brace, bracket or parentheses unbalance */ +#define FPPTAG_OUTPUTBALANCE 21 /* data is boolean, default is FALSE */ + +/* Display all whitespaces in the source */ +#define FPPTAG_OUTPUTSPACE 22 /* data is boolean, default is FALSE */ + +/* Allow nested comments */ +#define FPPTAG_NESTED_COMMENTS 23 /* data is boolean, default is FALSE */ + +/* Enable warnings at nested comments */ +#define FPPTAG_WARN_NESTED_COMMENTS 24 /* data is boolean, default is FALSE */ + +/* Enable warnings at missing includes */ +#define FPPTAG_WARNMISSINCLUDE 25 /* data is boolean, default is TRUE */ + +/* Output the main file */ +#define FPPTAG_OUTPUTMAIN 26 /* data is boolean, default is TRUE */ + +/* Include file */ +#define FPPTAG_INCLUDE_FILE 27 /* data is char pointer */ + +/* Include macro file */ +#define FPPTAG_INCLUDE_MACRO_FILE 28 /* data is char pointer */ + +/* Evaluate the right part of a concatenate before the concat */ +#define FPPTAG_RIGHTCONCAT 29 /* data is boolean, default is FALSE */ + +/* Include the specified file at the beginning of each function */ +#define FPPTAG_INITFUNC 30 /* data is char pointer or NULL */ + +/* Define function to be excluded from the "beginning-function-addings" */ +#define FPPTAG_EXCLFUNC 31 /* data is char pointer */ + +/* Enable output of all function names defined in the source */ +#define FPPTAG_DISPLAYFUNCTIONS 32 + +/* Switch on WWW-mode */ +#define FPPTAG_WEBMODE 33 + +int PREFIX fppPreProcess(REG(a0) struct fppTag *); diff --git a/fpp_pragmas.h b/fpp_pragmas.h new file mode 100644 index 0000000..15f2f0f --- /dev/null +++ b/fpp_pragmas.h @@ -0,0 +1,20 @@ +#ifdef RCS +static char rcsid[]="$Id$"; +#endif +/****************************************************************************** + * FREXXWARE + * ---------------------------------------------------------------------------- + * + * Project: Frexx C Preprocessor + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ---------------------------------------------------------------------------- + * $Log$ + * + *****************************************************************************/ +#pragma libcall FPPBase fppPreProcess 1E 801 diff --git a/makefile b/makefile new file mode 100644 index 0000000..b3bde52 --- /dev/null +++ b/makefile @@ -0,0 +1,86 @@ +############################################################################## +## FREXXWARE +############################################################################## +## +## Project: Frexx C Preprocessor +## $Source: /home/user/start/cpp/RCS/makefile,v $ +## $Revision: 1.3 $ +## $Date: 1994/06/02 09:11:24 $ +## $Author: start $ +## $State: Exp $ +## $Locker: $ +## +############################################################################## +## $Log: makefile,v $ +# Revision 1.3 1994/06/02 09:11:24 start +# Now uses 'gcc' and -O! +# +# Revision 1.2 1993/11/11 07:16:39 start +# New stuff +# +# Revision 1.1 1993/11/03 09:19:28 start +# Initial revision +# +## +############################################################################## + +# Frexx PreProcessor Makefile + +#HOST =-tp -B/home/danne/code/cpp/ -Wp\,-Q\,-Dunix\,-Ddpc\,-DAIX +#DEFINES = -Dunix -Dpdc -DAIX -DUNIX -DDEBUG +DEFINES = -Dunix -Dpdc -DUNIX -DDEBUG -DRCS +DEBUGFLAG = -g +LD = ld +LDFLAGS = +LIB = libfpp.a +CPP = fpp +FILECPP = fcpp +TEMP = templib.o +EXPORT = fpp.exp +CC = gcc +CFLAGS = $(DEBUGFLAG) $(DEFINES) +AR = ar +ARFLAGS = rv +.SUFFIXES: .o .c .c~ .h .h~ .a .i +OBJS = cpp1.o cpp2.o cpp3.o cpp4.o cpp5.o cpp6.o memory.o +FILEOBJS = cpp1.o cpp2.o cpp3.o cpp4.o cpp5.o cpp6.o memory.o usecpp.o + +# ** compile cpp +# + +#all: $(LIB) $(CPP) +all: $(FILECPP) + +$(LIB) : $(OBJS) $(EXPORT) + $(LD) $(OBJS) -o $(TEMP) -bE:$(EXPORT) -bM:SRE -T512 -H512 -lc + rm -f $(LIB) + $(AR) $(ARFLAGS) $(LIB) $(TEMP) + rm $(TEMP) + +$(CPP) : usecpp.c + $(CC) $(CFLAGS) -o $(CPP) usecpp.c -L. -lfpp + +$(FILECPP) : $(FILEOBJS) + $(CC) $(FILEOBJS) -o $(FILECPP) + +.c.o: + $(CC) $(CFLAGS) -c $< + +cpp1.o:cpp1.c +cpp2.o:cpp2.c +cpp3.o:cpp3.c +cpp4.o:cpp4.c +cpp5.o:cpp5.c +cpp6.o:cpp6.c +memory.o:memory.c + +usecpp.o:usecpp.c + +clean : + rm -f *.o $(FILECPP) + +tgz: + rm -f makefile*~ + (dir=`pwd`;name=`basename $$dir`;echo Creates $$name.tar.gz; cd .. ; \ + tar -cf $$name.tar `ls $$name/*.[ch] $$name/*.exp $$name/*.fd $$name/makefile*` ; \ + gzip $$name.tar ; chmod a+r $$name.tar.gz ; mv $$name.tar.gz $$name/) diff --git a/makefile.aix b/makefile.aix new file mode 100644 index 0000000..8c75691 --- /dev/null +++ b/makefile.aix @@ -0,0 +1,43 @@ +# Frexx PreProcessor library Makefile + +#HOST =-tp -B/home/danne/code/cpp/ -Wp\,-Q\,-Dunix\,-Ddpc\,-DAIX +DEFINES = -Dunix -Dpdc -DAIX -DUNIX -DDEBUG +DEBUGFLAG = -g +LD = ld +LDFLAGS = +LIB = libfpp.a +CPP = cpp +TEMP = templib.o +EXPORT = fpp.exp +CC = xlc +CFLAGS = $(DEBUGFLAG) $(DEFINES) +AR = ar +ARFLAGS = rv +.SUFFIXES: .o .c .c~ .h .h~ .a .i +OBJS = cpp1.o cpp2.o cpp3.o cpp4.o cpp5.o cpp6.o memory.o + +# ** compile cpp +# + +all: $(LIB) $(CPP) + + +$(LIB) : $(OBJS) $(EXPORT) + $(LD) $(OBJS) -o $(TEMP) -bE:$(EXPORT) -bM:SRE -T512 -H512 -lc + rm -f $(LIB) + $(AR) $(ARFLAGS) $(LIB) $(TEMP) + rm $(TEMP) + +$(CPP) : usecpp.c + $(CC) $(CFLAGS) -o $(CPP) usecpp.c -L. -lfpp + +.c.o: + $(CC) $(CFLAGS) -c $< + +cpp1.o:cpp1.c +cpp2.o:cpp2.c +cpp3.o:cpp3.c +cpp4.o:cpp4.c +cpp5.o:cpp5.c +cpp6.o:cpp6.c +memory.o:memory.c \ No newline at end of file diff --git a/makefile.bsd b/makefile.bsd new file mode 100644 index 0000000..a0a5760 --- /dev/null +++ b/makefile.bsd @@ -0,0 +1,77 @@ +############################################################################## +## FREXXWARE +############################################################################## +## +## Project: Frexx C Preprocessor +## $Source: /home/user/start/cpp/RCS/makefile,v $ +## $Revision: 1.3 $ +## $Date: 1994/06/02 09:11:24 $ +## $Author: start $ +## $State: Exp $ +## $Locker: $ +## +############################################################################## +## $Log: makefile,v $ +# Revision 1.3 1994/06/02 09:11:24 start +# Now uses 'gcc' and -O! +# +# Revision 1.2 1993/11/11 07:16:39 start +# New stuff +# +# Revision 1.1 1993/11/03 09:19:28 start +# Initial revision +# +## +############################################################################## + +# Frexx PreProcessor Makefile + +#HOST =-tp -B/home/danne/code/cpp/ -Wp\,-Q\,-Dunix\,-Ddpc\,-DAIX +#DEFINES = -Dunix -Dpdc -DAIX -DUNIX -DDEBUG +DEFINES = -Dunix -Dpdc -DUNIX -DDEBUG -DRCS -DBSD +DEBUGFLAG = -O +LD = ld +LDFLAGS = +LIB = libfpp.a +CPP = fpp +FILECPP = cpp +TEMP = templib.o +EXPORT = fpp.exp +CC = gcc +CFLAGS = $(DEBUGFLAG) $(DEFINES) +AR = ar +ARFLAGS = rv +.SUFFIXES: .o .c .c~ .h .h~ .a .i +OBJS = cpp1.o cpp2.o cpp3.o cpp4.o cpp5.o cpp6.o memory.o +FILEOBJS = cpp1.o cpp2.o cpp3.o cpp4.o cpp5.o cpp6.o memory.o usecpp.o + +# ** compile cpp +# + +#all: $(LIB) $(CPP) +all: $(FILECPP) + +$(LIB) : $(OBJS) $(EXPORT) + $(LD) $(OBJS) -o $(TEMP) -bE:$(EXPORT) -bM:SRE -T512 -H512 -lc + rm -f $(LIB) + $(AR) $(ARFLAGS) $(LIB) $(TEMP) + rm $(TEMP) + +$(CPP) : usecpp.c + $(CC) $(CFLAGS) -o $(CPP) usecpp.c -L. -lfpp + +$(FILECPP) : $(FILEOBJS) + $(CC) $(FILEOBJS) -o $(FILECPP) + +.c.o: + $(CC) $(CFLAGS) -c $< + +cpp1.o:cpp1.c +cpp2.o:cpp2.c +cpp3.o:cpp3.c +cpp4.o:cpp4.c +cpp5.o:cpp5.c +cpp6.o:cpp6.c +memory.o:memory.c + +usecpp.o:usecpp.c \ No newline at end of file diff --git a/makefile.dell b/makefile.dell new file mode 100644 index 0000000..e1ba159 --- /dev/null +++ b/makefile.dell @@ -0,0 +1,72 @@ +############################################################################## +## FREXXWARE +############################################################################## +## +## Project: Frexx C Preprocessor +## $Source: /home/user/start/cpp/RCS/makefile,v $ +## $Revision: 1.1 $ +## $Date: 1993/11/03 09:19:28 $ +## $Author: start $ +## $State: Exp $ +## $Locker: start $ +## +############################################################################## +## $Log: makefile,v $ +# Revision 1.1 1993/11/03 09:19:28 start +# Initial revision +# +## +############################################################################## + +# Frexx PreProcessor Makefile + +#HOST =-tp -B/home/danne/code/cpp/ -Wp\,-Q\,-Dunix\,-Ddpc\,-DAIX +#DEFINES = -Dunix -Dpdc -DAIX -DUNIX -DDEBUG +DEFINES = -Dunix -Dpdc -DUNIX -DDEBUG -DRCS +DEBUGFLAG = -O -Xa +LD = ld +LDFLAGS = +LIB = libfpp.a +CPP = fpp +FILECPP = cpp +TEMP = templib.o +EXPORT = fpp.exp +#CC = xlc +CC = cc +CFLAGS = $(DEBUGFLAG) $(DEFINES) +AR = ar +ARFLAGS = rv +.SUFFIXES: .o .c .c~ .h .h~ .a .i +OBJS = cpp1.o cpp2.o cpp3.o cpp4.o cpp5.o cpp6.o memory.o +FILEOBJS = cpp1.o cpp2.o cpp3.o cpp4.o cpp5.o cpp6.o memory.o usecpp.o + +# ** compile cpp +# + +#all: $(LIB) $(CPP) +all: $(FILECPP) + +$(LIB) : $(OBJS) $(EXPORT) + $(LD) $(OBJS) -o $(TEMP) -bE:$(EXPORT) -bM:SRE -T512 -H512 -lc + rm -f $(LIB) + $(AR) $(ARFLAGS) $(LIB) $(TEMP) + rm $(TEMP) + +$(CPP) : usecpp.c + $(CC) $(CFLAGS) -o $(CPP) usecpp.c -L. -lfpp + +$(FILECPP) : $(FILEOBJS) + $(CC) $(FILEOBJS) -o $(FILECPP) + +.c.o: + $(CC) $(CFLAGS) -c $< + +cpp1.o:cpp1.c +cpp2.o:cpp2.c +cpp3.o:cpp3.c +cpp4.o:cpp4.c +cpp5.o:cpp5.c +cpp6.o:cpp6.c +memory.o:memory.c + +usecpp.o:usecpp.c \ No newline at end of file diff --git a/makefile.gcc b/makefile.gcc new file mode 100644 index 0000000..9b53daa --- /dev/null +++ b/makefile.gcc @@ -0,0 +1,80 @@ +############################################################################## +## FREXXWARE +############################################################################## +## +## Project: Frexx C Preprocessor +## $Source: /home/user/start/cpp/RCS/makefile.gcc,v $ +## $Revision: 1.1 $ +## $Date: 1993/12/06 13:51:20 $ +## $Author: start $ +## $State: Exp $ +## $Locker: $ +## +############################################################################## +## $Log: makefile.gcc,v $ +# Revision 1.1 1993/12/06 13:51:20 start +# Initial revision +# +# Revision 1.1 1993/12/06 13:51:20 start +# Initial revision +# +# Revision 1.2 1993/11/11 07:16:39 start +# New stuff +# +# Revision 1.1 1993/11/03 09:19:28 start +# Initial revision +# +## +############################################################################## + +# Frexx PreProcessor Makefile + +#HOST =-tp -B/home/danne/code/cpp/ -Wp\,-Q\,-Dunix\,-Ddpc\,-DAIX +#DEFINES = -Dunix -Dpdc -DAIX -DUNIX -DDEBUG +DEFINES = -Dunix -Dpdc -DUNIX -DRCS +DEBUGFLAG = -O +LD = ld +LDFLAGS = +LIB = libfpp.a +CPP = fpp +FILECPP = cpp +TEMP = templib.o +EXPORT = fpp.exp +CC = gcc +CFLAGS = $(DEBUGFLAG) $(DEFINES) +AR = ar +ARFLAGS = rv +.SUFFIXES: .o .c .c~ .h .h~ .a .i +OBJS = cpp1.o cpp2.o cpp3.o cpp4.o cpp5.o cpp6.o memory.o +FILEOBJS = cpp1.o cpp2.o cpp3.o cpp4.o cpp5.o cpp6.o memory.o usecpp.o + +# ** compile cpp +# + +#all: $(LIB) $(CPP) +all: $(FILECPP) + +$(LIB) : $(OBJS) $(EXPORT) + $(LD) $(OBJS) -o $(TEMP) -bE:$(EXPORT) -bM:SRE -T512 -H512 -lc + rm -f $(LIB) + $(AR) $(ARFLAGS) $(LIB) $(TEMP) + rm $(TEMP) + +$(CPP) : usecpp.c + $(CC) $(CFLAGS) -o $(CPP) usecpp.c -L. -lfpp + +$(FILECPP) : $(FILEOBJS) + $(CC) $(FILEOBJS) -o $(FILECPP) + +.c.o: + $(CC) $(CFLAGS) -c $< + +cpp1.o:cpp1.c +cpp2.o:cpp2.c +cpp3.o:cpp3.c +cpp4.o:cpp4.c +cpp5.o:cpp5.c +cpp6.o:cpp6.c +memory.o:memory.c + +usecpp.o:usecpp.c \ No newline at end of file diff --git a/makefile.os9 b/makefile.os9 new file mode 100644 index 0000000..71f11f1 --- /dev/null +++ b/makefile.os9 @@ -0,0 +1,58 @@ +############################################################################## +## FREXXWARE +############################################################################## +## +## Project: Frexx C Preprocessor +## $Source: /home/user/start/cpp/RCS/makefile.os9,v $ +## $Revision: 1.1 $ +## $Date: 1993/12/06 13:51:20 $ +## $Author: start $ +## $State: Exp $ +## $Locker: start $ +## +############################################################################## +## $Log: makefile.os9,v $ +# Revision 1.1 1993/12/06 13:51:20 start +# Initial revision +# +# Revision 1.1 1993/11/03 09:19:28 start +# Initial revision +# +## +############################################################################## + +# Frexx PreProcessor Makefile + +#HOST =-tp -B/home/danne/code/cpp/ -Wp\,-Q\,-Dunix\,-Ddpc\,-DAIX +#DEFINES = -Dunix -Dpdc -DAIX -DUNIX -DDEBUG +DEFINES = -Dunix -Dpdc -DOS9 -DUNIX -DDEBUG -DRCS +DEBUGFLAG = -g -td=/r0 +LD = ld +LDFLAGS = -g +FILECPP = cpp +CC = cc +LIBDIR = /h0/ultra/lib +CFLAGS = $(DEBUGFLAG) $(DEFINES) +AR = ar +ARFLAGS = rv +#.SUFFIXES: .o .c .c~ .h .h~ .a .i +OBJS = cpp1.o cpp2.o cpp3.o cpp4.o cpp5.o cpp6.o memory.o +FILEOBJS = cpp1.r cpp2.r cpp3.r cpp4.r cpp5.r cpp6.r memory.r usecpp.r + +# ** compile cpp +# + +#all: $(LIB) $(CPP) +#all: $(FILECPP) + +$(FILECPP) : $(FILEOBJS) + $(CC) -g $(FILEOBJS) -l=$(LIBDIR)/sys_clib.l -fd=$(FILECPP) + +cpp1.r:cpp1.c +cpp2.r:cpp2.c +cpp3.r:cpp3.c +cpp4.r:cpp4.c +cpp5.r:cpp5.c +cpp6.r:cpp6.c +memory.r:memory.c + diff --git a/memory.c b/memory.c new file mode 100644 index 0000000..2375e0b --- /dev/null +++ b/memory.c @@ -0,0 +1,220 @@ +#ifdef RCS +static char rcsid[]="$Id: memory.c,v 1.2 1994/01/24 09:36:46 start Exp $"; +#endif +/****************************************************************************** +Copyright (c) 1999 Daniel Stenberg + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE +SOFTWARE. +******************************************************************************/ +/****************************************************************************** + * FREXXWARE + * ---------------------------------------------------------------------------- + * + * Project: Frexx C Preprocessor + * $Source: /home/user/start/cpp/RCS/memory.c,v $ + * $Revision: 1.2 $ + * $Date: 1994/01/24 09:36:46 $ + * $Author: start $ + * $State: Exp $ + * $Locker: $ + * + * ---------------------------------------------------------------------------- + * $Log: memory.c,v $ + * Revision 1.2 1994/01/24 09:36:46 start + * Made it run with OS9 properly. + * + * Revision 1.1 1993/11/03 09:13:08 start + * Initial revision + * + * + *****************************************************************************/ + +#include +#include +#if defined(OS9) +#include +#elif defined(UNIX) +#include +#elif defined(AMIGA) +#include +#include +#endif + +#include + +#include "memory.h" +#ifdef DEBUG +int mem; +int maxmem; +int malloc_count=0; +#endif + +/* + * We have two mallockey pointers because we have two different kinds of + * Malloc()s! One for each execution and one for each fplInit(). + */ +static struct MemInfo *MallocKey=NULL; + +void *Realloc(void *ptr, int size) +{ + struct MemInfo *point; + void *new; + /* `point' points to the MemInfo structure: */ + point=(struct MemInfo *)((char *)ptr-sizeof(struct MemInfo)); + + if(size<=point->size) + /* + * To increase performance, don't care about reallocing + * to smaller sizes! + */ + return(ptr); + new=Malloc(size); /* allocate new storage */ + if(!new) + return(NULL); /* fail! */ + + memcpy(new, ptr, point->size); /* copy contents */ + + Free(ptr); /* free old area */ + + return(new); /* return new pointer */ +} + + +void *Malloc(int size) +{ + char *alloc; + struct MemInfo *point; + +#ifdef DEBUG + size+=MEMORY_COOKIE; /* add extra bytes after the block! */ +#endif + +#ifdef AMIGA + alloc=(char *)AllocMem(size+sizeof(struct MemInfo), 0L); +#elif defined(UNIX) + alloc=(char *)malloc(size+sizeof(struct MemInfo)); +#endif + + if(!alloc) + return(NULL); + + point=(struct MemInfo *)alloc; + point->prev=MallocKey; /* previous */ + point->next=NULL; /* next */ + point->size=size; /* size */ +#ifdef DEBUG + malloc_count++; + mem+=size+sizeof(struct MemInfo); + if(mem>maxmem) + maxmem=mem; + + memset((void *)((char *)point+sizeof(struct MemInfo)), 0xbb, size); +#endif + if(MallocKey) + point->prev->next=point; + + MallocKey = (void *)point; + + alloc = ((char *)point+sizeof(struct MemInfo)); + return ((void *)alloc); +} + +void Free(void *ptr) +{ + struct MemInfo *point; + /* `point' points to the MemInfo structure: */ + point=(struct MemInfo *)((char *)ptr-sizeof(struct MemInfo)); + + if(MallocKey==point) { + /* if this is the last Malloc, set `last' to `prev' */ + MallocKey=point->prev; + if(MallocKey) + MallocKey->next=NULL; + } else { + /* point the previous' `next' to our `next', and our next `previous' + to our `previous'. Unlink us from the chain */ + if(point->prev) + /* only if we aren't the _first_ Malloc() ! */ + point->prev->next=point->next; + if(point->next) + /* only if there is a next! */ + point->next->prev=point->prev; + } +#ifdef DEBUG + mem-=point->size+sizeof(struct MemInfo); + + CheckMem(ptr); +#endif + +#ifdef AMIGA + FreeMem(point, point->size+sizeof(struct MemInfo)); +#elif UNIX + free(point); +#endif +} + +#ifdef DEBUG +void CheckMem(void *ptr) +{ + int i; + int b=0; + struct MemInfo *point; + /* `point' points to the MemInfo structure: */ + point=(struct MemInfo *)((char *)ptr-sizeof(struct MemInfo)); + for(i=0;isize-MEMORY_COOKIE)!= 0xbb) + b++; + + if(b) { +#if defined(UNIX) + fprintf(stderr, "Memory violation: malloc(%d) was abused %d bytes!\n", + point->size-MEMORY_COOKIE-sizeof(struct MemInfo), b); +#elif defined(AMIGA) + /* ERROR */; +#endif + } +} +#endif + +void FreeAll(void) +{ + struct MemInfo *point; + void *prev; + + if(!MallocKey) + return; + do { + point=MallocKey; + /* `point' points to the MemInfo structure! */ + + prev=(void *)point->prev; + +#ifdef DEBUG + mem-=point->size+sizeof(struct MemInfo); +#endif +#ifdef AMIGA + FreeMem(MallocKey, point->size+sizeof(struct MemInfo)); +#elif UNIX + free((char *)MallocKey); +#endif + } while(MallocKey=prev); +} diff --git a/memory.h b/memory.h new file mode 100644 index 0000000..e3b68cc --- /dev/null +++ b/memory.h @@ -0,0 +1,58 @@ +/****************************************************************************** + * FREXXWARE + * ---------------------------------------------------------------------------- + * + * Project: Frexx C Preprocessor + * $Source: /home/user/start/cpp/RCS/memory.h,v $ + * $Revision: 1.3 $ + * $Date: 1993/12/06 13:51:20 $ + * $Author: start $ + * $State: Exp $ + * $Locker: start $ + * + * ---------------------------------------------------------------------------- + * $Log: memory.h,v $ + * Revision 1.3 1993/12/06 13:51:20 start + * A lot of new stuff (too much to mention) + * + * Revision 1.2 1993/11/11 07:16:39 start + * New stuff + * + * Revision 1.2 1993/11/11 07:16:39 start + * New stuff + * + * Revision 1.1 1993/11/03 09:15:59 start + * Initial revision + * + * + *****************************************************************************/ +/****************************************************************************** + + memory.h + + Structures and defines for memory functions. + + *****************************************************************************/ + +typedef struct MemInfo { + struct MemInfo *prev; + struct MemInfo *next; + int size; +} MemInfo; + +void Free(void *); +void FreeAll(void); +void *Malloc(int); +void *Realloc(void *, int); +#ifdef DEBUG +void CheckMem(void *); +#endif + +#ifdef DEBUG +#define MEMORY_COOKIE 0 /* When using the DEBUG option, all Malloc() + will allocate a number of extra bytes at + the end of the block. These will be checked + to be intact when the block is freed or + CheckMem()'ed. This #define tells the size + of that block! */ +#endif diff --git a/usecpp.c b/usecpp.c new file mode 100644 index 0000000..01b2020 --- /dev/null +++ b/usecpp.c @@ -0,0 +1,608 @@ +#ifdef RCS +static char rcsid[]="$Id: usecpp.c,v 1.6 1994/06/02 09:11:01 start Exp start $"; +#endif +/****************************************************************************** +Copyright (c) 1999 Daniel Stenberg + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE +SOFTWARE. +******************************************************************************/ +/****************************************************************************** + * FREXXWARE + * ---------------------------------------------------------------------------- + * + * Project: Frexx C Preprocessor + * $Source: /home/user/start/cpp/RCS/usecpp.c,v $ + * $Revision: 1.6 $ + * $Date: 1994/06/02 09:11:01 $ + * $Author: start $ + * $State: Exp $ + * $Locker: start $ + * + * ---------------------------------------------------------------------------- + * $Log: usecpp.c,v $ + * Revision 1.6 1994/06/02 09:11:01 start + * Added the '-n' option! + * + * Revision 1.5 1994/06/02 08:51:49 start + * Added three more command line parameters + * Made -h invokes exit nice + * + * Revision 1.4 1994/01/24 09:37:17 start + * Major difference. + * + * Revision 1.3 1993/12/06 13:51:20 start + * A lot of new stuff (too much to mention) + * + * Revision 1.2 1993/11/11 07:16:39 start + * New stuff + * + * Revision 1.1 1993/11/03 09:13:08 start + * Initial revision + * + * + *****************************************************************************/ +/********************************************************************** + * + * usecpp.c + * + * This is a routine that is should be used to call functions in the + * fpp.library. We supply the own_input() and own_output() functions to + * the preprocessor to remain flexible. + */ + +#include + +#ifdef AMIGA +#include +#include + +#if defined(SHARED) +#include +#include + +#include "fpp_pragmas.h" +#include "fpp_protos.h" +#include "FPPBase.h" +struct Library *FPPBase=NULL; +#define PREFIX __saveds +#define REG(x) register __ ## x +#else +#define PREFIX +#define REG(x) +#endif + +#elif defined(UNIX) +#if defined(OS9) +#include +#else +#include +#ifdef BSD +#include /* for BSD systems (SUN OS at least) */ +#endif +#endif +#define PREFIX +#define REG(x) +#endif +#include +#include +#include +#include +#ifndef OS9 +#include +#else +#define va_list void * +#endif + +#include "fpp.h" +#define MAX_TAGS 40 /* maximum number of tags allowed! */ +#define FILE_LOCAL static + +#define CPP_PREFS_FILE "cpp.prefs" +#ifdef AMIGA +#define DEFAULT_CPP_PREFS_FILE "s:cpp.prefs" +#else +#define DEFAULT_CPP_PREFS_FILE "$HOME/cpp.prefs" +#endif + +FILE_LOCAL char PREFIX *own_input(char *, int, void *); +FILE_LOCAL void PREFIX own_output(int, void *); +FILE_LOCAL void PREFIX own_error(void *, char *, va_list); +FILE_LOCAL int SetOptions(int, char **, struct fppTag **); +FILE_LOCAL char GetPrefs(struct fppTag **, char **); +FILE_LOCAL char DoString(struct fppTag **, char *); + +#ifdef AMIGA +extern long __stack=8000; +#endif + +FILE_LOCAL char ignore=FALSE; /* if we should ignore strange flags! */ +FILE_LOCAL char display=FALSE; /* display all options in use! */ + +FILE_LOCAL char dontreadprefs; /* set if only the command line is valid */ + +int main(int argc, char **argv) +{ + struct fppTag tags[MAX_TAGS]; + int i; + struct fppTag *tagptr = tags; + char *dealloc; + + /* + * Append system-specific directories to the include directory list. + * The include directories will be searched through in the same order + * as you add them in the taglist! + * The directory _must_ end with a proper directory speparator! + */ + + tagptr->tag=FPPTAG_INCLUDE_DIR; +#if defined (AMIGA) + tagptr->data = "INCLUDE:"; +#elif defined (OS9) + tagptr->data = "/dd/defs/"; +#else + tagptr->data = "/usr/include/"; +#endif + tagptr++; + + if(GetPrefs(&tagptr, &dealloc)) + return(0); + + if( !(i = SetOptions(argc, argv, &tagptr))) + return(0); + + if (argc - i >2) { + printf("Too many file arguments. Usage: cpp [options] [input [output]]\n"); + return(-1); + } + + tagptr->tag=FPPTAG_INPUT; + tagptr->data=(void *)own_input; + tagptr++; + + if(itag=FPPTAG_INPUT_NAME; + tagptr->data=argv[i]; + tagptr++; + if(display) + fprintf(stderr, "cpp: input: %s\n", argv[i]); + } else /* Else, just get stdin */ + if(display) + fprintf(stderr, "cpp: input: [stdin]\n"); + i++; + } else + if(display) + fprintf(stderr, "cpp: input: [stdin]\n"); + + if(itag=FPPTAG_OUTPUT; + tagptr->data=(void *)own_output; + tagptr++; + + tagptr->tag=FPPTAG_ERROR; + tagptr->data=(void *)own_error; + tagptr++; + + /* The LAST tag: */ + + tagptr->tag=FPPTAG_END; + tagptr->data=0; + tagptr++; + +#if defined(SHARED) && defined(AMIGA) + if(!(FPPBase=OpenLibrary(FPPNAME, 1))) { + printf("Error opening %s!\n", FPPNAME); + return(-1); + } +#endif + fppPreProcess(tags); + +#if defined(SHARED) && defined(AMIGA) + CloseLibrary((struct Library *)FPPBase); +#endif + /* + * Preprocess ready! + */ + + if( dealloc ) + free( dealloc ); + + return(0); +} + + +FILE_LOCAL +char PREFIX *own_input(char *buffer, int size, void *userdata) +{ + return(fgets(buffer, size, stdin)); +} + +FILE_LOCAL +void PREFIX own_output(int c, void *userdata) +{ + putchar(c); +} + +FILE_LOCAL +void PREFIX own_error(void *userdata, char *format, va_list arg) +{ + vfprintf(stderr, format, arg); +} + +FILE_LOCAL +char GetPrefs(struct fppTag **tagptr, char **string) +{ + + FILE *PrefsFile_PF; + unsigned Length_U; + char *PrefsBuffer_PC; + char ret= 0; + char *environ; + + *string = NULL; + + /* Open prefs file for read */ + if ( (PrefsFile_PF = fopen(CPP_PREFS_FILE, "r")) || + (PrefsFile_PF = fopen(DEFAULT_CPP_PREFS_FILE, "r"))) { + + fseek(PrefsFile_PF, 0 , SEEK_END); + Length_U = ftell(PrefsFile_PF); + fseek(PrefsFile_PF, 0, SEEK_SET); + + if (*string = (char *)malloc(Length_U+1)) { + fread(*string, 1, Length_U, PrefsFile_PF); + (*string)[Length_U] = '\0'; + + ret = !DoString(tagptr, *string); + } + fclose(PrefsFile_PF); + if(ret) { + free( *string ); + return ret; + } + } + + if(environ = getenv("CPP_PREFS")) { + ret= !DoString(tagptr, environ); + if(ret && *string) + free( *string ); + } + return ret; +} + +FILE_LOCAL +char DoString(struct fppTag **tagptr, char *string) +{ + char *argv[MAX_TAGS]; + int argc=1; + do { + while(*string && *string != '-') + string++; + + if(!*string) + break; + + argv[argc]=string; + + do { + string++; + if(*string=='\"') { + do + string++; + while(*string != '\"'); + string++; + } + } while(*string && *string!=' ' && *string != '\n' && *string != '\t'); + argc++; + if(*string) { + *string='\0'; + string++; + } else + break; + } while(1); + + return (SetOptions(argc, argv, tagptr)); +} + +FILE_LOCAL +int SetOptions(int argc, char **argv, struct fppTag **tagptr) +{ + int i; + char *ap; + for (i = 1; i < argc; i++) { + ap = argv[i]; + if (*ap++ != '-' || *ap == '\0') + break; + else { + char c = *ap++; + + if(display) + fprintf(stderr, "cpp: option: %s\n", ap-2); + + switch (c) { /* Command character */ + case 'Q': /* ignore unknown flags but */ + ignore=1; /* output them on stderr */ + break; + + case 'q': /* ignore unknown flags */ + ignore=2; + break; + + case 'H': /* display all whitespaces */ + (*tagptr)->tag = FPPTAG_OUTPUTSPACE; + (*tagptr)->data= (void *)TRUE; + (*tagptr)++; + break; + + case 'b': /* display unbalance */ + (*tagptr)->tag = FPPTAG_OUTPUTBALANCE; + (*tagptr)->data= (void *)TRUE; + (*tagptr)++; + break; + + case 'f': /* output all defined functions! */ + (*tagptr)->tag = FPPTAG_DISPLAYFUNCTIONS; + (*tagptr)->data= (void *)TRUE; + (*tagptr)++; + break; + + case 'F': /* output all included files! */ + (*tagptr)->tag = FPPTAG_OUTPUTINCLUDES; + (*tagptr)->data= (void *)TRUE; + (*tagptr)++; + break; + + case 'V': /* do not output version */ + (*tagptr)->tag = FPPTAG_IGNOREVERSION; + (*tagptr)->data= (void *)FALSE; + (*tagptr)++; + break; + + case 'C': /* Keep comments */ + (*tagptr)->tag = FPPTAG_KEEPCOMMENTS; + (*tagptr)->data= (void *)TRUE; + (*tagptr)++; + break; + + case 'D': /* Define symbol */ + (*tagptr)->tag=FPPTAG_DEFINE; + (*tagptr)->data=argv[i]+2; + (*tagptr)++; + break; + + case 'd': /* Display all options */ + fprintf(stderr, "FOUND -d flag!\n"); + display = TRUE; + break; + + case 'E': /* Ignore non-fatal errors */ + (*tagptr)->tag=FPPTAG_IGNORE_NONFATAL; + (*tagptr)->data=(void *)TRUE; + (*tagptr)++; + break; + + case 'I': /* Include directory */ + (*tagptr)->tag=FPPTAG_INCLUDE_DIR; + (*tagptr)->data=ap; + (*tagptr)++; + break; + + case 'J': /* Allow nested comments */ + (*tagptr)->tag=FPPTAG_NESTED_COMMENTS; + (*tagptr)->data=ap; + (*tagptr)++; + break; + + case 'j': /* Warn at nested comments */ + (*tagptr)->tag=FPPTAG_WARN_NESTED_COMMENTS; + (*tagptr)->data=ap; + (*tagptr)++; + break; + + case 'L': + if(*ap == 'L') { /* Do not output #line */ + (*tagptr)->tag=FPPTAG_LINE; + } else { + /* Do not output the 'line' keyword */ + (*tagptr)->tag=FPPTAG_OUTPUTLINE; + } + (*tagptr)->data=(void *)FALSE; + (*tagptr)++; + break; + + case 'M': /* Do not warn at missing includes */ + (*tagptr)->tag=FPPTAG_WARNMISSINCLUDE; + (*tagptr)->data=(void *)FALSE; + (*tagptr)++; + break; + + case 'n': + dontreadprefs^=1; /* toggle prefsreading, default is read prefs */ + + /* + * This flag should reset all previously added tags! + */ + + break; + + case 'N': /* No machine specific built-ins */ + (*tagptr)->tag=FPPTAG_BUILTINS; + (*tagptr)->data=(void *)FALSE; + (*tagptr)++; + break; + + case 'B': /* No predefines like __LINE__, etc. */ + (*tagptr)->tag=FPPTAG_PREDEFINES; + (*tagptr)->data=(void *)FALSE; + (*tagptr)++; + break; + + case 'P': /* No C++ comments */ + (*tagptr)->tag=FPPTAG_IGNORE_CPLUSPLUS; + (*tagptr)->data=(void *)TRUE; + (*tagptr)++; + break; + + case 'p': /* warn about illegal # - instructions */ + (*tagptr)->tag = FPPTAG_WARNILLEGALCPP; + (*tagptr)->data= (void *)TRUE; + (*tagptr)++; + break; + + case 'R': + (*tagptr)->tag = FPPTAG_RIGHTCONCAT; + (*tagptr)->data= (void *)TRUE; + (*tagptr)++; + break; + + case 's': /* sizeof table */ + (*tagptr)->tag=FPPTAG_INITFUNC; + (*tagptr)->data=ap; + (*tagptr)++; + break; + + case 't': /* excluded functions */ + (*tagptr)->tag=FPPTAG_EXCLFUNC; + (*tagptr)->data=ap; + (*tagptr)++; + break; + + case 'S': /* sizeof table */ + (*tagptr)->tag=FPPTAG_SIZEOF_TABLE; + (*tagptr)->data=ap; + (*tagptr)++; + break; + + case 'U': /* Undefine symbol */ + (*tagptr)->tag=FPPTAG_UNDEFINE; + (*tagptr)->data=ap; + (*tagptr)++; + break; + + case 'w': /* Output all #defines but not the + main file */ + (*tagptr)->tag=FPPTAG_OUTPUTMAIN; + (*tagptr)->data=(void *)FALSE; + (*tagptr)++; + + case 'W': /* Output all #defines */ + if(!strncmp(ap, "WW", 2)) { + (*tagptr)->tag=FPPTAG_WEBMODE; + (*tagptr)->data=(void *)TRUE; + (*tagptr)++; + } + else { + (*tagptr)->tag=FPPTAG_OUTPUT_DEFINES; + (*tagptr)->data=(void *)TRUE; + (*tagptr)++; + } + break; + + case 'X': + (*tagptr)->tag=FPPTAG_INCLUDE_FILE; + (*tagptr)->data=ap; + (*tagptr)++; + break; + +/* + case 'x': + tags[tag]->tag=FPPTAG_INCLUDE_MACRO_FILE; + tags[tag++]->data=ap; + break; +*/ + case 'h': + case '?': /* if a question mark is possible to specify! */ + default: /* What is this one? */ + if( ignore < 2 && c != 'h') { + fprintf(stderr, "cpp: unknown option: -%s\n", ap-1); + } + if(!ignore || c == 'h') { + fprintf(stderr, + "Usage: cpp [options] [infile [outfile] ]\n\n" + "The following options are valid:\n" + " -B\tNo mahcine specific built-in symbols\n" + " -b\tOutput any parentheses, brace or bracket unbalance\n" + " -C\tWrite source file comments to output\n" + " -D\tDefine a symbol with the given (optional) value \"symbol[=value]\"\n" + " -d\tDisplay all specified options\n" + " -E\tIgnore non-fatal errors\n" + " -F\tOutput all included file names on stderr\n" + " -f\tOutput all defined functions' names on stderr\n" + " -H\tOutput all whitespaces from the source file\n" + " -h\tOutput this help text\n" + " -I\tAdd directory to the #include search list\n" + " -J\tAllow nested comments\n" + " -j\tEnable warnings for nested comments\n" + " -LL\tDon't output #line instructions\n" + " -L\tDon't output the 'line' keyword in \"#line\" instructions\n" + " -M\tDon't warn for missing include files\n" + " -N\tDon't predefine target-specific names\n" + " -n\tToggle prefs usage\n" + " -P\tDon't recognize C++ comment style\n" + " -p\tEnable warnings on non ANSI preprocessor instructions\n" + " -Q\tIgnore but visualize undefined flags\n" + " -q\tIgnore all undefined flags\n" + " -R\tEvaluate the right part first in symbol concatenations\n" + " -s\tInclude the following string at the top of each function\n" + " -S\tSpecify sizes for #if sizeof\n" + " -t\tThis function should not get an initial function\n" + " -U\tUndefine symbol\n" + " -V\tDon't output version information\n" + " -W\tOutput all #defines\n" + " -WWW\tWeb mode preprocessing\n" + " -w\tOnly output #defines\n" + " -X\tInclude file\n"); + return(0); + } /* if (!ignore) */ + } /* Switch on all options */ + } /* If it's a -option */ + } /* For all arguments */ + + return i; + +} /* end of function */