diff options
Diffstat (limited to 'rsc/source/rscpp/cpp2.c')
-rw-r--r-- | rsc/source/rscpp/cpp2.c | 625 |
1 files changed, 625 insertions, 0 deletions
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 + |