summaryrefslogtreecommitdiff
path: root/rsc/source/rscpp/cpp4.c
diff options
context:
space:
mode:
Diffstat (limited to 'rsc/source/rscpp/cpp4.c')
-rw-r--r--rsc/source/rscpp/cpp4.c635
1 files changed, 635 insertions, 0 deletions
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