diff options
Diffstat (limited to 'rsc/source/rscpp')
-rw-r--r-- | rsc/source/rscpp/cpp.h | 415 | ||||
-rw-r--r-- | rsc/source/rscpp/cpp1.c | 616 | ||||
-rw-r--r-- | rsc/source/rscpp/cpp2.c | 625 | ||||
-rw-r--r-- | rsc/source/rscpp/cpp3.c | 601 | ||||
-rw-r--r-- | rsc/source/rscpp/cpp4.c | 635 | ||||
-rw-r--r-- | rsc/source/rscpp/cpp5.c | 929 | ||||
-rw-r--r-- | rsc/source/rscpp/cpp6.c | 1148 | ||||
-rw-r--r-- | rsc/source/rscpp/cppdef.h | 346 | ||||
-rw-r--r-- | rsc/source/rscpp/cppmain.c | 45 | ||||
-rw-r--r-- | rsc/source/rscpp/makefile.mk | 92 |
10 files changed, 5452 insertions, 0 deletions
diff --git a/rsc/source/rscpp/cpp.h b/rsc/source/rscpp/cpp.h new file mode 100644 index 000000000000..11327d4fb9d1 --- /dev/null +++ b/rsc/source/rscpp/cpp.h @@ -0,0 +1,415 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +/* in cpp1.c: file-pointer auf stdout oder file */ +extern FILE *pCppOut; /* BP */ +#define PUTCHAR( d ) fprintf( pCppOut, "%c", (d) ) /* BP */ +#if OSL_DEBUG_LEVEL > 1 +extern FILE *pDefOut; /* ER */ +#ifdef EVALDEFS +#define NEVALBUF 2048 +#endif +#endif + +/* limit for reading commandfiles */ +#define PARALIMIT 100 + +#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 DEF_MAGIC 0x1D /* Magic for #defines */ +#define TOK_SEP 0x1E /* Token concatenation delim. */ +#define COM_SEP 0x1F /* Magic comment separator */ + +#ifdef EBCDIC +#define HT 0x05 /* horizontal tab */ +#define NL 0x15 /* new line */ +#define CR 0x0D /* carriage return */ +#define DEL 0x07 +#else +#define HT 0x09 /* horizontal tab */ +#define NL 0x0A /* new line */ +#define CR 0x0D /* carriage return */ +#define DEL 0x7F +#endif + + +#ifdef SOLAR +#define MAC_PARM 0x01 /* Macro formals start here */ +#else +/* + * 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 DEL /* Macro formals start here */ +#if PAR_MAC >= 33 + assertion fails -- PAR_MAC is not 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, */ + int size; /* this is the datum size value */ + int 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 + +/* + * Error codes. VMS uses system definitions. + * Decus C codes are defined in stdio.h. + * Others are cooked to order. + */ + +#if HOST == SYS_VMS +#include <ssdef.h> +#include <stsdef.h> +#define IO_NORMAL (SS$_NORMAL | STS$M_INHIB_MSG) +#define IO_ERROR SS$_ABORT +#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 + */ + +extern int line; /* Current line number */ +extern int wrongline; /* Force #line to cc pass 1 */ +extern char type[]; /* Character classifier */ +extern char token[IDMAX + 1]; /* Current input token */ +extern int instring; /* TRUE if scanning string */ +extern int inmacro; /* TRUE if scanning #define */ +extern int errors; /* Error counter */ +extern int recursion; /* Macro depth counter */ +extern char ifstack[BLK_NEST]; /* #if information */ +#define compiling ifstack[0] +extern char *ifptr; /* -> current ifstack item */ +extern char *incdir[NINCLUDE]; /* -i directories */ +extern char **incend; /* -> active end of incdir */ +extern int cflag; /* -C option (keep comments) */ +extern int eflag; /* -E option (ignore errors) */ +extern int nflag; /* -N option (no pre-defines) */ +extern int rec_recover; /* unwind recursive macros */ +extern char *preset[]; /* Standard predefined symbols */ +extern char *magic[]; /* Magic predefined symbols */ +extern FILEINFO *infile; /* Current input file */ +extern char work[NWORK + 1]; /* #define scratch */ +extern char *workp; /* Free space in work */ +#if OSL_DEBUG_LEVEL > 1 +extern int debug; /* Debug level */ +/* ER dump & evaluate #define's */ +extern int bDumpDefs; /* TRUE if #define's dump req. */ +extern int bIsInEval; /* TRUE if #define dumping now */ +#ifdef EVALDEFS +extern char EvalBuf[NEVALBUF + 1]; /* evaluation buffer */ +extern int nEvalOff; /* offset to free buffer pos */ +#endif +#endif +extern int keepcomments; /* Don't remove comments if set */ +extern SIZES size_table[]; /* For #if sizeof sizes */ + +#ifdef NOMAIN /* BP */ +#ifndef _NO_PROTO +int start_cpp( int argc, char *argv[] ); +#endif +#define MAIN start_cpp /* fuer die cpp.lib muss main() geandert werden */ +#else +#ifdef WNT +#define MAIN __cdecl main +#else +#define MAIN main +#endif +#endif + + +void InitCpp1(); +void InitCpp2(); +void InitCpp3(); +void InitCpp4(); +void InitCpp5(); +void InitCpp6(); + +#define HELLO() fprintf( stderr, "[Hello at %s, %d] ", __FILE__, __LINE__ ) + +#ifndef _STDIO_H +#include <stdio.h> +#endif + +#ifndef _STDLIB_H +#include <stdlib.h> +#endif + +#ifndef _STRING_H +#include <string.h> +#endif + +/* cpp1.c */ +void output( int c ); +void sharp(); +void cppmain(); +#if OSL_DEBUG_LEVEL > 1 +#ifdef EVALDEFS +int outputEval( int c ); +#endif +#endif + + +/* cpp2.c */ +int control( int counter ); +void doinclude(); +void dodefine(); +void doif( int hash ); +int openinclude( char *, int ); +int hasdirectory(char *, char * ); +int openfile( char * ); + +/* cpp3.c */ +int openfiles( char *filename ); +void addfile( FILE *fp, char *filename ); +void setincdirs(); +int AddInclude( char *pIncStr ); +int getredirection( int argc, char **argv ); +void zap_uc( char *ap ); + +void initdefines(); +int dooptions( int argc, char *argv[] ); +int readoptions(char* filename, char*** pfargv); + +/* cpp4.c */ +void dodefines(); +void checkparm( int c, DEFBUF *dp ); +int expcollect(); +void expstuff( DEFBUF *dp ); + +#if STRING_FORMAL +void stparmscan( int delim, DEFBUF *dp); +#else +void stparmscan( int delim); +#endif +#if OSL_DEBUG_LEVEL > 1 +void dumpparm( char *why ); +#endif + +void doundef(); +void textput( char *text ); +void charput( int c ); +void expand( DEFBUF *tokenp ); + +/* cpp5.c */ +int eval(); +int evallex(int); +int *evaleval(int *, int, int ); +int evalchar(int); +int dosizeof(); +int evalnum( int c ); +int bittest( int ); + +/* cpp6.c */ + +void skipnl(); +int skipws(); +void scanid( int c ); +int macroid( int c ); +int catenate(); +int scanstring( int c, void (*outfun)( int c ) ); +void scannumber( int c, void (*outfun)( int c ) ); +void save( int c ); +char *savestring( char *text ); +FILEINFO *getfile( int bufsize, char *name); +char *getmem( int size ); +DEFBUF *lookid( int c ); +DEFBUF *defendel( char *name, int delete ); +void dunpdef( char *why ); +void dumpadef( char *why, DEFBUF *dp); +int get(); +int cget(); +void unget(); +void ungetstring( char *text ); +void cerror( char *format, char *sarg); +void cwarn( char *format, char *sarg); +void cfatal( char *format, char *sarg); +void cierror( char *format, int n); +void ciwarn( char *format, int n); +#if OSL_DEBUG_LEVEL > 1 +void dumpdef( char *why ); +void dumpadef( char *why, DEFBUF *dp ); +#endif diff --git a/rsc/source/rscpp/cpp1.c b/rsc/source/rscpp/cpp1.c new file mode 100644 index 000000000000..1eb7561a2db0 --- /dev/null +++ b/rsc/source/rscpp/cpp1.c @@ -0,0 +1,616 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <stdio.h> +#include <ctype.h> +#include "cppdef.h" +#include "cpp.h" + +FILE *pCppOut = NULL; +FILE *pCppIn = NULL; + +#if OSL_DEBUG_LEVEL > 1 +FILE *pDefOut = NULL; /* ER evtl. #define's dump */ +#endif + +#ifdef B200 +/* BP, 25.07.91, einzige Moeglichkeit unter BC Stack und Heap festzusetzen */ +extern unsigned _stklen = 24000; +extern unsigned _heaplen = 30000; +#endif + + + +/* + * 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. + * + * token 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 token[IDMAX + 1]; /* Current input token */ +int errors; /* cpp error counter */ +FILEINFO *infile = NULL; /* Current input file */ +#if OSL_DEBUG_LEVEL > 1 +int debug; /* TRUE if debugging now */ +int bDumpDefs; /* TRUE if #define's dump req. */ +#ifdef EVALDEFS +int bIsInEval; /* TRUE if #define eval now */ +char EvalBuf[NEVALBUF + 1]; /* evaluation buffer */ +int nEvalOff = 0; /* offset to free buffer pos */ +#endif +#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 = TRUE; /* 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 <DEF_MAGIC>). Note especially that + * comments and \<newline> 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 \<newline> + * to the caller. Strictly speaking, this is a bug as \<newline> + * 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 = FALSE; /* TRUE if scanning string */ +int inmacro = FALSE; /* 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. + */ +int keepcomments = FALSE; /* Write out comments flag */ +int cflag = FALSE; /* -C option (keep comments) */ +int eflag = FALSE; /* -E option (never fail) */ +int nflag = 0; /* -N option (no predefines) */ + +/* + * 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] = { TRUE }; /* #if information */ +char *ifptr = ifstack; /* -> current ifstack[] */ + +/* + * incdir[] stores the -i directories (and the system-specific + * #include <...> directories. + */ +char *incdir[NINCLUDE]; /* -i directories */ +char **incend = incdir; /* -> free space in incdir[] */ + +/* + * 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 -N option supresses preset definitions. + */ +char *preset[] = { /* names defined at cpp start */ +#ifdef MACHINE + MACHINE, +#endif +#ifdef SYSTEM + SYSTEM, +#endif +#ifdef COMPILER + COMPILER, +#endif +#if OSL_DEBUG_LEVEL > 1 + "decus_cpp", /* Ourselves! */ +#endif + NULL /* Must be last */ +}; + +/* + * The value of these predefined symbols must be recomputed whenever + * they are evaluated. The order must not be changed. + */ +char *magic[] = { /* Note: order is important */ + "__LINE__", + "__FILE__", + NULL /* Must be last */ +}; + +static char *sharpfilename = NULL; + +int nRunde = 0; + +void InitCpp1() +{ + int i; + /* BP */ + /* in der LIB-Version muessen alle Variablen initialisiert werden */ + + line = wrongline = errors = recursion = 0; + for( i = 0; i < IDMAX; i++ ) + token[ i ] = 0; + + for( i = 0; i < NWORK; i++ ) + work[ i ] = 0; + + for( i = 0; i < NINCLUDE; i++ ) + incdir[ i ] = NULL; + + workp = NULL; + for( i = 0; i < BLK_NEST; i++ ) + ifstack[ i ] = TRUE; + ifptr = ifstack; + + pCppOut = stdout; + pCppIn = stdin; +#if OSL_DEBUG_LEVEL > 1 + debug = 0; + bDumpDefs = 0; + pDefOut = stdout; +#ifdef EVALDEFS + bIsInEval = 0; + for( i = 0; i < NEVALBUF; i++ ) + EvalBuf[ i ] = 0; + nEvalOff = 0; +#endif +#endif + rec_recover = TRUE; + infile = NULL; + instring = inmacro = keepcomments = cflag = eflag = FALSE; + nflag = 0; + incend = incdir; + sharpfilename = NULL; + /* BP */ +} + +int MAIN(int argc, char** argv) +{ + register int i; + char **useargv, **pfargv; + + +if( nRunde == 0 ) +{ + pCppIn = stdin; + pCppOut = stdout; +} + +nRunde++; + InitCpp1(); + InitCpp2(); + InitCpp3(); + InitCpp4(); + InitCpp5(); + InitCpp6(); + +#if HOST == SYS_VMS + argc = getredirection(argc, argv); /* vms >file and <file */ +#endif + initdefines(); /* O.S. specific def's */ + if ( argv[argc-1][0] == '@' ) + { + i = readoptions( argv[1], &pfargv ); /* Command file */ + useargv=pfargv; + } + else + { + i = dooptions(argc, argv); /* Command line -flags */ + useargv=argv; + } + switch (i) { +#if OSL_DEBUG_LEVEL > 1 + case 4: + if ( bDumpDefs ) + { + /* + * Get defBase file, "-" means use stdout. + */ + if (!streq(useargv[3], "-")) { +#if HOST == SYS_VMS + /* + * On vms, reopen stdout with "vanilla rms" attributes. + */ + if ((i = creat(useargv[3], 0, "rat=cr", "rfm=var")) == -1 + || dup2(i, fileno(stdout)) == -1) { +#else +/* alt if (freopen(useargv[3], "w", stdout) == NULL) { */ + + pDefOut = fopen( useargv[3], "w" ); + if( pDefOut == NULL ) { +#endif + perror(useargv[3]); + cerror("Can't open output file \"%s\"", useargv[3]); + exit(IO_ERROR); + } + } /* Continue by opening output */ + } +/* OSL_DEBUG_LEVEL > 1 */ +#endif + case 3: + /* + * Get output file, "-" means use stdout. + */ + if (!streq(useargv[2], "-")) { +#if HOST == SYS_VMS + /* + * On vms, reopen stdout with "vanilla rms" attributes. + */ + if ((i = creat(useargv[2], 0, "rat=cr", "rfm=var")) == -1 + || dup2(i, fileno(stdout)) == -1) { +#else +/* alt if (freopen(useargv[2], "w", stdout) == NULL) { */ + + pCppOut = fopen( useargv[2], "w" ); + if( pCppOut == NULL ) { +#endif + perror(useargv[2]); + cerror("Can't open output file \"%s\"", useargv[2]); + exit(IO_ERROR); + } + } /* Continue by opening input */ + case 2: /* One file -> stdin */ + /* + * Open input file, "-" means use stdin. + */ + if (!streq(useargv[1], "-")) { +/* alt: if (freopen(useargv[1], "r", stdin) == NULL) { */ + pCppIn = fopen( useargv[1], "r" ); + if( pCppIn == NULL) { + perror(useargv[1]); + cerror("Can't open input file \"%s\"", useargv[1]); + exit(IO_ERROR); + } + strcpy(work, useargv[1]); /* Remember input filename */ + break; + } /* Else, just get stdin */ + case 0: /* No args? */ + case 1: /* No files, stdin -> stdout */ +#if (HOST == SYS_UNIX) || (HOST == SYS_UNKNOWN) + work[0] = EOS; /* Unix can't find stdin name */ +#else + fgetname(stdin, work); /* Vax-11C, Decus C know name */ +#endif + break; + + default: + exit(IO_ERROR); /* Can't happen */ + } +/* if ( pfargv ) + { + for ( j=0;j++;j < PARALIMIT ) + { + if (pfargv[j]!=0) + free(pfargv[j]); + } + free(pfargv); + } +*/ + + setincdirs(); /* Setup -I include directories */ + addfile( pCppIn, work); /* "open" main input file */ +#if OSL_DEBUG_LEVEL > 1 + if (debug > 0 || bDumpDefs) + dumpdef("preset #define symbols"); +#endif + if( pCppIn != stdin ) + rewind( pCppIn ); + + cppmain(); /* Process main file */ + + if ((i = (ifptr - &ifstack[0])) != 0) { +#if OLD_PREPROCESSOR + ciwarn("Inside #ifdef block at end of input, depth = %d", i); +#else + cierror("Inside #ifdef block at end of input, depth = %d", i); +#endif + } +#if OSL_DEBUG_LEVEL > 1 + if( pDefOut != stdout && pDefOut != stderr ) + fclose( pDefOut ); +#endif + if( pCppOut != stdout && pCppOut != stderr ) + fclose( pCppOut ); + + if (errors > 0) { + fprintf(stderr, (errors == 1) + ? "%d error in preprocessor\n" + : "%d errors in preprocessor\n", errors); + if (!eflag) + exit(IO_ERROR); + } +#ifdef NOMAIN /* BP */ /* kein exit im der LIB-Version */ + return( IO_NORMAL ); +#else + exit(IO_NORMAL); /* No errors or -E option set */ +#endif + +} + +FILE_LOCAL +void cppmain() +/* + * Main process for cpp -- copies tokens from the current input + * stream (main file, include file, or a macro) to the output + * file. + */ +{ + register int c; /* Current character */ + register int counter; /* newlines and spaces */ + + /* + * 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. + * We also seem to need a blank line following that first #line. + */ +#ifdef EVALDEFS + if ( !bIsInEval ) +#endif + { + sharp(); + PUTCHAR('\n'); + } + /* + * 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. + */ + for (;;) { + counter = 0; /* Count empty lines */ + for (;;) { /* For each line, ... */ + while (type[(c = get())] == SPA) /* Skip leading blanks */ + ; /* in this line. */ + if (c == '\n') /* If line's all blank, */ + ++counter; /* Do nothing now */ + else if (c == '#') { /* Is 1st non-space '#' */ + keepcomments = FALSE; /* Don't pass comments */ + counter = control(counter); /* Yes, do a #command */ + keepcomments = (cflag && compiling); + } + else if (c == EOF_CHAR) /* At end of file? */ + { + break; + } + else if (!compiling) { /* #ifdef false? */ + skipnl(); /* 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 ((wrongline && infile->fp != NULL) || counter > 4) + sharp(); /* Output # line number */ + else { /* If just a few, stuff */ + while (--counter >= 0) /* them out ourselves */ + PUTCHAR('\n'); + } + /* + * Process each token on this line. + */ + unget(); /* Reread the char. */ + for (;;) { /* For the whole line, */ + do { /* Token concat. loop */ + for (counter = 0; (type[(c = get())] == SPA);) { +#if COMMENT_INVISIBLE + if (c != COM_SEP) + counter++; +#else + counter++; /* Skip over blanks */ +#endif + } + if (c == EOF_CHAR || c == '\n') + goto end_line; /* Exit line loop */ + else if (counter > 0) /* If we got any spaces */ + PUTCHAR(' '); /* Output one space */ + c = macroid(c); /* Grab the token */ + } while (type[c] == LET && catenate()); + if (c == EOF_CHAR || c == '\n') /* From macro exp error */ + goto end_line; /* Exit line loop */ + switch (type[c]) { + case LET: + fputs(token, pCppOut); /* Quite ordinary token */ +#ifdef EVALDEFS + { + int len; + if ( bIsInEval + && nEvalOff + (len=strlen(token)) < NEVALBUF ) + { + strcpy( &EvalBuf[nEvalOff], token ); + nEvalOff += len; + } + } +#endif + break; + + + case DIG: /* Output a number */ + case DOT: /* Dot may begin floats */ +#ifdef EVALDEFS + if ( bIsInEval ) + scannumber(c, outputEval); + else + scannumber(c, output); +#else + scannumber(c, output); +#endif + break; + + case QUO: /* char or string const */ + scanstring(c, output); /* Copy it to output */ + break; + + default: /* Some other character */ + cput(c); /* Just output it */ +#ifdef EVALDEFS + if ( bIsInEval && nEvalOff < NEVALBUF ) + EvalBuf[nEvalOff++] = c; +#endif + break; + } /* Switch ends */ + } /* Line for loop */ +end_line: if (c == '\n') { /* Compiling at EOL? */ + PUTCHAR('\n'); /* Output newline, if */ + if (infile->fp == NULL) /* Expanding a macro, */ + wrongline = TRUE; /* Output # line later */ + } + } /* Continue until EOF */ +#ifdef EVALDEFS + if ( bIsInEval ) + EvalBuf[nEvalOff++] = '\0'; +#endif +} + +void output(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 +/* alt: PUTCHAR(c); */ + PUTCHAR(c); +} + +#ifdef EVALDEFS +outputEval(c) +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 +/* alt: PUTCHAR(c); */ + { + PUTCHAR(c); + if ( bIsInEval && nEvalOff < NEVALBUF ) + EvalBuf[nEvalOff++] = c; + } +} +#endif + + +FILE_LOCAL +void sharp() +/* + * Output a line number line. + */ +{ + register char *name; + + if (keepcomments) /* Make sure # comes on */ + PUTCHAR('\n'); /* a fresh, new line. */ + fprintf( pCppOut, "#%s %d", LINE_PREFIX, line); + if (infile->fp != NULL) { + name = (infile->progname != NULL) + ? infile->progname : infile->filename; + if (sharpfilename == NULL + || (sharpfilename != NULL && !streq(name, sharpfilename)) ) { + if (sharpfilename != NULL) + free(sharpfilename); + sharpfilename = savestring(name); + fprintf( pCppOut, " \"%s\"", name); + } + } + PUTCHAR('\n'); + wrongline = FALSE; +} diff --git a/rsc/source/rscpp/cpp2.c b/rsc/source/rscpp/cpp2.c new file mode 100644 index 000000000000..68d1d2dc72ba --- /dev/null +++ b/rsc/source/rscpp/cpp2.c @@ -0,0 +1,625 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <stdio.h> +#include <ctype.h> +#include "cppdef.h" +#include "cpp.h" +#if HOST == SYS_VMS +/* + * Include the rms stuff. (We can't just include rms.h as it uses the + * VaxC-specific library include syntax that Decus CPP doesn't support. + * By including things by hand, we can CPP ourself.) + */ +#include <nam.h> +#include <fab.h> +#include <rab.h> +#include <rmsdef.h> +#endif + +/* + * 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_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)) +#define L_error ('e' + ('r' << 1)) /* BP 5.3.92, #error */ +#define MAXLINE 80 /* BP 5.3.92, #error */ +#if OSL_DEBUG_LEVEL > 1 +#define L_debug ('d' + ('b' << 1)) /* #debug */ +#define L_nodebug ('n' + ('d' << 1)) /* #nodebug */ +#endif + + +void InitCpp2() +{ + +} + + +int +control(int 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. + */ +{ + register int c; + register char *tp; + register int hash; + char *ep; + + c = skipws(); + if (c == '\n' || c == EOF_CHAR) + return (counter + 1); + if (!isdigit(c)) + scanid(c); /* Get #word to token[] */ + else { + unget(); /* Hack -- allow #123 as a */ + strcpy(token, "line"); /* synonym for #line 123 */ + } + hash = (token[1] == EOS) ? L_nogood : (token[0] + (token[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_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; + case L_error: tp = "error"; break; +#if OSL_DEBUG_LEVEL > 1 + case L_debug: tp = "debug"; break; + case L_nodebug: tp = "nodebug"; break; +#endif + default: hash = L_nogood; + case L_nogood: tp = ""; break; + } + if (!streq(tp, token)) + 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 (infile->fp == NULL) + cwarn("Control line \"%s\" within macro expansion", token); + 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 (++ifptr >= &ifstack[BLK_NEST]) + goto if_nest_err; + *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: /* BP 5.3.92, #error */ +dump_line: skipnl(); /* Ignore rest of line */ + return (counter + 1); + } + } + /* + * Make sure that #line and #pragma are output on a fresh line. + */ + if (counter > 0 && (hash == L_line || hash == L_pragma)) { + PUTCHAR('\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(); + workp = work; /* Save name in work */ + while (c != '\n' && c != EOF_CHAR) { + save(c); + c = get(); + } + unget(); + save(EOS); + /* + * Split #line argument into <line-number> and <name> + * We subtract 1 as we want the number of the next line. + */ + line = atoi(work) - 1; /* Reset line number */ + for (tp = work; isdigit(*tp) || type[(int)*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 (infile->progname != NULL) /* Give up the old name */ + free(infile->progname); /* if it's allocated. */ + infile->progname = savestring(tp); + } + wrongline = TRUE; /* Force output later */ + break; + + case L_include: + doinclude(); + break; + + case L_define: + dodefine(); + break; + + case L_undef: + doundef(); + break; + + case L_else: + if (ifptr == &ifstack[0]) + goto nest_err; + else if ((*ifptr & ELSE_SEEN) != 0) + goto else_seen_err; + *ifptr |= ELSE_SEEN; + if ((*ifptr & WAS_COMPILING) != 0) { + if (compiling || (*ifptr & TRUE_SEEN) != 0) + compiling = FALSE; + else { + compiling = TRUE; + } + } + break; + + case L_elif: + if (ifptr == &ifstack[0]) + goto nest_err; + else if ((*ifptr & ELSE_SEEN) != 0) { +else_seen_err: cerror("#%s may not follow #else", token); + goto dump_line; + } + if ((*ifptr & (WAS_COMPILING | TRUE_SEEN)) != WAS_COMPILING) { + compiling = FALSE; /* Done compiling stuff */ + goto dump_line; /* Skip this clause */ + } + doif(L_if); + break; + + case L_if: + case L_ifdef: + case L_ifndef: + if (++ifptr >= &ifstack[BLK_NEST]) +if_nest_err: cfatal("Too many nested #%s statements", token); + *ifptr = WAS_COMPILING; + doif(hash); + break; + + case L_endif: + if (ifptr == &ifstack[0]) { +nest_err: cerror("#%s must be in an #if", token); + goto dump_line; + } + if (!compiling && (*ifptr & WAS_COMPILING) != 0) + wrongline = TRUE; + compiling = ((*ifptr & WAS_COMPILING) != 0); + --ifptr; + break; + + case L_assert: + if (eval() == 0) + cerror("Preprocessor assertion failure", NULLST); + break; + + case L_pragma: + /* + * #pragma is provided to pass "options" to later + * passes of the compiler. cpp doesn't have any yet. + */ + fprintf( pCppOut, "#pragma "); + while ((c = get()) != '\n' && c != EOF_CHAR) + cput(c); + unget(); + break; + +#if OSL_DEBUG_LEVEL > 1 + case L_debug: + if (debug == 0) + dumpdef("debug set on"); + debug++; + break; + + case L_nodebug: + debug--; + break; +#endif + case L_error: /* BP 5.3.92, #error */ + { + fprintf( pCppOut, "cpp: line %u, Error directive: ", line ); + while ((c = get()) != '\n' && c != EOF_CHAR) + cput(c); + fprintf( pCppOut, "\n" ); + exit( 1 ); + 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. + */ + cerror("Illegal # command \"%s\"", token); + break; + } + if (hash != L_include) { +#if OLD_PREPROCESSOR + /* + * Ignore the rest of the #control line so you can write + * #if foo + * #endif foo + */ + goto dump_line; /* Take common exit */ +#else + if (skipws() != '\n') { + cwarn("Unexpected text in #control line ignored", NULLST); + skipnl(); + } +#endif + } + return (counter + 1); +} + +FILE_LOCAL +void doif(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. + */ +{ + register int c; + register int found; + + if ((c = skipws()) == '\n' || c == EOF_CHAR) { + unget(); + goto badif; + } + if (hash == L_if) { + unget(); + found = (eval() != 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 */ + goto badif; /* ... is an error */ + found = (lookid(c) != NULL); /* Look for it in symbol table */ + } + if (found == (hash == L_ifdef)) { + compiling = TRUE; + *ifptr |= TRUE_SEEN; + } + else { + compiling = FALSE; + } + return; + +badif: cerror("#if, #ifdef, or #ifndef without an argument", NULLST); +#if !OLD_PREPROCESSOR + skipnl(); /* Prevent an extra */ + unget(); /* Error message */ +#endif + return; +} + +FILE_LOCAL +void doinclude() +/* + * 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 <file>. + * #include <file> Search in an implementation-dependent + * list of places. + * #include token Expand the token, it must be one of + * "file" or <file>, process as such. + * + * Note: the November 12 draft forbids '>' in the #include <file> format. + * This restriction is unnecessary and not implemented. + */ +{ + register int c; + register int delim; +#if HOST == SYS_VMS + char def_filename[NAM$C_MAXRSS + 1]; +#endif + + delim = macroid(skipws()); + if (delim != '<' && delim != '"') + goto incerr; + if (delim == '<') + delim = '>'; + workp = work; + instring = TRUE; /* Accept all characters */ +#ifdef CONTROL_COMMENTS_NOT_ALLOWED + while ((c = get()) != '\n' && c != EOF_CHAR) + save(c); /* Put it away. */ + unget(); /* Force nl after includee */ + /* + * The draft is unclear if the following should be done. + */ + while (--workp >= work && *workp == ' ') + ; /* Trim blanks from filename */ + if (*workp != delim) + goto incerr; +#else + while ((c = get()) != delim && c != EOF_CHAR) + save(c); +#endif + *workp = EOS; /* Terminate filename */ + instring = FALSE; +#if HOST == SYS_VMS + /* + * Assume the default .h filetype. + */ + if (!vmsparse(work, ".H", def_filename)) { + perror(work); /* Oops. */ + goto incerr; + } + else if (openinclude(def_filename, (delim == '"'))) + return; +#else + if (openinclude(work, (delim == '"'))) + return; +#endif + /* + * No sense continuing if #include file isn't there. + */ + cfatal("Cannot open include file \"%s\"", work); + +incerr: cerror("#include syntax error", NULLST); + return; +} + +FILE_LOCAL int +openinclude(char* filename, int searchlocal) +/* + * 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 TRUE if the file was opened, FALSE + * if openinclude() fails. No error message is printed. + */ +{ + register char **incptr; +#if HOST == SYS_VMS +#if NFWORK < (NAM$C_MAXRSS + 1) + << error, NFWORK is not greater than NAM$C_MAXRSS >> +#endif +#endif + char tmpname[NFWORK]; /* Filename work area */ + + if (searchlocal) { + /* + * Look in local directory first + */ +#if HOST == SYS_UNIX + /* + * Try to open filename relative to the directory of the current + * source file (as opposed to the current directory). (ARF, SCK). + */ + if (filename[0] != '/' + && hasdirectory(infile->filename, tmpname)) + strcat(tmpname, filename); + else { + strcpy(tmpname, filename); + } +#else + if (!hasdirectory(filename, tmpname) + && hasdirectory(infile->filename, tmpname)) + strcat(tmpname, filename); + else { + strcpy(tmpname, filename); + } +#endif + if (openfile(tmpname)) + return (TRUE); + } + /* + * Look in any directories specified by -I command line + * arguments, then in the builtin search list. + */ + for (incptr = incdir; incptr < incend; incptr++) { + if (strlen(*incptr) + strlen(filename) >= (NFWORK - 1)) + cfatal("Filename work buffer overflow", NULLST); + else { +#if HOST == SYS_UNIX + if (filename[0] == '/') + strcpy(tmpname, filename); + else { + sprintf(tmpname, "%s/%s", *incptr, filename); + } +#elif HOST == SYS_UNKNOWN + if (filename[0] == '\\') + strcpy(tmpname, filename); + else { + sprintf(tmpname, "%s\\%s", *incptr, filename); + } +#else + if (!hasdirectory(filename, tmpname)) + sprintf(tmpname, "%s%s", *incptr, filename); +#endif + if (openfile(tmpname)) + return (TRUE); + } + } + return (FALSE); +} + +FILE_LOCAL int +hasdirectory(char* source, char* result) +/* + * 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. + */ +{ +#if HOST == SYS_UNIX + register char *tp; + + if ((tp = strrchr(source, '/')) == NULL) + return (FALSE); + else { + strncpy(result, source, tp - source + 1); + result[tp - source + 1] = EOS; + return (TRUE); + } +#else +#if HOST == SYS_VMS + if (vmsparse(source, NULLST, result) + && result[0] != EOS) + return (TRUE); + else { + return (FALSE); + } +#else + /* + * Random DEC operating system (RSX, RT11, RSTS/E) + */ + register char *tp; + + if ((tp = strrchr(source, ']')) == NULL + && (tp = strrchr(source, ':')) == NULL) + return (FALSE); + else { + strncpy(result, source, tp - source + 1); + result[tp - source + 1] = EOS; + return (TRUE); + } +#endif +#endif +} + +#if HOST == SYS_VMS + +/* + * EXP_DEV is set if a device was specified, EXP_DIR if a directory + * is specified. (Both set indicate a file-logical, but EXP_DEV + * would be set by itself if you are reading, say, SYS$INPUT:) + */ +#define DEVDIR (NAM$M_EXP_DEV | NAM$M_EXP_DIR) + +FILE_LOCAL int +vmsparse(source, defstring, result) +char *source; +char *defstring; /* non-NULL -> default string. */ +char *result; /* Size is at least NAM$C_MAXRSS + 1 */ +/* + * Parse the source string, applying the default (properly, using + * the system parse routine), storing it in result. + * TRUE if it parsed, FALSE on error. + * + * If defstring is NULL, there are no defaults and result gets + * (just) the node::[directory] part of the string (possibly "") + */ +{ + struct FAB fab = cc$rms_fab; /* File access block */ + struct NAM nam = cc$rms_nam; /* File name block */ + char fullname[NAM$C_MAXRSS + 1]; + register char *rp; /* Result pointer */ + + fab.fab$l_nam = &nam; /* fab -> nam */ + fab.fab$l_fna = source; /* Source filename */ + fab.fab$b_fns = strlen(source); /* Size of source */ + fab.fab$l_dna = defstring; /* Default string */ + if (defstring != NULLST) + fab.fab$b_dns = strlen(defstring); /* Size of default */ + nam.nam$l_esa = fullname; /* Expanded filename */ + nam.nam$b_ess = NAM$C_MAXRSS; /* Expanded name size */ + if (sys$parse(&fab) == RMS$_NORMAL) { /* Parse away */ + fullname[nam.nam$b_esl] = EOS; /* Terminate string */ + result[0] = EOS; /* Just in case */ + rp = &result[0]; + /* + * Remove stuff added implicitly, accepting node names and + * dev:[directory] strings (but not process-permanent files). + */ + if ((nam.nam$l_fnb & NAM$M_PPF) == 0) { + if ((nam.nam$l_fnb & NAM$M_NODE) != 0) { + strncpy(result, nam.nam$l_node, nam.nam$b_node); + rp += nam.nam$b_node; + *rp = EOS; + } + if ((nam.nam$l_fnb & DEVDIR) == DEVDIR) { + strncpy(rp, nam.nam$l_dev, nam.nam$b_dev + nam.nam$b_dir); + rp += nam.nam$b_dev + nam.nam$b_dir; + *rp = EOS; + } + } + if (defstring != NULLST) { + strncpy(rp, nam.nam$l_name, nam.nam$b_name + nam.nam$b_type); + rp += nam.nam$b_name + nam.nam$b_type; + *rp = EOS; + if ((nam.nam$l_fnb & NAM$M_EXP_VER) != 0) { + strncpy(rp, nam.nam$l_ver, nam.nam$b_ver); + rp[nam.nam$b_ver] = EOS; + } + } + return (TRUE); + } + return (FALSE); +} +#endif + diff --git a/rsc/source/rscpp/cpp3.c b/rsc/source/rscpp/cpp3.c new file mode 100644 index 000000000000..e9c03cdd4874 --- /dev/null +++ b/rsc/source/rscpp/cpp3.c @@ -0,0 +1,601 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#if defined(_MSC_VER) && (_MSC_VER > 1310) +#define _USE_32BIT_TIME_T +#endif + +#include <stdio.h> +#ifdef UNX +#include <stdlib.h> +#endif +#include <ctype.h> +#include "cppdef.h" +#include "cpp.h" + +#include "time.h" /* BP */ + +#ifndef _STRING_H +#include <string.h> +#endif + +#ifndef _NO_PROTO +int AddInclude( char *pIncStr ); /* BP, 11.09.91, Forward-Deklaration */ +#endif + +#if (OSL_DEBUG_LEVEL > 1) && (HOST == SYS_VMS || HOST == SYS_UNIX) +#include <signal.h> +#endif + +void InitCpp3() +{ +} + + +int +openfile(char* filename) +/* + * Open a file, add it to the linked list of open files. + * This is called only from openfile() above. + */ +{ + register FILE *fp; + + if ((fp = fopen(filename, "r")) == NULL) { +#if OSL_DEBUG_LEVEL > 1 + if ( debug || !bDumpDefs ) + perror(filename); +#endif + return (FALSE); + } +#if OSL_DEBUG_LEVEL > 1 + if (debug) + fprintf(stderr, "Reading from \"%s\"\n", filename); +#endif + addfile(fp, filename); + return (TRUE); +} + +void addfile(FILE* fp, char* filename) +/* + * 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.) + */ +{ + register FILEINFO *file; +/* #ifndef _NO_PROTO */ + extern FILEINFO *getfile( int bufsize, char *filename ); /* BP */ +/* #endif */ + file = getfile(NBUFF, filename); + file->fp = fp; /* Better remember FILE * */ + file->buffer[0] = EOS; /* Initialize for first read */ + line = 1; /* Working on line 1 now */ + wrongline = TRUE; /* Force out initial #line */ +} + +void setincdirs() +/* + * Append system-specific directories to the include directory list. + * Called only when cpp is started. + */ +{ + +#ifdef CPP_INCLUDE + *incend++ = CPP_INCLUDE; +#define IS_INCLUDE 1 +#else +#define IS_INCLUDE 0 +#endif + +#if HOST == SYS_UNIX + *incend++ = "/usr/include"; +#define MAXINCLUDE (NINCLUDE - 1 - IS_INCLUDE) +#endif + +#if HOST == SYS_VMS + extern char *getenv(); + + if (getenv("C$LIBRARY") != NULL) + *incend++ = "C$LIBRARY:"; + *incend++ = "SYS$LIBRARY:"; +#define MAXINCLUDE (NINCLUDE - 2 - IS_INCLUDE) +#endif + +#if HOST == SYS_RSX + extern int $$rsts; /* TRUE on RSTS/E */ + extern int $$pos; /* TRUE on PRO-350 P/OS */ + extern int $$vms; /* TRUE on VMS compat. */ + + if ($$pos) { /* P/OS? */ + *incend++ = "SY:[ZZDECUSC]"; /* C #includes */ + *incend++ = "LB:[1,5]"; /* RSX library */ + } + else if ($$rsts) { /* RSTS/E? */ + *incend++ = "SY:@"; /* User-defined account */ + *incend++ = "C:"; /* Decus-C library */ + *incend++ = "LB:[1,1]"; /* RSX library */ + } + else if ($$vms) { /* VMS compatibility? */ + *incend++ = "C:"; + } + else { /* Plain old RSX/IAS */ + *incend++ = "LB:[1,1]"; + } +#define MAXINCLUDE (NINCLUDE - 3 - IS_INCLUDE) +#endif + +#if HOST == SYS_RT11 + extern int $$rsts; /* RSTS/E emulation? */ + + if ($$rsts) + *incend++ = "SY:@"; /* User-defined account */ + *incend++ = "C:"; /* Decus-C library disk */ + *incend++ = "SY:"; /* System (boot) disk */ +#define MAXINCLUDE (NINCLUDE - 3 - IS_INCLUDE) +#endif + +#if HOST == SYS_UNKNOWN +/* + * BP: 25.07.91, Kontext: GenMake + * Unter DOS wird nun auch die Environment-Variable INCLUDE ausgewetet. + * Es kommt erschwerend hinzu, dass alle Eintraege, die mit ';' getrennt + * sind, mit in die Liste aufenommen werden muessen. + * Dies wird mit der Funktion strtok() realisiert. + * Vorsicht bei der Benutzung von malloc !!! + * In savestring wird naemlich getmem() verwendet. Vermutlich kommen sich + * die beiden Funktion in die Quere. Als ich malloc statt savestring + * verwendete knallte es in strcpy() ! + */ + +#if !defined( ZTC ) && !defined( WNT ) && !defined(BLC) && ! defined UNX && ! defined OS2 + extern char *getenv( char *pStr ); /* BP */ +#endif + char *pIncGetEnv = NULL; /* Pointer auf INCLUDE */ + + if ( ( pIncGetEnv = getenv("INCLUDE") ) != NULL ) + AddInclude( pIncGetEnv ); + +#define MAXINCLUDE (NINCLUDE - 3 - IS_INCLUDE) +#endif + + +} + +/* BP: 11.09.91, Kontext: Erweiterung des INCLUDE-Services + * Bislang konnte der cpp keine Include-Angaben in der Kommandozeile + * vertragen, bei denen die directries mit ';' getrennt wurden. + * Dies ist auch verstaendlich, da dieses cpp fuer UNIX-Systeme + * massgeschneidert wurde und in UNI die ';' als Zeichen zum Abschluss + * von Kommandos gilt. + */ + +int AddInclude( char* pIncStr ) +{ + char *pIncEnv = NULL; /* Kopie des INCLUDE */ + char *pIncPos; /* wandert zum naechsten */ + + pIncEnv = savestring( pIncStr ); + pIncPos = strtok( pIncEnv, ";" ); + + while( pIncPos != NULL ) + { + if (incend >= &incdir[MAXINCLUDE]) + cfatal("Too many include directories", NULLST); + *incend++ = pIncPos; + pIncPos = strtok( NULL, ";" ); + } + return( 1 ); +} + + + + +int +dooptions(int argc, char** argv) +/* + * dooptions is called to process command line arguments (-Detc). + * It is called only at cpp startup. + */ +{ + register char *ap; + register DEFBUF *dp; + register int c; + int i, j; + char *arg; + SIZES *sizp; /* For -S */ + int size; /* For -S */ + int isdatum; /* FALSE for -S* */ + int endtest; /* For -S */ + + for (i = j = 1; i < argc; i++) { + arg = ap = argv[i]; + + if (*ap++ != '-' || *ap == EOS) + { + argv[j++] = argv[i]; + } + else { + c = *ap++; /* Option byte */ + if (islower(c)) /* Normalize case */ + c = toupper(c); + switch (c) { /* Command character */ + case 'C': /* Keep comments */ + cflag = TRUE; + keepcomments = TRUE; + break; + + case 'D': /* Define symbol */ +#if HOST != SYS_UNIX +/* zap_uc(ap); */ /* Force define to U.C. */ +#endif + /* + * If the option is just "-Dfoo", make it -Dfoo=1 + */ + while (*ap != EOS && *ap != '=') + ap++; + if (*ap == EOS) + ap = "1"; + else + *ap++ = EOS; + /* + * Now, save the word and its definition. + */ + dp = defendel(argv[i] + 2, FALSE); + dp->repl = savestring(ap); + dp->nargs = DEF_NOARGS; + break; + + case 'E': /* Ignore non-fatal */ + eflag = TRUE; /* errors. */ + break; + + case 'I': /* Include directory */ + AddInclude( ap ); /* BP, 11.09.91 */ + break; + + case 'N': /* No predefineds */ + nflag++; /* Repeat to undefine */ + break; /* __LINE__, etc. */ + + case 'S': + sizp = size_table; + if (0 != (isdatum = (*ap != '*'))) /* If it's just -S, */ + endtest = T_FPTR; /* Stop here */ + else { /* But if it's -S* */ + ap++; /* Step over '*' */ + endtest = 0; /* Stop at end marker */ + } + while (sizp->bits != endtest && *ap != EOS) { + if (!isdigit(*ap)) { /* Skip to next digit */ + ap++; + continue; + } + size = 0; /* Compile the value */ + while (isdigit(*ap)) { + size *= 10; + size += (*ap++ - '0'); + } + if (isdatum) + sizp->size = size; /* Datum size */ + else + sizp->psize = size; /* Pointer size */ + sizp++; + } + if (sizp->bits != endtest) + cwarn("-S, too few values specified in %s", argv[i]); + else if (*ap != EOS) + cwarn("-S, too many values, \"%s\" unused", ap); + break; + + case 'U': /* Undefine symbol */ +#if HOST != SYS_UNIX +/* zap_uc(ap);*/ +#endif + if (defendel(ap, TRUE) == NULL) + cwarn("\"%s\" wasn't defined", ap); + break; + +#if OSL_DEBUG_LEVEL > 1 + case 'X': /* Debug */ + debug = (isdigit(*ap)) ? atoi(ap) : 1; +#if (HOST == SYS_VMS || HOST == SYS_UNIX) + signal(SIGINT, (void (*)(int)) abort); /* Trap "interrupt" */ +#endif + fprintf(stderr, "Debug set to %d\n", debug); + break; +#endif + +#if OSL_DEBUG_LEVEL > 1 + case 'P': /* #define's dump */ + bDumpDefs = 1; + fprintf(stderr, "Dump #define's is on\n"); + break; +#endif + + default: /* What is this one? */ + cwarn("Unknown option \"%s\"", arg); + fprintf(stderr, "The following options are valid:\n\ + -C\t\t\tWrite source file comments to output\n\ + -Dsymbol=value\tDefine a symbol with the given (optional) value\n\ + -Idirectory\t\tAdd a directory to the #include search list\n\ + -N\t\t\tDon't predefine target-specific names\n\ + -Stext\t\tSpecify sizes for #if sizeof\n\ + -Usymbol\t\tUndefine symbol\n"); +#if OSL_DEBUG_LEVEL > 1 + fprintf(stderr, " -Xvalue\t\tSet internal debug flag\n"); + fprintf(stderr, " -P\t\t\tdump #define's\n"); +#endif + break; + } /* Switch on all options */ + } /* If it's a -option */ + } /* For all arguments */ +#if OSL_DEBUG_LEVEL > 1 + if ( (bDumpDefs ? j > 4 : j > 3) ) { +#else + if (j > 3) { +#endif + cerror( + "Too many file arguments. Usage: cpp [input [output]]", + NULLST); + } + return (j); /* Return new argc */ +} + +int +readoptions(char* filename, char*** pfargv) +{ + FILE *fp; + int c; + int bInQuotes = 0; + char optbuff[1024], *poptbuff; + int fargc=0, back; + char *fargv[PARALIMIT], **pfa; + + pfa=*pfargv=malloc(sizeof(fargv)); + + poptbuff=&optbuff[0]; + filename++; + if ((fp = fopen(filename, "r")) == NULL) { +#if OSL_DEBUG_LEVEL > 1 + if ( debug || !bDumpDefs ) + perror(filename); +#endif + return (FALSE); + } + do + { + /* + * #i27914# double ticks '"' now have a duplicate function: + * 1. they define a string ( e.g. -DFOO="baz" ) + * 2. a string can contain spaces, so -DFOO="baz zum" defines one + * argument no two ! + */ + c=fgetc(fp); + if ( c != ' ' && c != CR && c != NL && c != HT && c != EOF) + { + *poptbuff++=(char)c; + if( c == '"' ) + bInQuotes = ~bInQuotes; + } + else + { + if( c != EOF && bInQuotes ) + *poptbuff++=(char)c; + else + { + *poptbuff=EOS; + if (strlen(optbuff)>0) + { + pfa[fargc+1]=malloc(strlen(optbuff)+1); + strcpy(pfa[fargc+1],optbuff); + fargc++; + pfa[fargc+1]=0; + poptbuff=&optbuff[0]; + } + } + } + } + while ( c != EOF ); + + fclose(fp); + back=dooptions(fargc+1,pfa); + + return (back); +} + + + +#if HOST != SYS_UNIX +FILE_LOCAL void +zap_uc(char* ap) +/* + * Dec operating systems mangle upper-lower case in command lines. + * This routine forces the -D and -U arguments to uppercase. + * It is called only on cpp startup by dooptions(). + */ +{ + while (*ap != EOS) { + /* + * Don't use islower() here so it works with Multinational + */ + if (*ap >= 'a' && *ap <= 'z') + *ap = (char)toupper(*ap); + ap++; + } +} +#endif + +void initdefines() +/* + * 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__, and __DATE__ are always present. + */ +{ + register char **pp; + register char *tp; + register DEFBUF *dp; + int i; + long tvec; + +#if !defined( ZTC ) && !defined( WNT ) && !defined(BLC) && !defined(G3) + extern char *ctime(); +#endif + + /* + * Predefine the built-in symbols. Allow the + * implementor to pre-define a symbol as "" to + * eliminate it. + */ + if (nflag == 0) { + for (pp = preset; *pp != NULL; pp++) { + if (*pp[0] != EOS) { + dp = defendel(*pp, FALSE); + dp->repl = savestring("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 (nflag < 2) { + for (pp = magic, i = DEF_NOARGS; *pp != NULL; pp++) { + dp = defendel(*pp, FALSE); + dp->nargs = --i; + } +#if OK_DATE + /* + * Define __DATE__ as today's date. + */ + dp = defendel("__DATE__", FALSE); + dp->repl = tp = getmem(27); + dp->nargs = DEF_NOARGS; + time( (time_t*)&tvec); + *tp++ = '"'; + strcpy(tp, ctime((const time_t*)&tvec)); + tp[24] = '"'; /* Overwrite newline */ +#endif + } +} + +#if HOST == SYS_VMS +/* + * getredirection() is intended to aid in porting C programs + * to VMS (Vax-11 C) which does not support '>' and '<' + * I/O redirection. With suitable modification, it may + * useful for other portability problems as well. + */ + +int +getredirection(argc, argv) +int argc; +char **argv; +/* + * Process vms redirection arg's. Exit if any error is seen. + * If getredirection() processes an argument, it is erased + * from the vector. getredirection() returns a new argc value. + * + * Warning: do not try to simplify the code for vms. The code + * presupposes that getredirection() is called before any data is + * read from stdin or written to stdout. + * + * Normal usage is as follows: + * + * main(argc, argv) + * int argc; + * char *argv[]; + * { + * argc = getredirection(argc, argv); + * } + */ +{ + register char *ap; /* Argument pointer */ + int i; /* argv[] index */ + int j; /* Output index */ + int file; /* File_descriptor */ + extern int errno; /* Last vms i/o error */ + + for (j = i = 1; i < argc; i++) { /* Do all arguments */ + switch (*(ap = argv[i])) { + case '<': /* <file */ + if (freopen(++ap, "r", stdin) == NULL) { + perror(ap); /* Can't find file */ + exit(errno); /* Is a fatal error */ + } + break; + + case '>': /* >file or >>file */ + if (*++ap == '>') { /* >>file */ + /* + * If the file exists, and is writable by us, + * call freopen to append to the file (using the + * file's current attributes). Otherwise, create + * a new file with "vanilla" attributes as if the + * argument was given as ">filename". + * access(name, 2) returns zero if we can write on + * the specified file. + */ + if (access(++ap, 2) == 0) { + if (freopen(ap, "a", stdout) != NULL) + break; /* Exit case statement */ + perror(ap); /* Error, can't append */ + exit(errno); /* After access test */ + } /* If file accessable */ + } + /* + * On vms, we want to create the file using "standard" + * record attributes. creat(...) creates the file + * using the caller's default protection mask and + * "variable length, implied carriage return" + * attributes. dup2() associates the file with stdout. + */ + if ((file = creat(ap, 0, "rat=cr", "rfm=var")) == -1 + || dup2(file, fileno(stdout)) == -1) { + perror(ap); /* Can't create file */ + exit(errno); /* is a fatal error */ + } /* If '>' creation */ + break; /* Exit case test */ + + default: + argv[j++] = ap; /* Not a redirector */ + break; /* Exit case test */ + } + } /* For all arguments */ + argv[j] = NULL; /* Terminate argv[] */ + return (j); /* Return new argc */ +} +#endif diff --git a/rsc/source/rscpp/cpp4.c b/rsc/source/rscpp/cpp4.c new file mode 100644 index 000000000000..b8f90ab4f7ed --- /dev/null +++ b/rsc/source/rscpp/cpp4.c @@ -0,0 +1,635 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <stdio.h> +#include <ctype.h> +#include "cppdef.h" +#include "cpp.h" +/* + * parm[], parmp, and parlist[] are used to store #define() argument + * lists. nargs contains the actual number of parameters stored. + */ +static char parm[NPARMWORK + 1]; /* define param work buffer */ +static char *parmp; /* Free space in parm */ +static char *parlist[LASTPARM]; /* -> start of each parameter */ +static int nargs; /* Parameters for this macro */ + +void InitCpp4() +{ + int i; + for( i = 0; i < NPARMWORK; i++ ) + parm[ i ] = 0; + for( i = 0; i < LASTPARM; i++ ) + parlist[ i ] = NULL; + + nargs = 0; +} + + +void dodefine() +/* + * 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(). + */ +{ + register int c; + register DEFBUF *dp; /* -> new definition */ + int isredefine; /* TRUE if redefined */ + char *old = 0; /* Remember redefined */ + + if (type[(c = skipws())] != LET) + goto bad_define; + isredefine = FALSE; /* Set if redefining */ + if ((dp = lookid(c)) == NULL) /* If not known now */ + dp = defendel(token, FALSE); /* Save the name */ + else { /* It's known: */ + isredefine = TRUE; /* Remember this fact */ + old = dp->repl; /* Remember replacement */ + dp->repl = NULL; /* No replacement now */ + } + parlist[0] = parmp = parm; /* Setup parm buffer */ + if ((c = get()) == '(') { /* With arguments? */ + nargs = 0; /* Init formals counter */ + do { /* Collect formal parms */ + if (nargs >= LASTPARM) + cfatal("Too many arguments for macro", NULLST); + else if ((c = skipws()) == ')') + break; /* Got them all */ + else if (type[c] != LET) /* Bad formal syntax */ + goto bad_define; + scanid(c); /* Get the formal param */ + parlist[nargs++] = parmp; /* Save its start */ + textput(token); /* Save text in parm[] */ + } while ((c = skipws()) == ','); /* Get another argument */ + if (c != ')') /* Must end at ) */ + goto bad_define; + c = ' '; /* Will skip to body */ + } + else { + /* + * DEF_NOARGS is needed to distinguish between + * "#define foo" and "#define foo()". + */ + nargs = DEF_NOARGS; /* No () parameters */ + } + if (type[c] == SPA) /* At whitespace? */ + c = skipws(); /* Not any more. */ + workp = work; /* Replacement put here */ + inmacro = TRUE; /* Keep \<newline> now */ + while (c != EOF_CHAR && c != '\n') { /* Compile macro body */ +#if OK_CONCAT +#if COMMENT_INVISIBLE + if (c == COM_SEP) { /* Token concatenation? */ + save(TOK_SEP); /* Stuff a delimiter */ + c = get(); +#else + if (c == '#') { /* Token concatenation? */ + while (workp > work && type[(int)workp[-1]] == SPA) + --workp; /* Erase leading spaces */ + save(TOK_SEP); /* Stuff a delimiter */ + c = skipws(); /* Eat whitespace */ +#endif + if (type[c] == LET) /* Another token here? */ + ; /* Stuff it normally */ + else if (type[c] == DIG) { /* Digit string after? */ + while (type[c] == DIG) { /* Stuff the digits */ + save(c); + c = get(); + } + save(TOK_SEP); /* Delimit 2nd token */ + } + else { +#if ! COMMENT_INVISIBLE + ciwarn("Strange character after # (%d.)", c); +#endif + } + continue; + } +#endif + switch (type[c]) { + case LET: + checkparm(c, dp); /* Might be a formal */ + break; + + case DIG: /* Number in mac. body */ + case DOT: /* Maybe a float number */ + scannumber(c, save); /* Scan it off */ + break; + + case QUO: /* String in mac. body */ +#if STRING_FORMAL + stparmscan(c, dp); /* Do string magic */ +#else + stparmscan(c); +#endif + break; + + case BSH: /* Backslash */ + save('\\'); + if ((c = get()) == '\n') + wrongline = TRUE; + save(c); + break; + + case SPA: /* Absorb whitespace */ + /* + * Note: the "end of comment" marker is passed on + * to allow comments to separate tokens. + */ + if (workp[-1] == ' ') /* Absorb multiple */ + break; /* spaces */ + else if (c == '\t') + c = ' '; /* Normalize tabs */ + /* Fall through to store character */ + default: /* Other character */ + save(c); + break; + } + c = get(); + } + inmacro = FALSE; /* Stop newline hack */ + unget(); /* For control check */ + if (workp > work && workp[-1] == ' ') /* Drop trailing blank */ + workp--; + *workp = EOS; /* Terminate work */ + dp->repl = savestring(work); /* Save the string */ + dp->nargs = nargs; /* Save arg count */ +#if OSL_DEBUG_LEVEL > 1 + if (debug) + dumpadef("macro definition", dp); + else if (bDumpDefs) + dumpadef(NULL, dp); +#endif + 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)) { +#ifdef STRICT_UNDEF + cerror("Redefining defined variable \"%s\"", dp->name); +#else + cwarn("Redefining defined variable \"%s\"", dp->name); +#endif + } + if (old != NULL) /* We don't need the */ + free(old); /* old definition now. */ + } + return; + +bad_define: + cerror("#define syntax error", NULLST); + inmacro = FALSE; /* Stop <newline> hack */ +} + +void checkparm(int c, DEFBUF* dp) +/* + * 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". + */ +{ + register int i; + register char *cp; + + scanid(c); /* Get parm to token[] */ + for (i = 0; i < nargs; i++) { /* For each argument */ + if (streq(parlist[i], token)) { /* If it's known */ +#ifdef SOLAR + save(DEL); +#endif + save(i + MAC_PARM); /* Save a magic cookie */ + return; /* And exit the search */ + } + } + if (streq(dp->name, token)) /* Macro name in body? */ + save(DEF_MAGIC); /* Save magic marker */ + for (cp = token; *cp != EOS;) /* And save */ + save(*cp++); /* The token itself */ +} + +#if STRING_FORMAL +void stparmscan(delim, dp) +int delim; +register DEFBUF *dp; +/* + * Scan the string (starting with the given delimiter). + * The token is replaced if it is the only text in this string or + * character constant. The algorithm follows checkparm() above. + * Note that scanstring() has approved of the string. + */ +{ + register int c; + + /* + * Warning -- this code hasn't been tested for a while. + * It exists only to preserve compatibility with earlier + * implementations of cpp. It is not part of the Draft + * ANSI Standard C language. + */ + save(delim); + instring = TRUE; + while ((c = get()) != delim + && c != '\n' + && c != EOF_CHAR) { + if (type[c] == LET) /* Maybe formal parm */ + checkparm(c, dp); + else { + save(c); + if (c == '\\') + save(get()); + } + } + instring = FALSE; + if (c != delim) + cerror("Unterminated string in macro body", NULLST); + save(c); +} +#else +void stparmscan(int delim) +/* + * Normal string parameter scan. + */ +{ + register char *wp; + register int i; + + wp = workp; /* Here's where it starts */ + if (!scanstring(delim, save)) + return; /* Exit on scanstring error */ + workp[-1] = EOS; /* Erase trailing quote */ + wp++; /* -> first string content byte */ + for (i = 0; i < nargs; i++) { + if (streq(parlist[i], wp)) { +#ifdef SOLAR + *wp++ = DEL; + *wp++ = MAC_PARM + PAR_MAC; /* Stuff a magic marker */ + *wp++ = (char)(i + MAC_PARM); /* Make a formal marker */ + *wp = wp[-4]; /* Add on closing quote */ + workp = wp + 1; /* Reset string end */ +#else + *wp++ = MAC_PARM + PAR_MAC; /* Stuff a magic marker */ + *wp++ = (i + MAC_PARM); /* Make a formal marker */ + *wp = wp[-3]; /* Add on closing quote */ + workp = wp + 1; /* Reset string end */ +#endif + return; + } + } + workp[-1] = wp[-1]; /* Nope, reset end quote. */ +} +#endif + +void doundef() +/* + * Remove the symbol from the defined list. + * Called from the #control processor. + */ +{ + register int c; + + if (type[(c = skipws())] != LET) + cerror("Illegal #undef argument", NULLST); + else { + scanid(c); /* Get name to token[] */ + if (defendel(token, TRUE) == NULL) { +#ifdef STRICT_UNDEF + cwarn("Symbol \"%s\" not defined in #undef", token); +#endif + } + } +} + +void textput(char* text) +/* + * Put the string in the parm[] buffer. + */ +{ + register int size; + + size = strlen(text) + 1; + if ((parmp + size) >= &parm[NPARMWORK]) + cfatal("Macro work area overflow", NULLST); + else { + strcpy(parmp, text); + parmp += size; + } +} + +void charput(int c) +/* + * Put the byte in the parm[] buffer. + */ +{ + if (parmp >= &parm[NPARMWORK]) + cfatal("Macro work area overflow", NULLST); + else { + *parmp++ = (char)c; + } +} + +/* + * M a c r o E x p a n s i o n + */ + +static DEFBUF *macro; /* Catches start of infinite macro */ + +void expand(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.) + */ +{ + register int c; + register FILEINFO *file; +#ifndef ZTC /* BP */ + extern FILEINFO *getfile(); +#endif + +#if OSL_DEBUG_LEVEL > 1 + if (debug) + dumpadef("expand entry", tokenp); +#endif + /* + * If no macro is pending, save the name of this macro + * for an eventual error message. + */ + if (recursion++ == 0) + macro = tokenp; + else if (recursion == RECURSION_LIMIT) { + cerror("Recursive macro definition of \"%s\"", tokenp->name); + fprintf(stderr, "(Defined by \"%s\")\n", macro->name); + if (rec_recover) { + do { + c = get(); + } while (infile != NULL && infile->fp == NULL); + unget(); + recursion = 0; + return; + } + } + /* + * Here's a macro to expand. + */ + nargs = 0; /* Formals counter */ + parmp = parm; /* Setup parm buffer */ + switch (tokenp->nargs) { + case (-2): /* __LINE__ */ + sprintf(work, "%d", line); + ungetstring(work); + break; + + case (-3): /* __FILE__ */ + for (file = infile; file != NULL; file = file->parent) { + if (file->fp != NULL) { + sprintf(work, "\"%s\"", (file->progname != NULL) + ? file->progname : file->filename); + ungetstring(work); + break; + } + } + break; + + default: + /* + * Nothing funny about this macro. + */ + if (tokenp->nargs < 0) + cfatal("Bug: Illegal __ macro \"%s\"", tokenp->name); + while ((c = skipws()) == '\n') /* Look for (, skipping */ + wrongline = TRUE; /* spaces and newlines */ + if (c != '(') { + /* + * If the programmer writes + * #define foo() ... + * ... + * foo [no ()] + * just write foo to the output stream. + */ + unget(); + cwarn("Macro \"%s\" needs arguments", tokenp->name); + fputs(tokenp->name, pCppOut ); + return; + } + else if (expcollect()) { /* Collect arguments */ + if (tokenp->nargs != nargs) { /* Should be an error? */ + cwarn("Wrong number of macro arguments for \"%s\"", + tokenp->name); + } +#if OSL_DEBUG_LEVEL > 1 + if (debug) + dumpparm("expand"); +#endif + } /* Collect arguments */ + case DEF_NOARGS: /* No parameters just stuffs */ + expstuff(tokenp); /* Do actual parameters */ + } /* nargs switch */ +} + +FILE_LOCAL int +expcollect() +/* + * Collect the actual parameters for this macro. TRUE if ok. + */ +{ + register int c; + register int paren; /* For embedded ()'s */ + for (;;) { + paren = 0; /* Collect next arg. */ + while ((c = skipws()) == '\n') /* Skip over whitespace */ + 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. + */ + *parmp = EOS; /* Make sure terminated */ + break; /* Exit collection loop */ + } + else if (nargs >= LASTPARM) + cfatal("Too many arguments in macro expansion", NULLST); + parlist[nargs++] = parmp; /* At start of new arg */ + for (;; c = cget()) { /* Collect arg's bytes */ + if (c == EOF_CHAR) { + cerror("end of file within macro argument", NULLST); + return (FALSE); /* Sorry. */ + } + else if (c == '\\') { /* Quote next character */ + charput(c); /* Save the \ for later */ + charput(cget()); /* Save the next char. */ + continue; /* And go get another */ + } + else if (type[c] == QUO) { /* Start of string? */ + scanstring(c, charput); /* Scan it off */ + 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(); /* 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? */ + wrongline = TRUE; /* We'll need a #line */ + charput(c); /* Store this one */ + } /* Collect an argument */ + charput(EOS); /* Terminate argument */ +#if OSL_DEBUG_LEVEL > 1 + if (debug) + fprintf( pCppOut, "parm[%d] = \"%s\"\n", nargs, parlist[nargs - 1]); +#endif + } /* Collect all args. */ + return (TRUE); /* Normal return */ +} + +FILE_LOCAL +void expstuff(DEFBUF* tokenp) +/* + * Stuff the macro body, replacing formal parameters by actual parameters. + */ +{ + register int c; /* Current character */ + register char *inp; /* -> repl string */ + register 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 */ +#ifndef ZTC /* BP */ + extern FILEINFO *getfile(); +#endif + + file = getfile(NBUFF, tokenp->name); + inp = tokenp->repl; /* -> macro replacement */ + defp = file->buffer; /* -> output buffer */ + defend = defp + (NBUFF - 1); /* Note its end */ + if (inp != NULL) { + while ((c = (*inp++ & 0xFF)) != EOS) { +#ifdef SOLAR + if (c == DEL) { + c = (*inp++ & 0xFF); +#else + if (c >= MAC_PARM && c <= (MAC_PARM + PAR_MAC)) { +#endif + string_magic = (c == (MAC_PARM + PAR_MAC)); + if (string_magic) + c = (*inp++ & 0xFF); + /* + * Replace formal parameter by actual parameter string. + */ + if ((c -= MAC_PARM) < nargs) { + size = strlen(parlist[c]); + if ((defp + size) >= defend) + goto nospace; + /* + * Erase the extra set of quotes. + */ + if (string_magic && defp[-1] == parlist[c][0]) { + strcpy(defp-1, parlist[c]); + defp += (size - 2); + } + else { + strcpy(defp, parlist[c]); + defp += size; + } + } + } + else if (defp >= defend) { +nospace: cfatal("Out of space in macro \"%s\" arg expansion", + tokenp->name); + } + else { + *defp++ = (char)c; + } + } + } + *defp = EOS; +#if OSL_DEBUG_LEVEL > 1 + if (debug > 1) + fprintf( pCppOut, "macroline: \"%s\"\n", file->buffer); +#endif +} + +#if OSL_DEBUG_LEVEL > 1 +void dumpparm(char* why) +/* + * Dump parameter list. + */ +{ + register int i; + + fprintf( pCppOut, "dump of %d parameters (%d bytes total) %s\n", + nargs, parmp - parm, why); + for (i = 0; i < nargs; i++) { + fprintf( pCppOut, "parm[%d] (%d) = \"%s\"\n", + i + 1, strlen(parlist[i]), parlist[i]); + } +} +#endif diff --git a/rsc/source/rscpp/cpp5.c b/rsc/source/rscpp/cpp5.c new file mode 100644 index 000000000000..70f05543c465 --- /dev/null +++ b/rsc/source/rscpp/cpp5.c @@ -0,0 +1,929 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <stdio.h> +#include <ctype.h> +#include "cppdef.h" +#include "cpp.h" + +/* + * 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; +static int evalue; /* Current value from evallex() */ + +#ifdef nomacargs +FILE_LOCAL int +isbinary(op) +register int op; +{ + return (op >= FIRST_BINOP && op <= LAST_BINOP); +} + +FILE_LOCAL int +isunary(op) +register 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. + */ + +#ifndef S_CHAR +#define S_CHAR (sizeof (char)) +#endif +#ifndef S_SINT +#define S_SINT (sizeof (short int)) +#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 +#define S_PSINT (sizeof (short int *)) +#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 */ +}; + + +void InitCpp5() +{ + +} + + + +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. + */ +{ + register int op; /* Current operator */ + register int *valp; /* -> value vector */ + register 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 */ +#ifndef ZTC /* BP */ + extern int *evaleval(); /* Does actual evaluation */ +#endif + 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; +again: ; +#ifdef DEBUG_EVAL + fprintf( pCppOut, "In #if at again: skip = %d, binop = %d, line is: %s", + opp->skip, binop, infile->bptr); +#endif + if ((op = evallex(opp->skip)) == 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) + return (1); /* Error in evallex */ +#ifdef DEBUG_EVAL + fprintf( pCppOut, "op = %s, opdope = %03o, binop = %d, skip = %d\n", + opname[op], opdope[op], binop, opp->skip); +#endif + if (op == DIG) { /* Value? */ + if (binop != 0) { + cerror("misplaced constant in #if", NULLST); + return (1); + } + else if (valp >= &value[NEXP-1]) { + cerror("#if value stack overflow", NULLST); + return (1); + } + else { +#ifdef DEBUG_EVAL + fprintf( pCppOut, "pushing %d onto value stack[%d]\n", + evalue, valp - value); +#endif + *valp++ = evalue; + binop = 1; + } + goto again; + } + else if (op > OP_END) { + cerror("Illegal #if line", NULLST); + return (1); + } + prec = opdope[op]; + if (binop != (prec & 1)) { + cerror("Operator %s in incorrect context", opname[op]); + return (1); + } + binop = (prec & 2) >> 1; + for (;;) { +#ifdef DEBUG_EVAL + fprintf( pCppOut, "op %s, prec %d., stacked op %s, prec %d, skip %d\n", + opname[op], prec, opname[opp->op], opp->prec, opp->skip); +#endif + 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("expression stack overflow at op \"%s\"", + opname[op]); + return (1); + } + opp->op = (char)op; + opp->prec = (char)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 = (char)((op1 & S_ANDOR) | ((!skip) ? S_QUEST : 0)); + else if (op == OP_COL) { /* : inverts S_QUEST */ + opp->skip = (char)((op1 & S_ANDOR) + | (((op1 & S_QUEST) != 0) ? 0 : S_QUEST)); + } + else { /* Other ops leave */ + opp->skip = (char)op1; /* skipping unchanged. */ + } +#ifdef DEBUG_EVAL + fprintf( pCppOut, "stacking %s, valp[-1] == %d at %s", + opname[op], valp[-1], infile->bptr); + dumpstack(opstack, opp, value, valp); +#endif + goto again; + } + /* + * 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) + return (valp[-1]); /* Finished ok. */ + goto again; /* Read another op. */ + + case OP_LPA: /* ( on stack */ + if (op != OP_RPA) { /* Matches ) on input */ + cerror("unbalanced paren's, op is \"%s\"", opname[op]); + return (1); + } + opp--; /* Unstack it */ + /* goto again; -- Fall through */ + + case OP_QUE: + goto again; /* Evaluate true expr. */ + + case OP_COL: /* : on stack. */ + opp--; /* Unstack : */ + if (opp->op != OP_QUE) { /* Matches ? on stack? */ + cerror("Misplaced '?' or ':', previous operator is %s", + opname[(int)opp->op]); + return (1); + } + /* + * Evaluate op1. + */ + default: /* Others: */ + opp--; /* Unstack the operator */ +#ifdef DEBUG_EVAL + fprintf( pCppOut, "Stack before evaluation of %s\n", opname[op1]); + dumpstack(opstack, opp, value, valp); +#endif + valp = evaleval(valp, op1, skip); +#ifdef DEBUG_EVAL + fprintf( pCppOut, "Stack after evaluation\n"); + dumpstack(opstack, opp, value, valp); +#endif + } /* op1 switch end */ + } /* Stack unwind loop */ +} + +FILE_LOCAL int +evallex(int skip) +/* + * Return 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. + */ +{ + register int c, c1, t; + +again: do { /* Collect the token */ + c = skipws(); + if ((c = macroid(c)) == EOF_CHAR || c == '\n') { + unget(); + return (OP_EOE); /* End of expression */ + } + } while ((t = type[c]) == LET && catenate()); + if (t == INV) { /* Total nonsense */ + if (!skip) { + if (isascii(c) && isprint(c)) + cierror("illegal character '%c' in #if", c); + else + cierror("illegal character (%d decimal) in #if", c); + } + return (OP_FAIL); + } + else if (t == QUO) { /* ' or " */ + if (c == '\'') { /* Character constant */ + evalue = evalchar(skip); /* Somewhat messy */ +#ifdef DEBUG_EVAL + fprintf( pCppOut, "evalchar returns %d.\n", evalue); +#endif + return (DIG); /* Return a value */ + } + cerror("Can't use a string in an #if", NULLST); + return (OP_FAIL); + } + else if (t == LET) { /* ID must be a macro */ + if (streq(token, "defined")) { /* Or defined name */ + c1 = c = skipws(); + if (c == '(') /* Allow defined(name) */ + c = skipws(); + if (type[c] == LET) { + evalue = (lookid(c) != NULL); + if (c1 != '(' /* Need to balance */ + || skipws() == ')') /* Did we balance? */ + return (DIG); /* Parsed ok */ + } + cerror("Bad #if ... defined() syntax", NULLST); + return (OP_FAIL); + } + else if (streq(token, "sizeof")) /* New sizeof hackery */ + return (dosizeof()); /* Gets own routine */ + /* + * The Draft ANSI C Standard says that an undefined symbol + * in an #if has the value zero. We are a bit pickier, + * warning except where the programmer was careful to write + * #if defined(foo) ? foo : 0 + */ +#ifdef STRICT_UNDEF + if (!skip) + cwarn("undefined symbol \"%s\" in #if, 0 used", token); +#endif + evalue = 0; + return (DIG); + } + else if (t == DIG) { /* Numbers are harder */ + evalue = evalnum(c); +#ifdef DEBUG_EVAL + fprintf( pCppOut, "evalnum returns %d.\n", evalue); +#endif + } + else if (strchr("!=<>&|\\", c) != NULL) { + /* + * Process a possible multi-byte lexeme. + */ + c1 = cget(); /* Peek at next char */ + switch (c) { + case '!': + if (c1 == '=') + return (OP_NE); + break; + + case '=': + if (c1 != '=') { /* Can't say a=b in #if */ + unget(); + cerror("= not allowed in #if", NULLST); + return (OP_FAIL); + } + return (OP_EQ); + + case '>': + case '<': + if (c1 == c) + return ((c == '<') ? OP_ASL : OP_ASR); + else if (c1 == '=') + return ((c == '<') ? OP_LE : OP_GE); + break; + + case '|': + case '&': + if (c1 == c) + return ((c == '|') ? OP_ORO : OP_ANA); + break; + + case '\\': + if (c1 == '\n') /* Multi-line if */ + goto again; + cerror("Unexpected \\ in #if", NULLST); + return (OP_FAIL); + } + unget(); + } + return (t); +} + +FILE_LOCAL int +dosizeof() +/* + * 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. + */ +{ + register int c; + register TYPES *tp; + register SIZES *sizp; + register short *testp; + short typecode; + + if ((c = skipws()) != '(') + goto nogood; + /* + * Scan off the tokens. + */ + typecode = 0; + while (0 != (c = skipws())) { + if ((c = macroid(c)) == EOF_CHAR || c == '\n') + goto nogood; /* End of line is a bug */ + else if (c == '(') { /* thing (*)() func ptr */ + if (skipws() == '*' + && skipws() == ')') { /* We found (*) */ + if (skipws() != '(') /* Let () be optional */ + unget(); + else if (skipws() != ')') + goto nogood; + typecode |= T_FPTR; /* Function pointer */ + } + else { /* Junk is a bug */ + goto nogood; + } + } + else if (type[c] != LET) /* Exit if not a type */ + break; + else if (!catenate()) { /* 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(token, tp->name)) + break; + } + if (tp->name == NULLST) { + cerror("#if sizeof, unknown type \"%s\"", token); + return (OP_FAIL); + } + typecode |= tp->type; /* Or in the type bit */ + } + } + /* + * We are at the end of the type scan. Chew off '*' if necessary. + */ + if (c == '*') { + typecode |= T_PTR; + c = skipws(); + } + if (c == ')') { /* Last syntax check */ + for (testp = test_table; *testp != 0; testp++) { + if (!bittest(typecode & *testp)) { + cerror("#if ... sizeof: illegal type combination", NULLST); + return (OP_FAIL); + } + } + /* + * 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("#if sizeof() error, no type specified", NULLST); + return (OP_FAIL); + } + /* + * Exactly one bit (and possibly T_PTR) may be set. + */ + for (sizp = size_table; sizp->bits != 0; sizp++) { + if ((typecode & ~T_PTR) == sizp->bits) { + evalue = ((typecode & T_PTR) != 0) + ? sizp->psize : sizp->size; + return (DIG); + } + } /* We shouldn't fail */ + cierror("#if ... sizeof: bug, unknown type code 0x%x", typecode); + return (OP_FAIL); + } + +nogood: unget(); + cerror("#if ... sizeof() syntax error", NULLST); + return (OP_FAIL); +} + +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 +} + +FILE_LOCAL int +evalnum(int c) +/* + * Expand number for #if lexical analysis. Note: evalnum recognizes + * the unsigned suffix, but only returns a signed int value. + */ +{ + register int value; + register int base; + register int c1; + + if (c != '0') + base = 10; + else if ((c = cget()) == 'x' || c == 'X') { + base = 16; + c = cget(); + } + else base = 8; + value = 0; + for (;;) { + c1 = c; + if (isascii(c) && isupper(c1)) + c1 = tolower(c1); +#ifdef EBCDIC + if (c1 <= 'f') +#else + if (c1 >= 'a') +#endif + c1 -= ('a' - 10); + else c1 -= '0'; + if (c1 < 0 || c1 >= base) + break; + value *= base; + value += c1; + c = cget(); + } + if (c == 'u' || c == 'U') /* Unsigned nonsense */ + c = cget(); + unget(); + return (value); +} + +FILE_LOCAL int +evalchar(int skip) +/* + * Get a character constant + */ +{ + register int c; + register int value; + register int count; + + instring = TRUE; + if ((c = cget()) == '\\') { + switch ((c = cget())) { + 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()) >= '0' && c <= '9') + || (c >= 'a' && c <= 'f') + || (c >= 'A' && c <= 'F')) + && (--count >= 0)) { + value *= 16; +#ifdef EBCDIC + value += (c <= '9') ? (c - '0') : ((c & 0xF) + 9); +#else + value += (c >= '0') ? (c - '0') : ((c & 0xF) + 9); +#endif + } + unget(); + 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(); + } + unget(); + } + 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()) != '\'' && c != EOF_CHAR && c != '\n') { + if (!skip) + ciwarn("multi-byte constant '%c' isn't portable", c); +#if BIG_ENDIAN + count += BITS_CHAR; + value += (c << count); +#else + value <<= BITS_CHAR; + value += c; +#endif + } + instring = FALSE; + return (value); +} + +FILE_LOCAL int * +evaleval(int* valp, int op, int skip) +/* + * 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. + */ +{ + register int v1, v2 = 0; + + if (isbinary(op)) + v2 = *--valp; + v1 = *--valp; +#ifdef DEBUG_EVAL + fprintf( pCppOut, "%s op %s", (isbinary(op)) ? "binary" : "unary", + opname[op]); + if (isbinary(op)) + fprintf( pCppOut, ", v2 = %d.", v2); + fprintf( pCppOut, ", v1 = %d.\n", v1); +#endif + 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("%s by zero in #if, zero result assumed", + (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: + cierror("#if bug, operand = %d.", op); + v1 = 0; + } + *valp++ = v1; + return (valp); +} + +#ifdef DEBUG_EVAL +dumpstack(opstack, opp, value, valp) +OPTAB opstack[NEXP]; /* Operand stack */ +register OPTAB *opp; /* Operator stack */ +int value[NEXP]; /* Value stack */ +register int *valp; /* -> value vector */ +{ + fprintf( pCppOut, "index op prec skip name -- op stack at %s", infile->bptr); + while (opp > opstack) { + fprintf( pCppOut, " [%2d] %2d %03o %d %s\n", opp - opstack, + opp->op, opp->prec, opp->skip, opname[opp->op]); + opp--; + } + while (--valp >= value) { + fprintf( pCppOut, "value[%d] = %d\n", (valp - value), *valp); + } +} +#endif + diff --git a/rsc/source/rscpp/cpp6.c b/rsc/source/rscpp/cpp6.c new file mode 100644 index 000000000000..fd2a2a9a0dd7 --- /dev/null +++ b/rsc/source/rscpp/cpp6.c @@ -0,0 +1,1148 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include "cppdef.h" +#include "cpp.h" + +/*ER evaluate macros to pDefOut */ + +/* + * 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 token[]. + * 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 token[]. + * 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 token[]. + * 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(), cwarn(), cfatal(), cierror(), ciwarn() + * These routines format an print messages to the user. + * cerror & cwarn take a format and a single string argument. + * cierror & ciwarn take a format and a single int (char) argument. + * cfatal takes a format and a single string argument. + */ + +/* + * This table must be rewritten for a non-Ascii machine. + * + * Note that several "non-visible" characters have special meaning: + * 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 + */ +#if TOK_SEP != 0x1E || COM_SEP != 0x1F || DEF_MAGIC != 0x1D + << error type table is not correct >> +#endif + +#if OK_DOLLAR +#define DOL LET +#else +#define DOL 000 +#endif + +#ifdef EBCDIC + +char type[256] = { /* Character type codes Hex */ + END, 000, 000, 000, 000, SPA, 000, 000, /* 00 */ + 000, 000, 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 */ + 000, 000, 000, 000, 000, 000, 000, 000, /* 20 */ + 000, 000, 000, 000, 000, 000, 000, 000, /* 28 */ + 000, 000, 000, 000, 000, 000, 000, 000, /* 30 */ + 000, 000, 000, 000, 000, 000, 000, 000, /* 38 */ + SPA, 000, 000, 000, 000, 000, 000, 000, /* 40 */ + 000, 000, 000, DOT, OP_LT,OP_LPA,OP_ADD, OP_OR, /* 48 .<(+| */ +OP_AND, 000, 000, 000, 000, 000, 000, 000, /* 50 & */ + 000, 000,OP_NOT, DOL,OP_MUL,OP_RPA, 000,OP_XOR, /* 58 !$*);^ */ +OP_SUB,OP_DIV, 000, 000, 000, 000, 000, 000, /* 60 -/ */ + 000, 000, 000, 000,OP_MOD, LET, OP_GT,OP_QUE, /* 68 ,%_>? */ + 000, 000, 000, 000, 000, 000, 000, 000, /* 70 */ + 000, 000,OP_COL, 000, 000, QUO, OP_EQ, QUO, /* 78 `:#@'=" */ + 000, LET, LET, LET, LET, LET, LET, LET, /* 80 abcdefg */ + LET, LET, 000, 000, 000, 000, 000, 000, /* 88 hi */ + 000, LET, LET, LET, LET, LET, LET, LET, /* 90 jklmnop */ + LET, LET, 000, 000, 000, 000, 000, 000, /* 98 qr */ + 000,OP_NOT, LET, LET, LET, LET, LET, LET, /* A0 ~stuvwx */ + LET, LET, 000, 000, 000, 000, 000, 000, /* A8 yz [ */ + 000, 000, 000, 000, 000, 000, 000, 000, /* B0 */ + 000, 000, 000, 000, 000, 000, 000, 000, /* B8 ] */ + 000, LET, LET, LET, LET, LET, LET, LET, /* C0 {ABCDEFG */ + LET, LET, 000, 000, 000, 000, 000, 000, /* C8 HI */ + 000, LET, LET, LET, LET, LET, LET, LET, /* D0 }JKLMNOP */ + LET, LET, 000, 000, 000, 000, 000, 000, /* D8 QR */ + BSH, 000, LET, LET, LET, LET, LET, LET, /* E0 \ STUVWX */ + LET, LET, 000, 000, 000, 000, 000, 000, /* E8 YZ */ + DIG, DIG, DIG, DIG, DIG, DIG, DIG, DIG, /* F0 01234567 */ + DIG, DIG, 000, 000, 000, 000, 000, 000, /* F8 89 */ +}; + +#else + +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 */ +}; + +#endif + + +/* + * C P P S y m b o l T a b l e s + */ + +/* + * SBSIZE defines the number of hash-table slots for the symbol table. + * It must be a power of 2. + */ +#ifndef SBSIZE +#define SBSIZE 64 +#endif +#define SBMASK (SBSIZE - 1) +#if (SBSIZE ^ SBMASK) != ((SBSIZE * 2) - 1) + << error, SBSIZE must be a power of 2 >> +#endif + + +static DEFBUF *symtab[SBSIZE]; /* Symbol table queue headers */ + +void InitCpp6() +{ + int i; + for( i = 0; i < SBSIZE; i++ ) + symtab[ i ] = NULL; +} + + + +void skipnl() +/* + * Skip to the end of the current input line. + */ +{ + register int c; + + do { /* Skip to newline */ + c = get(); + } while (c != '\n' && c != EOF_CHAR); +} + +int +skipws() +/* + * Skip over whitespace + */ +{ + register int c; + + do { /* Skip whitespace */ + c = get(); +#if COMMENT_INVISIBLE + } while (type[c] == SPA || c == COM_SEP); +#else + } while (type[c] == SPA); +#endif + return (c); +} + +void scanid(int c) +/* + * Get the next token (an id) into the token buffer. + * Note: this code is duplicated in lookid(). + * Change one, change both. + */ +{ + register char *bp; + + if (c == DEF_MAGIC) /* Eat the magic token */ + c = get(); /* undefiner. */ + bp = token; + do { + if (bp < &token[IDMAX]) /* token dim is IDMAX+1 */ + *bp++ = (char)c; + c = get(); + } while (type[c] == LET || type[c] == DIG); + unget(); + *bp = EOS; +} + +int +macroid(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 token. + */ +{ + register DEFBUF *dp; + + if (infile != NULL && infile->fp != NULL) + recursion = 0; + while (type[c] == LET && (dp = lookid(c)) != NULL) { + expand(dp); + c = get(); + } + return (c); +} + +int +catenate() +/* + * 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. + */ +{ + register int c; + register char *token1; + +#if OK_CONCAT + if (get() != TOK_SEP) { /* Token concatenation */ + unget(); + return (FALSE); + } + else { + token1 = savestring(token); /* Save first token */ + c = macroid(get()); /* Scan next token */ + switch(type[c]) { /* What was it? */ + case LET: /* An identifier, ... */ + if (strlen(token1) + strlen(token) >= NWORK) + cfatal("work buffer overflow doing %s #", token1); + sprintf(work, "%s%s", token1, token); + break; + + case DIG: /* A digit string */ + strcpy(work, token1); + workp = work + strlen(work); + do { + save(c); + } while ((c = get()) != TOK_SEP); + /* + * The trailing TOK_SEP is no longer needed. + */ + save(EOS); + break; + + default: /* An error, ... */ +#if ! COMMENT_INVISIBLE + if (isprint(c)) + cierror("Strange character '%c' after #", c); + else + cierror("Strange character (%d.) after #", c); +#endif + strcpy(work, token1); + unget(); + 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. + */ + free(token1); /* Free up memory */ + ungetstring(work); /* Unget the new thing, */ + return (TRUE); + } +#else + return (FALSE); /* Not supported */ +#endif +} + +int +scanstring(int delim, +#ifndef _NO_PROTO +void (*outfun)( int ) /* BP */ /* Output function */ +#else +void (*outfun)() /* BP */ +#endif +) +/* + * 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. + */ +{ + register int c; + + instring = TRUE; /* Don't strip comments */ + (*outfun)(delim); + while ((c = get()) != delim + && c != '\n' + && c != EOF_CHAR) { + + if (c != DEF_MAGIC) + (*outfun)(c); + if (c == '\\') + (*outfun)(get()); + } + instring = FALSE; + if (c == delim) { + (*outfun)(c); + return (TRUE); + } + else { + cerror("Unterminated string", NULLST); + unget(); + return (FALSE); + } +} + +void scannumber(int c, +#ifndef _NO_PROTO +register void (*outfun)( int ) /* BP */ /* Output/store func */ +#else +register void (*outfun)() /* BP */ +#endif +) +/* + * Process a number. We know that c is from 0 to 9 or dot. + * Algorithm from Dave Conroy's Decus C. + */ +{ + register 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 */ + + 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? */ + (*outfun)('.'); /* Always out the dot */ + if (type[(c = get())] != DIG) { /* If not a float numb, */ + unget(); /* Rescan strange char */ + return; /* All done for now */ + } + } /* End of float test */ + else if (c == '0') { /* Octal or hex? */ + (*outfun)(c); /* Stuff initial zero */ + radix = 8; /* Assume it's octal */ + c = get(); /* Look for an 'x' */ + if (c == 'x' || c == 'X') { /* Did we get one? */ + radix = 16; /* Remember new radix */ + (*outfun)(c); /* Stuff the 'x' */ + c = get(); /* Get next character */ + } + } + for (;;) { /* 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 */ + goto done; /* Break from for loop */ + } /* End of switch */ + } /* End general case */ + (*outfun)(c); /* Accept the character */ + signseen = TRUE; /* Don't read sign now */ + c = get(); /* 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". + */ +done: if (dotflag || expseen) { /* Floating point? */ + if (c == 'l' || c == 'L') { + (*outfun)(c); + c = get(); /* 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'". + */ + for (;;) { + switch (c) { + case 'l': + case 'L': + if (dotflag) + goto nomore; + dotflag = TRUE; + break; + + case 'u': + case 'U': + if (expseen) + goto nomore; + expseen = TRUE; + break; + + default: + goto nomore; + } + (*outfun)(c); /* Got 'L' or 'U'. */ + c = get(); /* Look at next, too. */ + } + } +nomore: unget(); /* Not part of a number */ + if (octal89 && radix == 8) + cwarn("Illegal digit in octal number", NULLST); +} + +void save(int c) +{ + if (workp >= &work[NWORK]) { + work[NWORK-1] = '\0'; + cfatal("Work buffer overflow: %s", work); + } + else *workp++ = (char)c; +} + +char * +savestring(char* text) +/* + * Store a string into free memory. + */ +{ + register char *result; + + result = getmem(strlen(text) + 1); + strcpy(result, text); + return (result); +} + +FILEINFO * +getfile(int bufsize, char* name) +/* + * Common FILEINFO buffer initialization for a new file or macro. + */ +{ + register FILEINFO *file; + register int size; + + size = strlen(name); /* File/macro name */ + file = (FILEINFO *) getmem(sizeof (FILEINFO) + bufsize + size); + file->parent = infile; /* Chain files together */ + file->fp = NULL; /* No file yet */ + file->filename = savestring(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 (infile != NULL) /* If #include file */ + infile->line = line; /* Save current line */ + infile = file; /* New current file */ + line = 1; /* Note first line */ + return (file); /* All done. */ +} + +char * +getmem(int size) +/* + * Get a block of free memory. + */ +{ + register char *result; + + if ((result = malloc((unsigned) size)) == NULL) + cfatal("Out of memory", NULLST); + return (result); +} + + +DEFBUF * +lookid(int c) +/* + * Look for the next token in the symbol table. Returns token in "token". + * If found, returns the table pointer; Else returns NULL. + */ +{ + register int nhash; + register DEFBUF *dp; + register char *np; + int temp = 0; + int isrecurse; /* For #define foo foo */ + + np = token; + nhash = 0; + if (0 != (isrecurse = (c == DEF_MAGIC))) /* If recursive macro */ + c = get(); /* hack, skip DEF_MAGIC */ + do { + if (np < &token[IDMAX]) { /* token dim is IDMAX+1 */ + *np++ = (char)c; /* Store token byte */ + nhash += c; /* Update hash value */ + } + c = get(); /* And get another byte */ + } while (type[c] == LET || type[c] == DIG); + unget(); /* Rescan terminator */ + *np = EOS; /* Terminate token */ + if (isrecurse) /* Recursive definition */ + return (NULL); /* undefined just now */ + nhash += (np - token); /* Fix hash value */ + dp = symtab[nhash & SBMASK]; /* Starting bucket */ + while (dp != (DEFBUF *) NULL) { /* Search symbol table */ + if (dp->hash == nhash /* Fast precheck */ + && (temp = strcmp(dp->name, token)) >= 0) + break; + dp = dp->link; /* Nope, try next one */ + } + return ((temp == 0) ? dp : NULL); +} + +DEFBUF * +defendel(char* name, int delete) +/* + * 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). + */ +{ + register DEFBUF *dp; + register DEFBUF **prevp; + register char *np; + int nhash; + int temp; + int size; + + for (nhash = 0, np = name; *np != EOS;) + nhash += *np++; + size = (np - name); + nhash += size; + prevp = &symtab[nhash & SBMASK]; + 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 */ + free(dp->repl); /* if any, and then */ + free((char *) dp); /* Free the symbol */ + } + break; + } + prevp = &dp->link; + } + if (!delete) { + dp = (DEFBUF *) getmem(sizeof (DEFBUF) + size); + dp->link = *prevp; + *prevp = dp; + dp->hash = nhash; + dp->repl = NULL; + dp->nargs = 0; + strcpy(dp->name, name); + } + return (dp); +} + +#if OSL_DEBUG_LEVEL > 1 + +void dumpdef(char *why) +{ + register DEFBUF *dp; + register DEFBUF **syp; + FILE *pRememberOut = NULL; + + if ( bDumpDefs ) /*ER */ + { + pRememberOut = pCppOut; + pCppOut = pDefOut; + } + fprintf( pCppOut, "CPP symbol table dump %s\n", why); + for (syp = symtab; syp < &symtab[SBSIZE]; syp++) { + if ((dp = *syp) != (DEFBUF *) NULL) { + fprintf( pCppOut, "symtab[%d]\n", (syp - symtab)); + do { + dumpadef((char *) NULL, dp); + } while ((dp = dp->link) != (DEFBUF *) NULL); + } + } + if ( bDumpDefs ) + { + fprintf( pCppOut, "\n"); + pCppOut = pRememberOut; + } +} + +void dumpadef(char *why, register DEFBUF *dp) +{ + register char *cp; + register int c; + FILE *pRememberOut = NULL; + +/*ER dump #define's to pDefOut */ + if ( bDumpDefs ) + { + pRememberOut = pCppOut; + pCppOut = pDefOut; + } + fprintf( pCppOut, " \"%s\" [%d]", dp->name, dp->nargs); + if (why != NULL) + fprintf( pCppOut, " (%s)", why); + if (dp->repl != NULL) { + fprintf( pCppOut, " => "); + for (cp = dp->repl; (c = *cp++ & 0xFF) != EOS;) { +#ifdef SOLAR + if (c == DEL) { + c = *cp++ & 0xFF; + if( c == EOS ) break; + fprintf( pCppOut, "<%%%d>", c - MAC_PARM); + } +#else + if (c >= MAC_PARM && c <= (MAC_PARM + PAR_MAC)) + fprintf( pCppOut, "<%%%d>", c - MAC_PARM); +#endif + else if (isprint(c) || c == '\n' || c == '\t') + PUTCHAR(c); + else if (c < ' ') + fprintf( pCppOut, "<^%c>", c + '@'); + else + fprintf( pCppOut, "<\\0%o>", c); + } +/*ER evaluate macros to pDefOut */ +#ifdef EVALDEFS + if ( bDumpDefs && !bIsInEval && dp->nargs <= 0 ) + { + FILEINFO *infileSave = infile; + char *tokenSave = savestring( token ); + char *workSave = savestring( work ); + int lineSave = line; + int wronglineSave = wrongline; + int recursionSave = recursion; + FILEINFO *file; + EVALTYPE valEval; + + bIsInEval = 1; + infile = NULL; /* start from scrap */ + line = 0; + wrongline = 0; + *token = EOS; + *work = EOS; + recursion = 0; + file = getfile( strlen( dp->repl ), dp->name ); + strcpy( file->buffer, dp->repl ); + fprintf( pCppOut, " ===> "); + nEvalOff = 0; + cppmain(); /* get() frees also *file */ + valEval = 0; + if ( 0 == evaluate( EvalBuf, &valEval ) ) + { +#ifdef EVALFLOATS + if ( valEval != (EVALTYPE)((long)valEval ) ) + fprintf( pCppOut, " ==eval=> %f", valEval ); + else +#endif + fprintf( pCppOut, " ==eval=> %ld", (long)valEval ); + } + recursion = recursionSave; + wrongline = wronglineSave; + line = lineSave; + strcpy( work, workSave ); + free( workSave ); + strcpy( token, tokenSave ); + free( tokenSave ); + infile = infileSave; + bIsInEval = 0; + } +#endif + } + else { + fprintf( pCppOut, ", no replacement."); + } + PUTCHAR('\n'); + if ( bDumpDefs ) + pCppOut = pRememberOut; +} +#endif + +/* + * G E T + */ + +int +get() +/* + * Return the next character from a macro or the current file. + * Handle end of file from #include files. + */ +{ + register int c; + register FILEINFO *file; + register int popped; /* Recursion fixup */ + + popped = 0; +get_from_file: + if ((file = infile) == NULL) + return (EOF_CHAR); +newline: +#if 0 + fprintf( pCppOut, "get(%s), recursion %d, line %d, bptr = %d, buffer \"%s\"\n", + file->filename, recursion, line, + file->bptr - file->buffer, file->buffer); +#endif + /* + * 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++; + recursion -= file->unrecur; + if (recursion < 0) + recursion = 0; + infile = file->parent; /* Unwind file chain */ + } + else { /* Else get from a file */ + if ((file->bptr = fgets(file->buffer, NBUFF, file->fp)) + != NULL) { +#if OSL_DEBUG_LEVEL > 1 + if (debug > 1) { /* Dump it to stdout */ + fprintf( pCppOut, "\n#line %d (%s), %s", + line, file->filename, file->buffer); + } +#endif + goto newline; /* process the line */ + } + else { + if( file->fp != stdin ) + fclose(file->fp); /* Close finished file */ + if ((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. + */ + 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. + */ + free(file->filename); /* Free name and */ + if (file->progname != NULL) /* if a #line was seen, */ + free(file->progname); /* free it, too. */ + free((char *) file); /* Free file space */ + if (infile == NULL) /* If at end of file */ + return (EOF_CHAR); /* Return end of file */ + line = 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 { + recursion -= file->parent->unrecur; + if (recursion < 0) + recursion = 0; + file->parent->unrecur = 0; + } + } +#if (HOST == SYS_UNIX) +/*ER*/ if (c == '\r') +/*ER*/ return get(); /* DOS fuck */ +#endif + if (c == '\n') /* Maintain current */ + ++line; /* line counter */ + if (instring) /* Strings just return */ + return (c); /* the character. */ + else if (c == '/') { /* Comment? */ + instring = TRUE; /* So get() won't loop */ +/*MM c++ comments */ +/*MM*/ c = get(); +/*MM*/ if ((c != '*') && (c != '/')) { /* Next byte '*'? */ + instring = FALSE; /* Nope, no comment */ + unget(); /* Push the char. back */ + return ('/'); /* Return the slash */ + } + if (keepcomments) { /* If writing comments */ + PUTCHAR('/'); /* Write out the */ + /* initializer */ +/*MM*/ if( '*' == c ) + PUTCHAR('*'); +/*MM*/ else +/*MM*/ PUTCHAR('/'); + + } +/*MM*/ if( '*' == c ){ + for (;;) { /* Eat a comment */ + c = get(); + test: if (keepcomments && c != EOF_CHAR) + cput(c); + switch (c) { + case EOF_CHAR: + cerror("EOF in comment", NULLST); + return (EOF_CHAR); + + case '/': + if ((c = get()) != '*') /* Don't let comments */ + goto test; /* Nest. */ +#ifdef STRICT_COMMENTS + cwarn("Nested comments", NULLST); +#endif + /* Fall into * stuff */ + case '*': + if ((c = get()) != '/') /* If comment doesn't */ + goto test; /* end, look at next */ + instring = FALSE; /* End of comment, */ + if (keepcomments) { /* Put out the comment */ + cput(c); /* terminator, too */ + } + /* + * 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 (!keepcomments) + wrongline = TRUE; /* later... */ + default: /* Anything else is */ + break; /* Just a character */ + } /* End switch */ + } /* End comment loop */ + } + else{ /* c++ comment */ +/*MM c++ comment*/ + for (;;) { /* Eat a comment */ + c = get(); + if (keepcomments && c != EOF_CHAR) + cput(c); + if( EOF_CHAR == c ) + return (EOF_CHAR); + else if( '\n' == c ){ + instring = FALSE; /* End of comment, */ + return( c ); + } + } + } + } /* End if in comment */ + else if (!inmacro && c == '\\') { /* If backslash, peek */ + if ((c = get()) == '\n') { /* for a <nl>. If so, */ + wrongline = TRUE; + goto newline; + } + else { /* Backslash anything */ + unget(); /* Get it later */ + return ('\\'); /* Return the backslash */ + } + } + else if (c == '\f' || c == VT) /* Form Feed, Vertical */ + c = ' '; /* Tab are whitespace */ + else if (c == 0xef) /* eat up UTF-8 BOM */ + { + if((c = get()) == 0xbb) + { + if((c = get()) == 0xbf) + { + c = get(); + return c; + } + else + { + unget(); + unget(); + return 0xef; + } + } + else + { + unget(); + return 0xef; + } + } + return (c); /* Just return the char */ +} + +void unget() +/* + * 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(). + */ +{ + register FILEINFO *file; + + if ((file = infile) == NULL) + return; /* Unget after EOF */ + if (--file->bptr < file->buffer) + cfatal("Too much pushback", NULLST); + if (*file->bptr == '\n') /* Ungetting a newline? */ + --line; /* Unget the line number, too */ +} + +void ungetstring(char* text) +/* + * Push a string back on the input stream. This is done by treating + * the text as if it were a macro. + */ +{ + register FILEINFO *file; +#ifndef ZTC /* BP */ + extern FILEINFO *getfile(); +#endif + file = getfile(strlen(text) + 1, ""); + strcpy(file->buffer, text); +} + +int +cget() +/* + * Get one character, absorb "funny space" after comments or + * token concatenation + */ +{ + register int c; + + do { + c = get(); +#if COMMENT_INVISIBLE + } while (c == TOK_SEP || c == COM_SEP); +#else + } while (c == TOK_SEP); +#endif + return (c); +} + +/* + * Error messages and other hacks. The first byte of severity + * is 'S' for string arguments and 'I' for int arguments. This + * is needed for portability with machines that have int's that + * are shorter than char *'s. + */ + +static void domsg(char* severity, char* format, void* arg) +/* + * Print filenames, macro names, and line numbers for error messages. + */ +{ + register char *tp; + register FILEINFO *file; + + fprintf(stderr, "%sline %d, %s: ", MSG_PREFIX, line, &severity[1]); + if (*severity == 'S') + fprintf(stderr, format, (char *)arg); + else + fprintf(stderr, format, *((int *)arg) ); + putc('\n', stderr); + if ((file = infile) == NULL) + return; /* At end of file */ + if (file->fp != NULL) { + tp = file->buffer; /* Print current file */ + fprintf(stderr, "%s", tp); /* name, making sure */ + if (tp[strlen(tp) - 1] != '\n') /* there's a newline */ + putc('\n', stderr); + } + while ((file = file->parent) != NULL) { /* Print #includes, too */ + if (file->fp == NULL) + fprintf(stderr, "from macro %s\n", file->filename); + else { + tp = file->buffer; + fprintf(stderr, "from file %s, line %d:\n%s", + (file->progname != NULL) + ? file->progname : file->filename, + file->line, tp); + if (tp[strlen(tp) - 1] != '\n') + putc('\n', stderr); + } + } +} + +void cerror(char* format, char* sarg) +/* + * Print a normal error message, string argument. + */ +{ + domsg("SError", format, sarg); + errors++; +} + +void cierror(char* format, int narg) +/* + * Print a normal error message, numeric argument. + */ +{ + domsg("IError", format, &narg); + errors++; +} + +void cfatal(char* format, char* sarg) +/* + * A real disaster + */ +{ + domsg("SFatal error", format, sarg); + exit(IO_ERROR); +} + +void cwarn(char* format, char* sarg) +/* + * A non-fatal error, string argument. + */ +{ + domsg("SWarning", format, sarg); +} + +void ciwarn(char* format, int narg) +/* + * A non-fatal error, numeric argument. + */ +{ + domsg("IWarning", format, &narg); +} + diff --git a/rsc/source/rscpp/cppdef.h b/rsc/source/rscpp/cppdef.h new file mode 100644 index 000000000000..cdbf07766c8f --- /dev/null +++ b/rsc/source/rscpp/cppdef.h @@ -0,0 +1,346 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +/* + * 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 + +#ifndef HOST +#ifdef unix +#define HOST SYS_UNIX +#else +#ifdef vms +#define HOST SYS_VMS +#else +#ifdef rsx +#define HOST SYS_RSX +#else +#ifdef rt11 +#define HOST SYS_RT11 +#endif +#endif +#endif +#endif +#endif + +#ifndef HOST +#define HOST SYS_UNKNOWN +#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. + * + * 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). + * + * OK_DATE Predefines the compilation date if set TRUE. + * Not permitted by the Nov. 12, 1984 Draft Standard. + * + * 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. + */ + +#if TARGET == SYS_LATTICE +/* + * We assume the operating system is pcdos for the IBM-PC. + * We also assume the small model (just like the PDP-11) + */ +#define MACHINE "i8086" +#define SYSTEM "pcdos" +#endif + +#if TARGET == SYS_ONYX +#define MACHINE "z8000" +#define SYSTEM "unix" +#endif + +#if TARGET == SYS_VMS +#define MACHINE "vax" +#define SYSTEM "vms" +#define COMPILER "vax11c" +#endif + +#if TARGET == SYS_RSX +#define MACHINE "pdp11" +#define SYSTEM "rsx" +#define COMPILER "decus" +#endif + +#if TARGET == SYS_RT11 +#define MACHINE "pdp11" +#define SYSTEM "rt11" +#define COMPILER "decus" +#endif + +#if TARGET == SYS_68000 || defined(M68000) || defined(m68000) || defined(m68k) +/* + * All three machine designators have been seen in various systems. + * Warning -- compilers differ as to sizeof (int). cpp3 assumes that + * sizeof (int) == 2 + */ +#define MACHINE "M68000", "m68000", "m68k" +#define SYSTEM "unix" +#endif + +#if TARGET == SYS_UNIX +#define SYSTEM "unix" +#ifdef pdp11 +#define MACHINE "pdp11" +#endif +#ifdef vax +#define MACHINE "vax" +#endif +#endif + +/* + * defaults + */ + +#ifndef MSG_PREFIX +#define MSG_PREFIX "cpp: " +#endif + +#ifndef LINE_PREFIX +#define LINE_PREFIX "" +#endif + +/* + * OLD_PREPROCESSOR forces the definition of OK_DOLLAR, OK_CONCAT, + * COMMENT_INVISIBLE, and STRING_FORMAL to values appropriate for + * an old-style preprocessor. + */ + +#ifndef OLD_PREPROCESSOR +#define OLD_PREPROCESSOR FALSE +#endif + +#if OLD_PREPROCESSOR +#define OK_DOLLAR FALSE +#define OK_CONCAT TRUE +#define COMMENT_INVISIBLE TRUE +#define STRING_FORMAL TRUE +#define IDMAX 63 /* actually, seems to be unlimited */ +#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. + */ +#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 + +/* + * STRING_FORMAL may be defined to allow recognition of macro parameters + * anywhere in replacement strings. This was removed from the Draft Ansi + * Standard and a limited recognition capability added. + */ +#ifndef STRING_FORMAL +#define STRING_FORMAL 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 + +/* + * 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. + * IDMAX The longest identifier, 31 per Ansi Standard + * 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. + * NFWORK FileNameWorkBuffer (added by erAck, was NWORK) + */ + +#ifndef IDMAX +#define IDMAX 127 +#endif +#ifdef SOLAR +#define PAR_MAC (253 + 1) +#else +#define PAR_MAC (31 + 1) +#endif +/* ER 13.06.95 19:33 + da Makros im file->buffer expandiert werden, muss NBUFF mindestens NWORK sein +#define NWORK 4096 +#define NBUFF 4096 + */ +/* ER 13.06.95 20:05 NWORK wg. grooossen Makros in *.src erhoeht, + da wir bald 10 Sprachen haben werden gleich ordentlich reingehauen.. */ +#define NWORK 128000 +#define NBUFF NWORK +#define NFWORK 1024 +#define NEXP 128 +#define NINCLUDE 100 +#define NPARMWORK (NWORK * 2) +#define BLK_NEST 32 + + +#ifndef ALERT +#ifdef EBCDIC +#define ALERT '\057' +#else +#define ALERT '\007' /* '\a' is "Bell" */ +#endif +#endif + +#ifndef VT +#define VT '\013' /* Vertical Tab CTRL/K */ +#endif + + +#ifndef FILE_LOCAL +#ifdef decus +#define FILE_LOCAL static +#else +#ifdef vax11c +#define FILE_LOCAL static +#else +#define FILE_LOCAL /* Others are global */ +#endif +#endif +#endif + diff --git a/rsc/source/rscpp/cppmain.c b/rsc/source/rscpp/cppmain.c new file mode 100644 index 000000000000..3060a6d6be9a --- /dev/null +++ b/rsc/source/rscpp/cppmain.c @@ -0,0 +1,45 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#define NOMAIN + +#include <stdio.h> +#include <ctype.h> +#include "cppdef.h" +#include "cpp.h" + +int main( argc, argv ) + int argc; + char *argv[]; +{ +#ifdef TSTCPP + ( start_cpp( argc, argv ) ); + puts("erster teil ist fertig" ); +#endif + return( start_cpp( argc, argv ) ); +} + diff --git a/rsc/source/rscpp/makefile.mk b/rsc/source/rscpp/makefile.mk new file mode 100644 index 000000000000..ca62bb37792c --- /dev/null +++ b/rsc/source/rscpp/makefile.mk @@ -0,0 +1,92 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* +PRJ=..$/.. + +TARGETTYPE=CUI +NO_DEFAULT_STL=TRUE + +PRJNAME=rsc +TARGET=rscpp + +.IF "$(cpp)" != "" +PRJNAME=CPP +TARGET=cpp +.ENDIF + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +CDEFS+=-DSOLAR + +.IF "$(cpp)" != "" +CDEFS+=-DNOMAIN +.ENDIF + +# --- Files -------------------------------------------------------- + +OBJFILES= \ + $(OBJ)$/cpp1.obj \ + $(OBJ)$/cpp2.obj \ + $(OBJ)$/cpp3.obj \ + $(OBJ)$/cpp4.obj \ + $(OBJ)$/cpp5.obj \ + $(OBJ)$/cpp6.obj \ + +.IF "$(cpp)" == "" +LIBSALCPPRT=$(0) +APP1TARGET= $(TARGET) +APP1LIBS=$(LB)$/$(TARGET).lib +.IF "$(GUI)" != "OS2" +APP1STACK=32768 +.ENDIF +.ENDIF + +.IF "$(GUI)"=="UNX" +CDEFS+=-Dunix +.ENDIF + +.IF "$(OS)$(CPU)"=="SOLARISI" +# cc: Sun C 5.5 Patch 112761-10 2004/08/10 +# Solaris x86 compiler ICE +# "cpp6.c", [get]:ube: internal error +# remove after compiler upgrade +NOOPTFILES=$(OBJ)$/cpp6.obj +.ENDIF + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk + +cpp1.c: cppdef.h cpp.h +cpp2.c: cppdef.h cpp.h +cpp3.c: cppdef.h cpp.h +cpp4.c: cppdef.h cpp.h +cpp5.c: cppdef.h cpp.h +cpp6.c: cppdef.h cpp.h + + |