diff options
Diffstat (limited to 'rsc/source/rscpp/cpp1.c')
-rw-r--r-- | rsc/source/rscpp/cpp1.c | 619 |
1 files changed, 619 insertions, 0 deletions
diff --git a/rsc/source/rscpp/cpp1.c b/rsc/source/rscpp/cpp1.c new file mode 100644 index 000000000000..e3ac953a83c7 --- /dev/null +++ b/rsc/source/rscpp/cpp1.c @@ -0,0 +1,619 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: cpp1.c,v $ + * $Revision: 1.11 $ + * + * 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; +} |