summaryrefslogtreecommitdiff
path: root/rsc/source/rscpp/cpp1.c
diff options
context:
space:
mode:
Diffstat (limited to 'rsc/source/rscpp/cpp1.c')
-rw-r--r--rsc/source/rscpp/cpp1.c619
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;
+}