diff options
Diffstat (limited to 'soltools/cpp')
-rw-r--r-- | soltools/cpp/Test.txt | 116 | ||||
-rw-r--r-- | soltools/cpp/_cpp.c | 402 | ||||
-rw-r--r-- | soltools/cpp/_eval.c | 795 | ||||
-rw-r--r-- | soltools/cpp/_getopt.c | 94 | ||||
-rw-r--r-- | soltools/cpp/_getopt.h | 29 | ||||
-rw-r--r-- | soltools/cpp/_include.c | 250 | ||||
-rw-r--r-- | soltools/cpp/_lex.c | 707 | ||||
-rw-r--r-- | soltools/cpp/_macro.c | 762 | ||||
-rw-r--r-- | soltools/cpp/_mcrvalid.c | 127 | ||||
-rw-r--r-- | soltools/cpp/_nlist.c | 138 | ||||
-rw-r--r-- | soltools/cpp/_tokens.c | 557 | ||||
-rw-r--r-- | soltools/cpp/_unix.c | 226 | ||||
-rw-r--r-- | soltools/cpp/cpp.h | 251 |
13 files changed, 4454 insertions, 0 deletions
diff --git a/soltools/cpp/Test.txt b/soltools/cpp/Test.txt new file mode 100644 index 000000000..484d150c1 --- /dev/null +++ b/soltools/cpp/Test.txt @@ -0,0 +1,116 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#define ABC \ + ggg + +ABC + +/* Standards */ + +#define NOTHING +NOTHING + +#define SYMBOL symbol +#undef SYMBOL +#define SYMBOL _symbol_ + +< SYMBOL > // < _symbol_ > +xSYMBOLx // xSYMBOLx ++SYMBOL- // +_symbol_- +>SYMBOL< // >_symbol_< +<SYMBOL> // <_symbol_> + +#define FALSE 0 +#define TRUE !FALSE +a = x > 0 ? TRUE : FALSE // a = x > 0 ? !0 : 0 + +#define A x +#define B y +#define MAC(a, b) \ + T() { a(); return b; } // T() { x(); return y; } +MAC(A,B); + +#ifdef MAC +MAC(X,Y) +#endif // MAC + +/* Recursions */ + +#define y x +#define x y +x // x + +#define Test(a) a +#define b Test(b) +a = b; // a = b; + +#define func abc(func) +a = func // a = abc(func) + +#define func1 func(abc) +a = func1 // a = abc(func)(abc) + +#define args(func, args) func args +args(t1, (args(t2, (x, y)))) // t1 (t2 (x, y)) + +#define ARGS(a) a +#define __ ARGS +int foo __((int x)); // int foo (int x); + +/* Concatenations */ + +#define tail _Test +// Txt_##tail // Txt_##_Test + +#define z(e,f) e##_##f +z ( abc, xyz ) // abc_xyz + + +#define CAT( var ) fix##.var +CAT( a ) // fix.a + +#define CAT3( class, ref ) class##ref::class##ref +CAT3( a, b ) // ab::ab + +#define CAT2( var ) fix##var::fix##var +CAT2( a ) // fixa::fixa + +/* Extremes */ + +#define MAKE_X( name ) name##_Test +#define MAKE_Y( name ) MAKE_X( name##_Sym ) +MAKE_Y( Txt ); // Txt_Sym_Test; + + +/* Extensions */ + +/* +#ident "(c)# Test.txt" + +#if #machine(i386) +# error illegal machine +#endif +char machine[6]; +*/ + +/* Last bug */ +#define Cfstrcpy Cstrcpy +#define Cstrcpy( s1, s2 ) strcpy( s1, s2 ) + +Cfstrcpy(Par1,Par2 ) // blub( Par1, Par2 ) diff --git a/soltools/cpp/_cpp.c b/soltools/cpp/_cpp.c new file mode 100644 index 000000000..77a719347 --- /dev/null +++ b/soltools/cpp/_cpp.c @@ -0,0 +1,402 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <stdarg.h> +#include "cpp.h" + +#define OUTS 16384 +static char outbuf[OUTS]; +char *outptr = outbuf; +Source *cursource; +static int nerrs; +struct token nltoken = {NL, 0, 1, (uchar *) "\n", 0}; +char *curtime; +int incdepth; +int ifdepth; +int ifsatisfied[NIF]; +int skipping; + +int +#ifdef _WIN32 +__cdecl +#endif // _WIN32 + main(int argc, char **argv) +{ + + Tokenrow tr; + time_t t; + char ebuf[BUFSIZ]; + + setbuf(stderr, ebuf); + t = time(NULL); + curtime = ctime(&t); + maketokenrow(3, &tr); + expandlex(); + // coverity[tainted_string] - build time test tool + setup(argc, argv); + fixlex(); + if (!Pflag) + genline(); + process(&tr); + flushout(); + fflush(stderr); + exit(nerrs > 0); +} + +void + process(Tokenrow * trp) +{ + int anymacros = 0; + + for (;;) + { + if (trp->tp >= trp->lp) + { + trp->tp = trp->lp = trp->bp; + outptr = outbuf; + // coverity[overrun-buffer-arg: FALSE] - a multiple of trp->max is allocated, not trp->max itself + anymacros |= gettokens(trp, 1); + trp->tp = trp->bp; + } + if (trp->tp->type == END) + { + if (--incdepth >= 0) + { + if (cursource->ifdepth) + error(ERROR, + "Unterminated conditional in #include"); + unsetsource(); + cursource->line += cursource->lineinc; + trp->tp = trp->lp; + if (!Pflag) + genline(); + continue; + } + if (ifdepth) + error(ERROR, "Unterminated #if/#ifdef/#ifndef"); + break; + } + if (trp->tp->type == SHARP) + { + trp->tp += 1; + control(trp); + } + else + if (!skipping && anymacros) + expandrow(trp, NULL); + if (skipping) + setempty(trp); + puttokens(trp); + anymacros = 0; + cursource->line += cursource->lineinc; + if (cursource->lineinc > 1 && !Pflag) + genline(); + } +} + +void + control(Tokenrow * trp) +{ + Nlist *np; + Token *tp; + + tp = trp->tp; + if (tp->type != NAME) + { + if (tp->type == NUMBER) + goto kline; + if (tp->type != NL) + error(ERROR, "Unidentifiable control line"); + return; /* else empty line */ + } + np = lookup(tp, 0); + if (np == NULL || ((np->flag & ISKW) == 0 && !skipping)) + { + error(WARNING, "Unknown preprocessor control %t", tp); + return; + } + if (skipping) + { + switch (np->val) + { + case KENDIF: + if (--ifdepth < skipping) + skipping = 0; + --cursource->ifdepth; + setempty(trp); + return; + + case KIFDEF: + case KIFNDEF: + case KIF: + if (++ifdepth >= NIF) + error(FATAL, "#if too deeply nested"); + ++cursource->ifdepth; + return; + + case KELIF: + case KELSE: + if (ifdepth <= skipping) + break; + return; + + default: + return; + } + } + switch (np->val) + { + case KDEFINE: + dodefine(trp); + break; + + case KUNDEF: + tp += 1; + if (tp->type != NAME || trp->lp - trp->bp != 4) + { + error(ERROR, "Syntax error in #undef"); + break; + } + if ((np = lookup(tp, 0)) != NULL) + { + np->flag &= ~ISDEFINED; + + if (Mflag) + { + if (np->ap) + error(INFO, "Macro deletion of %s(%r)", np->name, np->ap); + else + error(INFO, "Macro deletion of %s", np->name); + } + } + break; + + case KPRAGMA: + case KIDENT: + for (tp = trp->tp - 1; ((tp->type != NL) && (tp < trp->lp)); tp++) + tp->type = UNCLASS; + return; + + case KIFDEF: + case KIFNDEF: + case KIF: + if (++ifdepth >= NIF) + error(FATAL, "#if too deeply nested"); + ++cursource->ifdepth; + ifsatisfied[ifdepth] = 0; + if (eval(trp, np->val)) + ifsatisfied[ifdepth] = 1; + else + skipping = ifdepth; + break; + + case KELIF: + if (ifdepth == 0) + { + error(ERROR, "#elif with no #if"); + return; + } + if (ifsatisfied[ifdepth] == 2) + error(ERROR, "#elif after #else"); + if (eval(trp, np->val)) + { + if (ifsatisfied[ifdepth]) + skipping = ifdepth; + else + { + skipping = 0; + ifsatisfied[ifdepth] = 1; + } + } + else + skipping = ifdepth; + break; + + case KELSE: + if (ifdepth == 0 || cursource->ifdepth == 0) + { + error(ERROR, "#else with no #if"); + return; + } + if (ifsatisfied[ifdepth] == 2) + error(ERROR, "#else after #else"); + if (trp->lp - trp->bp != 3) + error(ERROR, "Syntax error in #else"); + skipping = ifsatisfied[ifdepth] ? ifdepth : 0; + ifsatisfied[ifdepth] = 2; + break; + + case KENDIF: + if (ifdepth == 0 || cursource->ifdepth == 0) + { + error(ERROR, "#endif with no #if"); + return; + } + --ifdepth; + --cursource->ifdepth; + if (trp->lp - trp->bp != 3) + error(WARNING, "Syntax error in #endif"); + break; + + case KERROR: + trp->tp = tp + 1; + error(WARNING, "#error directive: %r", trp); + break; + + case KLINE: + trp->tp = tp + 1; + expandrow(trp, "<line>"); + tp = trp->bp + 2; + kline: + if (tp + 1 >= trp->lp || tp->type != NUMBER || tp + 3 < trp->lp + || (tp + 3 == trp->lp + && ((tp + 1)->type != STRING || *(tp + 1)->t == 'L'))) + { + error(ERROR, "Syntax error in #line"); + return; + } + cursource->line = atol((char *) tp->t) - 1; + if (cursource->line < 0 || cursource->line >= 32768) + error(WARNING, "#line specifies number out of range"); + tp = tp + 1; + if (tp + 1 < trp->lp) + cursource->filename = (char *) newstring(tp->t + 1, tp->len - 2, 0); + return; + + case KDEFINED: + error(ERROR, "Bad syntax for control line"); + break; + + case KIMPORT: + doinclude(trp, -1, 1); + trp->lp = trp->bp; + return; + + case KINCLUDE: + doinclude(trp, -1, 0); + trp->lp = trp->bp; + return; + + case KINCLUDENEXT: + doinclude(trp, cursource->pathdepth, 0); + trp->lp = trp->bp; + return; + + case KEVAL: + eval(trp, np->val); + break; + + default: + error(ERROR, "Preprocessor control `%t' not yet implemented", tp); + break; + } + setempty(trp); + return; +} + +void * + domalloc(size_t size) +{ + void *p = malloc(size); + + if (p == NULL) + error(FATAL, "Out of memory from malloc"); + return p; +} + +void + dofree(void *p) +{ + free(p); +} + +void + error(enum errtype type, char *string,...) +{ + va_list ap; + char c, *cp, *ep; + Token *tp; + Tokenrow *trp; + Source *s; + int i; + + fprintf(stderr, "cpp: "); + for (s = cursource; s; s = s->next) + if (*s->filename) + fprintf(stderr, "%s:%d ", s->filename, s->line); + va_start(ap, string); + for (ep = string; *ep; ep++) + { + if (*ep == '%') + { + switch (*++ep) + { + + case 'c': + c = (char) va_arg(ap, int); + fprintf(stderr, "%c", c); + break; + + case 's': + cp = va_arg(ap, char *); + fprintf(stderr, "%s", cp); + break; + + case 'd': + i = va_arg(ap, int); + fprintf(stderr, "%d", i); + break; + + case 't': + tp = va_arg(ap, Token *); + fprintf(stderr, "%.*s", (int)tp->len, tp->t); + break; + + case 'r': + trp = va_arg(ap, Tokenrow *); + for (tp = trp->tp; tp < trp->lp && tp->type != NL; tp++) + { + if (tp > trp->tp && tp->wslen) + fputc(' ', stderr); + fprintf(stderr, "%.*s", (int)tp->len, tp->t); + } + break; + + default: + fputc(*ep, stderr); + break; + } + } + else + fputc(*ep, stderr); + } + va_end(ap); + fputc('\n', stderr); + if (type == FATAL) + exit(1); + if (type != WARNING) + nerrs = 1; + fflush(stderr); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/soltools/cpp/_eval.c b/soltools/cpp/_eval.c new file mode 100644 index 000000000..dba04abf4 --- /dev/null +++ b/soltools/cpp/_eval.c @@ -0,0 +1,795 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "cpp.h" + +#define NSTAK 32 +#define SGN 0 +#define UNS 1 +#define UND 2 + +#define UNSMARK 0x1000 + +struct value +{ + int val; + int type; +}; + +/* conversion types */ +#define RELAT 1 +#define ARITH 2 +#define LOGIC 3 +#define SPCL 4 +#define SHIFT 5 +#define UNARY 6 + +/* operator priority, arity, and conversion type, indexed by tokentype */ +struct pri +{ + char pri; + char arity; + char ctype; +}; + +static const struct pri priority[] = +{ + { + 0, 0, 0 + }, /* END */ + { + 0, 0, 0 + }, /* UNCLASS */ + { + 0, 0, 0 + }, /* NAME */ + { + 0, 0, 0 + }, /* NUMBER */ + { + 0, 0, 0 + }, /* STRING */ + { + 0, 0, 0 + }, /* CCON */ + { + 0, 0, 0 + }, /* NL */ + { + 0, 0, 0 + }, /* WS */ + { + 0, 0, 0 + }, /* DSHARP */ + { + 11, 2, RELAT + }, /* EQ */ + { + 11, 2, RELAT + }, /* NEQ */ + { + 12, 2, RELAT + }, /* LEQ */ + { + 12, 2, RELAT + }, /* GEQ */ + { + 13, 2, SHIFT + }, /* LSH */ + { + 13, 2, SHIFT + }, /* RSH */ + { + 7, 2, LOGIC + }, /* LAND */ + { + 6, 2, LOGIC + }, /* LOR */ + { + 0, 0, 0 + }, /* PPLUS */ + { + 0, 0, 0 + }, /* MMINUS */ + { + 0, 0, 0 + }, /* ARROW */ + { + 0, 0, 0 + }, /* SBRA */ + { + 0, 0, 0 + }, /* SKET */ + { + 3, 0, 0 + }, /* LP */ + { + 3, 0, 0 + }, /* RP */ + { + 0, 0, 0 + }, /* DOT */ + { + 10, 2, ARITH + }, /* AND */ + { + 15, 2, ARITH + }, /* STAR */ + { + 14, 2, ARITH + }, /* PLUS */ + { + 14, 2, ARITH + }, /* MINUS */ + { + 16, 1, UNARY + }, /* TILDE */ + { + 16, 1, UNARY + }, /* NOT */ + { + 15, 2, ARITH + }, /* SLASH */ + { + 15, 2, ARITH + }, /* PCT */ + { + 12, 2, RELAT + }, /* LT */ + { + 12, 2, RELAT + }, /* GT */ + { + 9, 2, ARITH + }, /* CIRC */ + { + 8, 2, ARITH + }, /* OR */ + { + 5, 2, SPCL + }, /* QUEST */ + { + 5, 2, SPCL + }, /* COLON */ + { + 0, 0, 0 + }, /* ASGN */ + { + 4, 2, 0 + }, /* COMMA */ + { + 0, 0, 0 + }, /* SHARP */ + { + 0, 0, 0 + }, /* SEMIC */ + { + 0, 0, 0 + }, /* CBRA */ + { + 0, 0, 0 + }, /* CKET */ + { + 0, 0, 0 + }, /* ASPLUS */ + { + 0, 0, 0 + }, /* ASMINUS */ + { + 0, 0, 0 + }, /* ASSTAR */ + { + 0, 0, 0 + }, /* ASSLASH */ + { + 0, 0, 0 + }, /* ASPCT */ + { + 0, 0, 0 + }, /* ASCIRC */ + { + 0, 0, 0 + }, /* ASLSH */ + { + 0, 0, 0 + }, /* ASRSH */ + { + 0, 0, 0 + }, /* ASOR */ + { + 0, 0, 0 + }, /* ASAND */ + { + 0, 0, 0 + }, /* ELLIPS */ + { + 0, 0, 0 + }, /* DSHARP1 */ + { + 0, 0, 0 + }, /* NAME1 */ + { + 0, 0, 0 + }, /* NAME2 */ + { + 16, 1, UNARY + }, /* DEFINED */ + { + 16, 0, UNARY + }, /* UMINUS */ + { + 16, 1, UNARY + }, /* ARCHITECTURE */ +}; + +static int evalop(struct pri); +static struct value tokval(Token *); +static struct value vals[NSTAK], *vp; +static enum toktype ops[NSTAK], *op; + +/* + * Evaluate an #if #elif #ifdef #ifndef line. trp->tp points to the keyword. + */ +long + eval(Tokenrow * trp, int kw) +{ + Token *tp; + Nlist *np; + size_t ntok; + int rnd; + + trp->tp++; + if (kw == KIFDEF || kw == KIFNDEF) + { + if (trp->lp - trp->bp != 4 || trp->tp->type != NAME) + { + error(ERROR, "Syntax error in #ifdef/#ifndef"); + return 0; + } + np = lookup(trp->tp, 0); + return (kw == KIFDEF) == (np && np->flag & (ISDEFINED | ISMAC)); + } + ntok = trp->tp - trp->bp; + kwdefined->val = KDEFINED; /* activate special meaning of + * defined */ + expandrow(trp, "<if>"); + kwdefined->val = NAME; + vp = vals; + op = ops; + *op++ = END; + for (rnd = 0, tp = trp->bp + ntok; tp < trp->lp; tp++) + { + switch (tp->type) + { + case WS: + case NL: + continue; + + /* nilary */ + case NAME: + case NAME1: + case NAME2: + case NUMBER: + case CCON: + case STRING: + if (rnd) + goto syntax; + *vp++ = tokval(tp); + rnd = 1; + continue; + + /* unary */ + case DEFINED: + case TILDE: + case NOT: + if (rnd) + goto syntax; + *op++ = tp->type; + continue; + + /* unary-binary */ + case PLUS: + case MINUS: + case STAR: + case AND: + if (rnd == 0) + { + if (tp->type == MINUS) + *op++ = UMINUS; + if (tp->type == STAR || tp->type == AND) + { + error(ERROR, "Illegal operator * or & in #if/#elif"); + return 0; + } + continue; + } + /* fall through */ + + /* plain binary */ + case EQ: + case NEQ: + case LEQ: + case GEQ: + case LSH: + case RSH: + case LAND: + case LOR: + case SLASH: + case PCT: + case LT: + case GT: + case CIRC: + case OR: + case QUEST: + case COLON: + case COMMA: + if (rnd == 0) + goto syntax; + if (evalop(priority[tp->type]) != 0) + return 0; + *op++ = tp->type; + rnd = 0; + continue; + + case LP: + if (rnd) + goto syntax; + *op++ = LP; + continue; + + case RP: + if (!rnd) + goto syntax; + if (evalop(priority[RP]) != 0) + return 0; + if (op <= ops || op[-1] != LP) + { + goto syntax; + } + op--; + continue; + + case SHARP: + if ((tp + 1) < trp->lp) + { + np = lookup(tp + 1, 0); + if (np && (np->val == KMACHINE)) + { + tp++; + if (rnd) + goto syntax; + *op++ = ARCHITECTURE; + continue; + } + } + /* fall through */ + + default: + error(ERROR, "Bad operator (%t) in #if/#elif", tp); + return 0; + } + } + if (rnd == 0) + goto syntax; + if (evalop(priority[END]) != 0) + return 0; + if (op != &ops[1] || vp != &vals[1]) + { + error(ERROR, "Botch in #if/#elif"); + return 0; + } + if (vals[0].type == UND) + error(ERROR, "Undefined expression value"); + return vals[0].val; +syntax: + error(ERROR, "Syntax error in #if/#elif"); + return 0; +} + +int + evalop(struct pri pri) +{ + struct value v1; + struct value v2 = { 0, UND }; + int rv1, rv2; + int rtype, oper; + + rv2 = 0; + rtype = 0; + while (pri.pri < priority[op[-1]].pri) + { + oper = *--op; + if (priority[oper].arity == 2) + { + v2 = *--vp; + rv2 = v2.val; + } + v1 = *--vp; + rv1 = v1.val; +/*lint -e574 -e644 */ + switch (priority[oper].ctype) + { + case 0: + default: + error(WARNING, "Syntax error in #if/#endif"); + return 1; + case ARITH: + case RELAT: + if (v1.type == UNS || v2.type == UNS) + rtype = UNS; + else + rtype = SGN; + if (v1.type == UND || v2.type == UND) + rtype = UND; + if (priority[oper].ctype == RELAT && rtype == UNS) + { + oper |= UNSMARK; + rtype = SGN; + } + break; + case SHIFT: + if (v1.type == UND || v2.type == UND) + rtype = UND; + else + rtype = v1.type; + if (rtype == UNS) + oper |= UNSMARK; + break; + case UNARY: + rtype = v1.type; + break; + case LOGIC: + case SPCL: + break; + } + switch (oper) + { + case EQ: + case EQ | UNSMARK: + rv1 = rv1 == rv2; + break; + case NEQ: + case NEQ | UNSMARK: + rv1 = rv1 != rv2; + break; + case LEQ: + rv1 = rv1 <= rv2; + break; + case GEQ: + rv1 = rv1 >= rv2; + break; + case LT: + rv1 = rv1 < rv2; + break; + case GT: + rv1 = rv1 > rv2; + break; + case LEQ | UNSMARK: + rv1 = (unsigned long)rv1 <= (unsigned long)rv2; + break; + case GEQ | UNSMARK: + rv1 = (unsigned long)rv1 >= (unsigned long)rv2; + break; + case LT | UNSMARK: + rv1 = (unsigned long)rv1 < (unsigned long)rv2; + break; + case GT | UNSMARK: + rv1 = (unsigned long)rv1 > (unsigned long)rv2; + break; + case LSH: + rv1 <<= rv2; + break; + case LSH | UNSMARK: + rv1 = (unsigned long) rv1 << rv2; + break; + case RSH: + rv1 >>= rv2; + break; + case RSH | UNSMARK: + rv1 = (unsigned long) rv1 >> rv2; + break; + case LAND: + rtype = UND; + if (v1.type == UND) + break; + if (rv1 != 0) + { + if (v2.type == UND) + break; + rv1 = rv2 != 0; + } + else + rv1 = 0; + rtype = SGN; + break; + case LOR: + rtype = UND; + if (v1.type == UND) + break; + if (rv1 == 0) + { + if (v2.type == UND) + break; + rv1 = rv2 != 0; + } + else + rv1 = 1; + rtype = SGN; + break; + case AND: + rv1 &= rv2; + break; + case STAR: + rv1 *= rv2; + break; + case PLUS: + rv1 += rv2; + break; + case MINUS: + rv1 -= rv2; + break; + case UMINUS: + if (v1.type == UND) + rtype = UND; + rv1 = -rv1; + break; + case OR: + rv1 |= rv2; + break; + case CIRC: + rv1 ^= rv2; + break; + case TILDE: + rv1 = ~rv1; + break; + case NOT: + rv1 = !rv1; + if (rtype != UND) + rtype = SGN; + break; + case SLASH: + if (rv2 == 0) + { + rtype = UND; + break; + } + if (rtype == UNS) + rv1 /= (unsigned long) rv2; + else + rv1 /= rv2; + break; + case PCT: + if (rv2 == 0) + { + rtype = UND; + break; + } + if (rtype == UNS) + rv1 %= (unsigned long) rv2; + else + rv1 %= rv2; + break; + case COLON: + if (op[-1] != QUEST) + error(ERROR, "Bad ?: in #if/endif"); + else + { + op--; + if ((--vp)->val == 0) + v1 = v2; + rtype = v1.type; + rv1 = v1.val; + } + break; + + case DEFINED: + case ARCHITECTURE: + break; + + default: + error(ERROR, "Eval botch (unknown operator)"); + return 1; + } +/*lint +e574 +e644 */ + v1.val = rv1; + v1.type = rtype; + *vp++ = v1; + } + return 0; +} + +struct value + tokval(Token * tp) +{ + struct value v; + Nlist *np; + int i, base; + unsigned int n; + uchar *p, c; + + v.type = SGN; + v.val = 0; + switch (tp->type) + { + + case NAME: + v.val = 0; + break; + + case NAME1: + np = lookup(tp, 0); + if (np != NULL && np->flag & (ISDEFINED | ISMAC)) + v.val = 1; + break; + + case NAME2: + np = lookup(tp, 0); + if (np != NULL && np->flag & (ISARCHITECTURE)) + v.val = 1; + break; + + case NUMBER: + n = 0; + base = 10; + p = tp->t; + c = p[tp->len]; + p[tp->len] = '\0'; + if (*p == '0') + { + base = 8; + if (p[1] == 'x' || p[1] == 'X') + { + base = 16; + p++; + } + p++; + } + for (;; p++) + { + if ((i = digit(*p)) < 0) + break; + if (i >= base) + error(WARNING, + "Bad digit in number %t", tp); + n *= base; + n += i; + } + if (n >= 0x80000000 && base != 10) + v.type = UNS; + for (; *p; p++) + { + if (*p == 'u' || *p == 'U') + v.type = UNS; + else + if (*p == 'l' || *p == 'L') + ; + else + { + error(ERROR, + "Bad number %t in #if/#elif", tp); + break; + } + } + v.val = n; + tp->t[tp->len] = c; + break; + + case CCON: + n = 0; + p = tp->t; + if (*p == 'L') + { + p += 1; + error(WARNING, "Wide char constant value undefined"); + } + p += 1; + if (*p == '\\') + { + p += 1; + i = digit(*p); + if (i >= 0 && i <= 7) + { + n = i; + p += 1; + i = digit(*p); + if (i >= 0 && i <= 7) + { + p += 1; + n <<= 3; + n += i; + i = digit(*p); + if (i >= 0 && i <= 7) + { + p += 1; + n <<= 3; + n += i; + } + } + } + else + if (*p == 'x') + { + p += 1; + while (1) + { + i = digit(*p); + if (i < 0 || i > 16) + break; + p += 1; + n <<= 4; + n += i; + } + } + else + { + static const char cvcon[] = "b\bf\fn\nr\rt\tv\v''\"\"??\\\\"; + static size_t cvlen = sizeof(cvcon) - 1; + + size_t j; + for (j = 0; j < cvlen; j += 2) + { + if (*p == cvcon[j]) + { + n = cvcon[j + 1]; + break; + } + } + p += 1; + if (j >= cvlen) + error(WARNING, + "Undefined escape in character constant"); + } + } + else + if (*p == '\'') + error(ERROR, "Empty character constant"); + else + n = *p++; + if (*p != '\'') + error(WARNING, "Multibyte character constant undefined"); + else + if (n > 127) + error(WARNING, "Character constant taken as not signed"); + v.val = n; + break; + + case STRING: + error(ERROR, "String in #if/#elif"); + break; + } + return v; +} + +int + digit(int i) +{ + if ('0' <= i && i <= '9') + i -= '0'; + else + if ('a' <= i && i <= 'f') + i -= 'a' - 10; + else + if ('A' <= i && i <= 'F') + i -= 'A' - 10; + else + i = -1; + return i; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/soltools/cpp/_getopt.c b/soltools/cpp/_getopt.c new file mode 100644 index 000000000..b41147c3e --- /dev/null +++ b/soltools/cpp/_getopt.c @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <stdio.h> +#include <string.h> + +#include "_getopt.h" + +#define EPR fprintf(stderr, +#define ERR(str, chr) if(opterr) { EPR "%s%c\n", str, chr); } + +static int opterr = 1; +int optind = 1; +static int optopt; +char *optarg; + +int + stgetopt(int argc, char *const argv[], const char *opts) +{ + static int sp = 1; + int c; + char *cp; + + if (sp == 1) + { + if (optind >= argc || + argv[optind][0] != '-' || argv[optind][1] == '\0') + return -1; + else if (strcmp(argv[optind], "--") == 0) + { + optind++; + return -1; + } + else if (strcmp(argv[optind], "-isysroot") == 0) + { + // skip macOS SDK selection flags + optind++; optind++; + } + } + optopt = c = argv[optind][sp]; + if (c == ':' || (cp = strchr(opts, c)) == NULL) + { + ERR(": illegal option -- ", c); + if (argv[optind][++sp] == '\0') + { + optind++; + sp = 1; + } + return '?'; + } + if (*++cp == ':') + { + if (argv[optind][sp + 1] != '\0') + optarg = &argv[optind++][sp + 1]; + else + if (++optind >= argc) + { + ERR(": option requires an argument -- ", c); + sp = 1; + return '?'; + } + else + optarg = argv[optind++]; + sp = 1; + } + else + { + if (argv[optind][++sp] == '\0') + { + sp = 1; + optind++; + } + optarg = NULL; + } + return c; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/soltools/cpp/_getopt.h b/soltools/cpp/_getopt.h new file mode 100644 index 000000000..c894c2c91 --- /dev/null +++ b/soltools/cpp/_getopt.h @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SOLTOOLS_CPP__GETOPT_H +#define INCLUDED_SOLTOOLS_CPP__GETOPT_H + +int stgetopt(int, char *const [], const char *); +extern char *optarg; +extern int optind; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/soltools/cpp/_include.c b/soltools/cpp/_include.c new file mode 100644 index 000000000..19d14ae68 --- /dev/null +++ b/soltools/cpp/_include.c @@ -0,0 +1,250 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#if (defined(_WIN32) || defined(__IBMC__)) +# include <io.h> +#else +# include <unistd.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> + +#if defined(__IBMC__) || defined(__EMX__) || defined(_MSC_VER) +# include <fcntl.h> +# ifndef PATH_MAX +# define PATH_MAX _MAX_PATH +# endif +#endif +#include <limits.h> + +#include "cpp.h" + +Includelist includelist[NINCLUDE]; +Wraplist wraplist[NINCLUDE]; + +void + doinclude(Tokenrow * trp, int depth, int import) +{ + char fname[PATH_MAX], iname[PATH_MAX]; + Includelist *ip; + int angled, fd, i; + size_t len; + + trp->tp += 1; + if (trp->tp >= trp->lp) + goto syntax; + if (trp->tp->type != STRING && trp->tp->type != LT) + { + len = trp->tp - trp->bp; + expandrow(trp, "<include>"); + trp->tp = trp->bp + len; + } + if (trp->tp->type == STRING) + { + len = trp->tp->len - 2; + if (len > sizeof(fname) - 1) + len = sizeof(fname) - 1; + strncpy(fname, (char *) trp->tp->t + 1, len); + angled = 0; + } + else + { + if (trp->tp->type == LT) + { + len = 0; + trp->tp++; + while (trp->tp->type != GT) + { + if (trp->tp > trp->lp || len + trp->tp->len + 2 >= sizeof(fname)) + goto syntax; + strncpy(fname + len, (char *) trp->tp->t, trp->tp->len); + len += trp->tp->len; + trp->tp++; + } + angled = 1; + } + else + goto syntax; + } + trp->tp += 2; + if (trp->tp < trp->lp || len == 0) + goto syntax; + fname[len] = '\0'; + if (fname[0] == '/') + { + fd = open(fname, O_RDONLY); + strcpy(iname, fname); + } + else + { + for (fd = -1, i = (depth < 0) ? (NINCLUDE - 1) : (depth - 1); i >= 0; i--) + { + ip = &includelist[i]; + if (ip->file == NULL || ip->deleted || (angled && ip->always == 0)) + continue; + if (strlen(fname) + strlen(ip->file) + 2 > sizeof(iname)) + continue; + strcpy(iname, ip->file); + strcat(iname, "/"); + strcat(iname, fname); + if ((fd = open(iname, O_RDONLY)) >= 0) + break; + } + } + + if (fd >= 0) + { + if (++incdepth > NINC ) + error(FATAL, "#%s too deeply nested", import ? "import" : "include"); + if (Xflag) + genimport(fname, angled, iname, import); + if (Iflag) + error(INFO, "Open %s file [%s]", import ? "import" : "include", iname ); + + for (i = NINCLUDE - 1; i >= 0; i--) + { + if ((wraplist[i].file != NULL) && + (strncmp(wraplist[i].file, iname, strlen(wraplist[i].file)) == 0)) + break; + } + + setsource((char *) newstring((uchar *) iname, strlen(iname), 0), i, fd, NULL, (i >= 0) ? 1 : 0); + + if (!Pflag) + genline(); + } + else + { + trp->tp = trp->bp + 2; + error(ERROR, "Could not find %s file %r", import ? "import" : "include", trp); + } + return; +syntax: + error(ERROR, "Syntax error in #%s", import ? "import" : "include"); + return; +} + +/* + * Generate a line directive for cursource + */ +void + genline(void) +{ + static Token ta = {UNCLASS, 0, 0, NULL, 0}; + static Tokenrow tr = {&ta, &ta, &ta + 1, 1}; + uchar *p; + + ta.t = p = (uchar *) outptr; + strcpy((char *) p, "#line "); + p += sizeof("#line ") - 1; + p = (uchar *) outnum((char *) p, cursource->line); + *p++ = ' '; + *p++ = '"'; + if (cursource->filename[0] != '/' && wd[0]) + { + strcpy((char *) p, wd); + p += strlen(wd); + *p++ = '/'; + } + strcpy((char *) p, cursource->filename); + p += strlen((char *) p); + *p++ = '"'; + *p++ = '\n'; + ta.len = (char *) p - outptr; + outptr = (char *) p; + tr.tp = tr.bp; + puttokens(&tr); +} + +/* + * Generate a pragma import/include directive + */ +void + genimport(char const *fname, int angled, char const *iname, int import) +{ + static Token ta = {UNCLASS, 0, 0, NULL, 0}; + static Tokenrow tr = {&ta, &ta, &ta + 1, 1}; + uchar *p; + + ta.t = p = (uchar *) outptr; + + if (import) + strcpy((char *) p, "#pragma import"); + else + strcpy((char *) p, "#pragma include"); + + p += strlen((char *) p); + + *p++ = '('; + + *p++ = angled ? '<' : '"'; + strcpy((char *) p, fname); + p += strlen(fname); + *p++ = angled ? '>' : '"'; + + *p++ = ','; + + *p++ = '"'; + strcpy((char *) p, iname); + p += strlen(iname); + *p++ = '"'; + + *p++ = ')'; + *p++ = '\n'; + + ta.len = (char *) p - outptr; + outptr = (char *) p; + tr.tp = tr.bp; + puttokens(&tr); +} + +/* + * Generate an extern C directive + */ +void + genwrap(int end) +{ + static Token ta = {UNCLASS, 0, 0, NULL, 0}; + static Tokenrow tr = {&ta, &ta, &ta + 1, 1}; + uchar *p; + + if (!Cplusplus) + return; + + ta.t = p = (uchar *) outptr; + + if (! end) + strcpy((char *) p, "extern \"C\" {"); + else + strcpy((char *) p, "}"); + + p += strlen((char *) p); + + *p++ = '\n'; + + ta.len = (char *) p - outptr; + outptr = (char *) p; + tr.tp = tr.bp; + puttokens(&tr); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/soltools/cpp/_lex.c b/soltools/cpp/_lex.c new file mode 100644 index 000000000..28fae7a54 --- /dev/null +++ b/soltools/cpp/_lex.c @@ -0,0 +1,707 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#if (defined(_WIN32) || defined(__IBMC__)) +#include <io.h> +#else +#include <unistd.h> +#endif +#include "cpp.h" +/* + * lexical FSM encoding + * when in state state, and one of the characters + * in ch arrives, enter nextstate. + * States >= S_SELF are either final, or at least require special action. + * In 'fsm' there is a line for each state X charset X nextstate. + * List chars that overwrite previous entries later (e.g. C_ALPH + * can be overridden by '_' by a later entry; and C_XX is the + * universal set, and should always be first. + * States above S_SELF are represented in the big table as negative values. + * S_SELF and S_SELFB encode the resulting token type in the upper bits. + * These actions differ in that S_SELF doesn't have a lookahead char, + * S_SELFB does. + * + * The encoding is blown out into a big table for time-efficiency. + * Entries have + * nextstate: 6 bits; ?\ marker: 1 bit; tokentype: 9 bits. + */ + +#define MAXSTATE 32 +#define ACT(tok,act) ((tok<<7)+act) +#define QBSBIT 0100 +#define GETACT(st) ((st>>7)&0x1ff) + +/* character classes */ +#define C_ALPH 1 +#define C_NUM 2 +#define C_XX 3 + +enum state +{ + START = 0, NUM1, NUM2, NUM3, ID1, ST1, ST2, ST3, COM1, COM2, COM3, COM4, + CC1, CC2, WS1, PLUS1, MINUS1, STAR1, PCT1, SHARP1, + CIRC1, GT1, GT2, LT1, LT2, OR1, AND1, ASG1, NOT1, DOTS1, + S_SELF = MAXSTATE, S_SELFB, S_EOF, S_NL, S_EOFSTR, + S_STNL, S_COMNL, S_EOFCOM, S_COMMENT, S_EOB, S_WS, S_NAME +}; + +struct fsm +{ + int state; /* if in this state */ + uchar ch[4]; /* and see one of these characters */ + int nextstate; /* enter this state if +ve */ +}; + +static const struct fsm fsm[] = { + /* start state */ + {START, {C_XX}, ACT(UNCLASS, S_SELF)}, + {START, {' ', '\t', '\v'}, WS1}, + {START, {C_NUM}, NUM1}, + {START, {'.'}, NUM3}, + {START, {C_ALPH}, ID1}, + {START, {'L'}, ST1}, + {START, {'"'}, ST2}, + {START, {'\''}, CC1}, + {START, {'/'}, COM1}, + {START, {EOFC}, S_EOF}, + {START, {'\n'}, S_NL}, + {START, {'-'}, MINUS1}, + {START, {'+'}, PLUS1}, + {START, {'<'}, LT1}, + {START, {'>'}, GT1}, + {START, {'='}, ASG1}, + {START, {'!'}, NOT1}, + {START, {'&'}, AND1}, + {START, {'|'}, OR1}, + {START, {'#'}, SHARP1}, + {START, {'%'}, PCT1}, + {START, {'['}, ACT(SBRA, S_SELF)}, + {START, {']'}, ACT(SKET, S_SELF)}, + {START, {'('}, ACT(LP, S_SELF)}, + {START, {')'}, ACT(RP, S_SELF)}, + {START, {'*'}, STAR1}, + {START, {','}, ACT(COMMA, S_SELF)}, + {START, {'?'}, ACT(QUEST, S_SELF)}, + {START, {':'}, ACT(COLON, S_SELF)}, + {START, {';'}, ACT(SEMIC, S_SELF)}, + {START, {'{'}, ACT(CBRA, S_SELF)}, + {START, {'}'}, ACT(CKET, S_SELF)}, + {START, {'~'}, ACT(TILDE, S_SELF)}, + {START, {'^'}, CIRC1}, + + /* saw a digit */ + {NUM1, {C_XX}, ACT(NUMBER, S_SELFB)}, + {NUM1, {C_NUM, C_ALPH, '.'}, NUM1}, + {NUM1, {'E', 'e'}, NUM2}, + {NUM1, {'_'}, ACT(NUMBER, S_SELFB)}, + + /* saw possible start of exponent, digits-e */ + {NUM2, {C_XX}, ACT(NUMBER, S_SELFB)}, + {NUM2, {'+', '-'}, NUM1}, + {NUM2, {C_NUM, C_ALPH}, NUM1}, + {NUM2, {'_'}, ACT(NUMBER, S_SELFB)}, + + /* saw a '.', which could be a number or an operator */ + {NUM3, {C_XX}, ACT(DOT, S_SELFB)}, + {NUM3, {'.'}, DOTS1}, + {NUM3, {C_NUM}, NUM1}, + + {DOTS1, {C_XX}, ACT(UNCLASS, S_SELFB)}, + {DOTS1, {C_NUM}, NUM1}, + {DOTS1, {'.'}, ACT(ELLIPS, S_SELF)}, + + /* saw a letter or _ */ + {ID1, {C_XX}, ACT(NAME, S_NAME)}, + {ID1, {C_ALPH, C_NUM}, ID1}, + + /* saw L (start of wide string?) */ + {ST1, {C_XX}, ACT(NAME, S_NAME)}, + {ST1, {C_ALPH, C_NUM}, ID1}, + {ST1, {'"'}, ST2}, + {ST1, {'\''}, CC1}, + + /* saw " beginning string */ + {ST2, {C_XX}, ST2}, + {ST2, {'"'}, ACT(STRING, S_SELF)}, + {ST2, {'\\'}, ST3}, + {ST2, {'\n'}, S_STNL}, + {ST2, {EOFC}, S_EOFSTR}, + + /* saw \ in string */ + {ST3, {C_XX}, ST2}, + {ST3, {'\n'}, S_STNL}, + {ST3, {EOFC}, S_EOFSTR}, + + /* saw ' beginning character const */ + {CC1, {C_XX}, CC1}, + {CC1, {'\''}, ACT(CCON, S_SELF)}, + {CC1, {'\\'}, CC2}, + {CC1, {'\n'}, S_STNL}, + {CC1, {EOFC}, S_EOFSTR}, + + /* saw \ in ccon */ + {CC2, {C_XX}, CC1}, + {CC2, {'\n'}, S_STNL}, + {CC2, {EOFC}, S_EOFSTR}, + + /* saw /, perhaps start of comment */ + {COM1, {C_XX}, ACT(SLASH, S_SELFB)}, + {COM1, {'='}, ACT(ASSLASH, S_SELF)}, + {COM1, {'*'}, COM2}, + {COM1, {'/'}, COM4}, + + /* saw / followed by *, start of comment */ + {COM2, {C_XX}, COM2}, + {COM2, {'\n'}, S_COMNL}, + {COM2, {'*'}, COM3}, + {COM2, {EOFC}, S_EOFCOM}, + + /* saw the * possibly ending a comment */ + {COM3, {C_XX}, COM2}, + {COM3, {'\n'}, S_COMNL}, + {COM3, {'*'}, COM3}, + {COM3, {'/'}, S_COMMENT}, + + /* // comment */ + {COM4, {C_XX}, COM4}, + {COM4, {'\n'}, S_NL}, + {COM4, {EOFC}, S_EOFCOM}, + + /* saw white space, eat it up */ + {WS1, {C_XX}, S_WS}, + {WS1, {'\t', '\v', ' '}, WS1}, + + /* saw -, check --, -=, -> */ + {MINUS1, {C_XX}, ACT(MINUS, S_SELFB)}, + {MINUS1, {'-'}, ACT(MMINUS, S_SELF)}, + {MINUS1, {'='}, ACT(ASMINUS, S_SELF)}, + {MINUS1, {'>'}, ACT(ARROW, S_SELF)}, + + /* saw +, check ++, += */ + {PLUS1, {C_XX}, ACT(PLUS, S_SELFB)}, + {PLUS1, {'+'}, ACT(PPLUS, S_SELF)}, + {PLUS1, {'='}, ACT(ASPLUS, S_SELF)}, + + /* saw <, check <<, <<=, <= */ + {LT1, {C_XX}, ACT(LT, S_SELFB)}, + {LT1, {'<'}, LT2}, + {LT1, {'='}, ACT(LEQ, S_SELF)}, + {LT2, {C_XX}, ACT(LSH, S_SELFB)}, + {LT2, {'='}, ACT(ASLSH, S_SELF)}, + + /* saw >, check >>, >>=, >= */ + {GT1, {C_XX}, ACT(GT, S_SELFB)}, + {GT1, {'>'}, GT2}, + {GT1, {'='}, ACT(GEQ, S_SELF)}, + {GT2, {C_XX}, ACT(RSH, S_SELFB)}, + {GT2, {'='}, ACT(ASRSH, S_SELF)}, + + /* = */ + {ASG1, {C_XX}, ACT(ASGN, S_SELFB)}, + {ASG1, {'='}, ACT(EQ, S_SELF)}, + + /* ! */ + {NOT1, {C_XX}, ACT(NOT, S_SELFB)}, + {NOT1, {'='}, ACT(NEQ, S_SELF)}, + + /* & */ + {AND1, {C_XX}, ACT(AND, S_SELFB)}, + {AND1, {'&'}, ACT(LAND, S_SELF)}, + {AND1, {'='}, ACT(ASAND, S_SELF)}, + + /* | */ + {OR1, {C_XX}, ACT(OR, S_SELFB)}, + {OR1, {'|'}, ACT(LOR, S_SELF)}, + {OR1, {'='}, ACT(ASOR, S_SELF)}, + + /* # */ + {SHARP1, {C_XX}, ACT(SHARP, S_SELFB)}, + {SHARP1, {'#'}, ACT(DSHARP, S_SELF)}, + + /* % */ + {PCT1, {C_XX}, ACT(PCT, S_SELFB)}, + {PCT1, {'='}, ACT(ASPCT, S_SELF)}, + + /* * */ + {STAR1, {C_XX}, ACT(STAR, S_SELFB)}, + {STAR1, {'='}, ACT(ASSTAR, S_SELF)}, + + /* ^ */ + {CIRC1, {C_XX}, ACT(CIRC, S_SELFB)}, + {CIRC1, {'='}, ACT(ASCIRC, S_SELF)}, + + {-1, "", 0} +}; + +/* first index is char, second is state */ +/* increase #states to power of 2 to encourage use of shift */ +static short bigfsm[256][MAXSTATE]; + +void + expandlex(void) +{ + const struct fsm *fp; + int i, j, nstate; + + for (fp = fsm; fp->state >= 0; fp++) + { + for (i = 0; fp->ch[i]; i++) + { + nstate = fp->nextstate; + if (nstate >= S_SELF) + nstate = ~nstate; + switch (fp->ch[i]) + { + + case C_XX: /* random characters */ + for (j = 0; j < 256; j++) + bigfsm[j][fp->state] = (short) nstate; + continue; + case C_ALPH: + for (j = 0; j < 256; j++) + if (('a' <= j && j <= 'z') || ('A' <= j && j <= 'Z') + || j == '_') + bigfsm[j][fp->state] = (short) nstate; + continue; + case C_NUM: + for (j = '0'; j <= '9'; j++) + bigfsm[j][fp->state] = (short) nstate; + continue; + default: + bigfsm[fp->ch[i]][fp->state] = (short) nstate; + } + } + } + + /* + * install special cases for ? (trigraphs), \ (splicing), runes, and + * EOB + */ + for (i = 0; i < MAXSTATE; i++) + { + for (j = 0; j < 0xFF; j++) + if (j == '?' || j == '\\' || j == '\n' || j == '\r') + { + if (bigfsm[j][i] > 0) + bigfsm[j][i] = ~bigfsm[j][i]; + bigfsm[j][i] &= ~QBSBIT; + } + bigfsm[EOB][i] = ~S_EOB; + if (bigfsm[EOFC][i] >= 0) + bigfsm[EOFC][i] = ~S_EOF; + } +} + +void + fixlex(void) +{ + /* do C++ comments? */ + if ((Cplusplus == 0) || (Cflag != 0)) + bigfsm['/'][COM1] = bigfsm['x'][COM1]; +} + +/* + * fill in a row of tokens from input, terminated by NL or END + * First token is put at trp->lp. + * Reset is non-zero when the input buffer can be "rewound." + * The value is a flag indicating that possible macros have + * been seen in the row. + */ +int + gettokens(Tokenrow * trp, int reset) +{ + int c, state, oldstate; + uchar *ip; + Token *tp, *maxp; + int runelen; + Source *s = cursource; + int nmac = 0; + + tp = trp->lp; + ip = s->inp; + if (reset) + { + s->lineinc = 0; + if (ip >= s->inl) + { /* nothing in buffer */ + s->inl = s->inb; + fillbuf(s); + ip = s->inp = s->inb; + } + else + if (ip >= s->inb + (3 * INS / 4)) + { + memmove(s->inb, ip, 4 + s->inl - ip); + s->inl = s->inb + (s->inl - ip); + ip = s->inp = s->inb; + } + } + maxp = &trp->bp[trp->max]; + runelen = 1; + for (;;) + { +continue2: + if (tp >= maxp) + { + trp->lp = tp; + tp = growtokenrow(trp); + // coverity[overrun-local : FALSE] - a multiple of trp->max is allocated, not trp->max itself + maxp = &trp->bp[trp->max]; + } + tp->type = UNCLASS; + tp->t = ip; + tp->wslen = 0; + state = START; + for (;;) + { + oldstate = state; + + c = *ip; + + if ((state = bigfsm[c][state]) >= 0) + { + ip += runelen; + runelen = 1; + continue; + } + state = ~state; + reswitch: + switch (state & 0177) + { + case S_SELF: + ip += runelen; + runelen = 1; + /*fall-through*/ + case S_SELFB: + tp->type = (unsigned char) GETACT(state); + tp->len = ip - tp->t; + tp++; + goto continue2; + + case S_NAME: /* like S_SELFB but with nmac check */ + tp->type = NAME; + tp->len = ip - tp->t; + nmac |= quicklook(tp->t[0], tp->len > 1 ? tp->t[1] : 0); + tp++; + goto continue2; + + case S_WS: + tp->wslen = ip - tp->t; + tp->t = ip; + state = START; + continue; + + default: + if ((state & QBSBIT) == 0) + { + ip += runelen; + runelen = 1; + continue; + } + state &= ~QBSBIT; + s->inp = ip; + + if (c == '\n') + { + while (s->inp + 1 >= s->inl && fillbuf(s) != EOF); + + if (s->inp[1] == '\r') + { + memmove(s->inp + 1, s->inp + 2, s->inl - s->inp + 2); + s->inl -= 1; + } + + goto reswitch; + } + + if (c == '\r') + { + while (s->inp + 1 >= s->inl && fillbuf(s) != EOF); + + if (s->inp[1] == '\n') + { + memmove(s->inp, s->inp + 1, s->inl - s->inp + 1); + s->inl -= 1; + } + else + *s->inp = '\n'; + + state = oldstate; + continue; + } + + if (c == '?') + { /* check trigraph */ + if (trigraph(s)) + { + state = oldstate; + continue; + } + goto reswitch; + } + if (c == '\\') + { /* line-folding */ + if (foldline(s)) + { + s->lineinc++; + state = oldstate; + continue; + } + goto reswitch; + } + error(WARNING, "Lexical botch in cpp"); + ip += runelen; + runelen = 1; + continue; + + case S_EOB: + s->inp = ip; + fillbuf(cursource); + state = oldstate; + continue; + + case S_EOF: + tp->type = END; + tp->len = 0; + s->inp = ip; + if (tp != trp->bp && (tp - 1)->type != NL && cursource->fd != -1) + error(WARNING, "No newline at end of file"); + trp->lp = tp + 1; + return nmac; + + case S_STNL: + error(ERROR, "Unterminated string or char const"); + /* fall through */ + case S_NL: + tp->t = ip; + tp->type = NL; + tp->len = 1; + tp->wslen = 0; + s->lineinc++; + s->inp = ip + 1; + trp->lp = tp + 1; + return nmac; + + case S_EOFSTR: + error(FATAL, "EOF in string or char constant"); + break; + + case S_COMNL: + s->lineinc++; + state = COM2; + ip += runelen; + runelen = 1; + continue; + + case S_EOFCOM: + error(WARNING, "EOF inside comment"); + --ip; + /* fall through */ + case S_COMMENT: + if (!Cflag) + { + tp->t = ++ip; + tp->t[-1] = ' '; + tp->wslen = 1; + state = START; + continue; + } + else + { + runelen = 1; + s->lineinc = 0; + tp->type = COMMENT; + } + } + break; + } + ip += runelen; + runelen = 1; + tp->len = ip - tp->t; + tp++; + } +} + +/* have seen ?; handle the trigraph it starts (if any) else 0 */ +int + trigraph(Source * s) +{ + uchar c; + + while (s->inp + 2 >= s->inl && fillbuf(s) != EOF); + ; + if (s->inp[1] != '?') + return 0; + c = 0; + switch (s->inp[2]) + { + case '=': + c = '#'; + break; + case '(': + c = '['; + break; + case '/': + c = '\\'; + break; + case ')': + c = ']'; + break; + case '\'': + c = '^'; + break; + case '<': + c = '{'; + break; + case '!': + c = '|'; + break; + case '>': + c = '}'; + break; + case '-': + c = '~'; + break; + } + if (c) + { + *s->inp = c; + memmove(s->inp + 1, s->inp + 3, s->inl - s->inp + 2); + s->inl -= 2; + } + return c; +} + +int + foldline(Source * s) +{ + int n = 1; + + /* skip pending white spaces */ + while ((s->inp[n] == ' ') || (s->inp[n] == '\t')) + { + n++; + if ((s->inp + n >= s->inl) && (fillbuf(s) == EOF)) + break; + } + + /* refill buffer */ + while (s->inp + (n + 1) >= s->inl && fillbuf(s) != EOF); + + /* skip DOS line ends */ + if (((s->inp[n] == '\r') && (s->inp[n+1] == '\n')) || + ((s->inp[n] == '\n') && (s->inp[n+1] == '\r'))) + n++; + + if ((s->inp[n] == '\n') || (s->inp[n] == '\r')) + { + memmove(s->inp, s->inp + n + 1, s->inl - s->inp + n + 2); + s->inl -= n + 1; + return 1; + } + return 0; +} + +int + fillbuf(Source * s) +{ + int n = 0; + + if (s->fd >= 0) + { + n = read(s->fd, (char *) s->inl, INS / 8); + if (n <= 0) + n = 0; + } + s->inl += n; + s->inl[0] = s->inl[1] = s->inl[2] = s->inl[3] = EOB; + if (n == 0) + { + s->inl[0] = s->inl[1] = s->inl[2] = s->inl[3] = EOFC; + return EOF; + } + return 0; +} + +/* + * Push down to new source of characters. + * If fd>0 and str==NULL, then from a file `name'; + * if fd==-1 and str, then from the string. + */ +Source * + setsource(char *name, int path, int fd, char const *str, int wrap) +{ + Source *s = new(Source); + size_t len; + + s->line = 1; + s->lineinc = 0; + s->fd = fd; + s->filename = name; + s->next = cursource; + s->ifdepth = 0; + s->pathdepth = path; + s->wrap = wrap; + + cursource = s; + + if (s->wrap) + genwrap(0); + + /* slop at right for EOB */ + if (str) + { + len = strlen(str); + s->inb = domalloc(len + 4); + s->inp = s->inb; + memcpy((char *) s->inp, str, len); + } + else + { + s->inb = domalloc(INS + 4); + s->inp = s->inb; + len = 0; + } + s->inl = s->inp + len; + s->inl[0] = s->inl[1] = EOB; + + return s; +} + +void + unsetsource(void) +{ + Source *s = cursource; + + if (s->wrap) + genwrap(1); + + if (s->fd >= 0) + { + close(s->fd); + dofree(s->inb); + } + cursource = s->next; + dofree(s); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/soltools/cpp/_macro.c b/soltools/cpp/_macro.c new file mode 100644 index 000000000..ef41b992e --- /dev/null +++ b/soltools/cpp/_macro.c @@ -0,0 +1,762 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#if defined(__IBMC__) || defined(__EMX__) || defined(_MSC_VER) +# ifndef PATH_MAX +# define PATH_MAX _MAX_PATH +# endif +#endif +#include <limits.h> + +#include "cpp.h" + +#define NCONCAT 16384 + +/* + * do a macro definition. tp points to the name being defined in the line + */ +void + dodefine(Tokenrow * trp) +{ + Token *tp; + Nlist *np; + Source *s; + Tokenrow *def, *args; + static uchar location[(PATH_MAX + 8) * NINC], *cp; + + tp = trp->tp + 1; + if (tp >= trp->lp || tp->type != NAME) + { + error(ERROR, "#defined token is not a name"); + return; + } + np = lookup(tp, 1); + if (np->flag & ISUNCHANGE) + { + error(ERROR, "#defined token %t can't be redefined", tp); + return; + } + /* collect arguments */ + tp += 1; + args = NULL; + if (tp < trp->lp && tp->type == LP && tp->wslen == 0) + { + tp += 1; + args = new(Tokenrow); + maketokenrow(2, args); + if (tp->type != RP) + { + /* macro with args */ + size_t narg = 0; + int err = 0; + + for (;;) + { + Token *atp; + + if (tp->type != NAME) + { + err++; + break; + } + if (narg >= args->max) + growtokenrow(args); + for (atp = args->bp; atp < args->lp; atp++) + if (atp->len == tp->len + && strncmp((char *) atp->t, (char *) tp->t, tp->len) == 0) + error(ERROR, "Duplicate macro argument"); + *args->lp++ = *tp; + narg++; + tp += 1; + if (tp->type == RP) + break; + if (tp->type != COMMA) + { + err++; + break; + } + tp += 1; + } + if (err) + { + error(ERROR, "Syntax error in macro parameters"); + return; + } + } + tp += 1; + } + trp->tp = tp; + if (((trp->lp) - 1)->type == NL) + trp->lp -= 1; + def = normtokenrow(trp); + if (np->flag & ISDEFINED) + { + if (comparetokens(def, np->vp) + || (np->ap == NULL) != (args == NULL) + || (np->ap && comparetokens(args, np->ap))) + { + if ( np->loc ) + error(ERROR, + "Macro redefinition of %t (already defined at %s)", + trp->bp + 2, np->loc); + else + error(ERROR, + "Macro redefinition of %t (already defined at %s)", + trp->bp + 2, "commandline" ); + } + } + if (args) + { + Tokenrow *tap; + + tap = normtokenrow(args); + dofree(args->bp); + dofree(args); + args = tap; + } + np->ap = args; + np->vp = def; + np->flag |= ISDEFINED; + + /* build location string of macro definition */ + for (cp = location, s = cursource; s; s = s->next) + if (*s->filename) + { + if (cp != location) + *cp++ = ' '; + sprintf((char *)cp, "%s:%d", s->filename, s->line); + cp += strlen((char *)cp); + } + + np->loc = newstring(location, strlen((char *)location), 0); + + if (Mflag) + { + if (np->ap) + error(INFO, "Macro definition of %s(%r) [%r]", np->name, np->ap, np->vp); + else + error(INFO, "Macro definition of %s [%r]", np->name, np->vp); + } +} + +/* + * Definition received via -D or -U + */ +void + doadefine(Tokenrow * trp, int type) +{ + Nlist *np; + static uchar onestr[2] = "1"; + static Token onetoken[1] = {{NUMBER, 0, 1, onestr, 0}}; + static Tokenrow onetr = {onetoken, onetoken, onetoken + 1, 1}; + + trp->tp = trp->bp; + if (type == 'U') + { + if (trp->lp - trp->tp != 2 || trp->tp->type != NAME) + goto syntax; + if ((np = lookup(trp->tp, 0)) == NULL) + return; + np->flag &= ~ISDEFINED; + return; + } + + if (type == 'A') + { + if (trp->tp >= trp->lp || trp->tp->type != NAME) + goto syntax; + trp->tp->type = ARCHITECTURE; + np = lookup(trp->tp, 1); + np->flag |= ISARCHITECTURE; + trp->tp += 1; + if (trp->tp >= trp->lp || trp->tp->type == END) + { + np->vp = &onetr; + return; + } + else + error(FATAL, "Illegal -A argument %r", trp); + } + + if (trp->tp >= trp->lp || trp->tp->type != NAME) + goto syntax; + np = lookup(trp->tp, 1); + np->flag |= ISDEFINED; + trp->tp += 1; + if (trp->tp >= trp->lp || trp->tp->type == END) + { + np->vp = &onetr; + return; + } + if (trp->tp->type != ASGN) + goto syntax; + trp->tp += 1; + if ((trp->lp - 1)->type == END) + trp->lp -= 1; + np->vp = normtokenrow(trp); + return; +syntax: + error(FATAL, "Illegal -D or -U argument %r", trp); +} + + + +/* + * Do macro expansion in a row of tokens. + * Flag is NULL if more input can be gathered. + */ +void + expandrow(Tokenrow * trp, char *flag) +{ + Token * tp; + Nlist * np; + + MacroValidatorList validators; + mvl_init(&validators); + /* Sets all token-identifiers to 0 because tokens may not be initialised (never use C!) */ + tokenrow_zeroTokenIdentifiers(trp); + + if (flag) + setsource(flag, -1, -1, "", 0); + for (tp = trp->tp; tp < trp->lp;) + { + mvl_check(&validators, tp); + + if (tp->type != NAME + || quicklook(tp->t[0], tp->len > 1 ? tp->t[1] : 0) == 0 + || (np = lookup(tp, 0)) == NULL + || (np->flag & (ISDEFINED | ISMAC)) == 0 + || (np->flag & ISACTIVE) != 0) + { + tp++; + continue; + } + trp->tp = tp; + if (np->val == KDEFINED) + { + tp->type = DEFINED; + if ((tp + 1) < trp->lp && (tp + 1)->type == NAME) + (tp + 1)->type = NAME1; + else + if ((tp + 3) < trp->lp && (tp + 1)->type == LP + && (tp + 2)->type == NAME && (tp + 3)->type == RP) + (tp + 2)->type = NAME1; + else + error(ERROR, "Incorrect syntax for `defined'"); + tp++; + continue; + } + else + if (np->val == KMACHINE) + { + if (((tp - 1) >= trp->bp) && ((tp - 1)->type == SHARP)) + { + tp->type = ARCHITECTURE; + if ((tp + 1) < trp->lp && (tp + 1)->type == NAME) + (tp + 1)->type = NAME2; + else + if ((tp + 3) < trp->lp && (tp + 1)->type == LP + && (tp + 2)->type == NAME && (tp + 3)->type == RP) + (tp + 2)->type = NAME2; + else + error(ERROR, "Incorrect syntax for `#machine'"); + } + tp++; + continue; + } + + if (np->flag & ISMAC) + builtin(trp, np->val); + else + { + // coverity[overrun-buffer-arg: FALSE] - a multiple of trp->max is allocated, not trp->max itself + expand(trp, np, &validators); + } + tp = trp->tp; + } // end for + if (flag) + unsetsource(); + + mvl_destruct(&validators); +} + +/* + * Expand the macro whose name is np, at token trp->tp, in the tokenrow. + * Return trp->tp at the first token next to be expanded + * (ordinarily the beginning of the expansion) + * I.e.: the same position as before! + * Only one expansion is performed, then we return to the expandrow() + * loop and start at same position. + */ +void + expand(Tokenrow * trp, Nlist * np, MacroValidatorList * pValidators) +{ + Tokenrow ntr; + int ntokc, narg; + Tokenrow *atr[NARG + 1]; + + if (Mflag == 2) + { + if (np->ap) + error(INFO, "Macro expansion of %t with %s(%r)", trp->tp, np->name, np->ap); + else + error(INFO, "Macro expansion of %t with %s", trp->tp, np->name); + } + + copytokenrow(&ntr, np->vp); /* copy macro value */ + if (np->ap == NULL) /* parameterless */ + ntokc = 1; + else + { + int i; + + ntokc = gatherargs(trp, atr, &narg); + if (narg < 0) + { /* not actually a call (no '(') */ + trp->tp++; + return; + } + if (narg != rowlen(np->ap)) + { + error(ERROR, "Disagreement in number of macro arguments"); + trp->tp += ntokc; + return; + } + + /** If gatherargs passed a macro validating token, this token + must become valid here. + trp->tp+0 was checked in expandrow(), so we don't need to do it + again here: + */ + for (i = 1; i < ntokc; i++) + { + mvl_check(pValidators,trp->tp+i); + } + + substargs(np, &ntr, atr); /* put args into replacement */ + for (i = 0; i < narg; i++) + { + dofree(atr[i]->bp); + dofree(atr[i]); + } + } + + doconcat(&ntr); /* execute ## operators */ + ntr.tp = ntr.bp; + makespace(&ntr, trp->tp); + + tokenrow_zeroTokenIdentifiers(&ntr); + insertrow(trp, ntokc, &ntr); + + /* add validator for just invalidated macro: + */ + np->flag |= ISACTIVE; + if (trp->tp != trp->lp) + { /* tp is a valid pointer: */ + mvl_add(pValidators,np,trp->tp); + } + else + { /* tp is == lp, therefore does not point to valid memory: */ + mvl_add(pValidators,np,NULL); + } + /* reset trp->tp to original position: + */ + trp->tp -= ntr.lp - ntr.bp; /* so the result will be tested for macros from the same position again */ + + dofree(ntr.bp); + + return; +} + +/* + * Gather an arglist, starting in trp with tp pointing at the macro name. + * Return total number of tokens passed, stash number of args found. + * trp->tp is not changed relative to the tokenrow. + */ +int + gatherargs(Tokenrow * trp, Tokenrow ** atr, int *narg) +{ + int parens = 1; + int ntok = 0; + Token *bp, *lp; + Tokenrow ttr; + int ntokp; + int needspace; + + *narg = -1; /* means that there is no macro + * call */ + /* look for the ( */ + for (;;) + { + trp->tp++; + ntok++; + if (trp->tp >= trp->lp) + { + // coverity[overrun-buffer-arg: FALSE] - a multiple of trp->max is allocated, not trp->max itself + gettokens(trp, 0); + if ((trp->lp - 1)->type == END) + { + trp->lp -= 1; + trp->tp -= ntok; + return ntok; + } + } + if (trp->tp->type == LP) + break; + if (trp->tp->type != NL) + return ntok; + } + *narg = 0; + ntok++; + ntokp = ntok; + trp->tp++; + /* search for the terminating ), possibly extending the row */ + needspace = 0; + while (parens > 0) + { + if (trp->tp >= trp->lp) + { + // coverity[overrun-buffer-arg: FALSE] - a multiple of trp->max is allocated, not trp->max itself + gettokens(trp, 0); + } + if (needspace) + { + needspace = 0; + /* makespace(trp); [rh] */ + } + if (trp->tp->type == END) + { + trp->lp -= 1; + trp->tp -= ntok; + error(ERROR, "EOF in macro arglist"); + return ntok; + } + if (trp->tp->type == NL) + { + trp->tp += 1; + adjustrow(trp, -1); + trp->tp -= 1; + /* makespace(trp); [rh] */ + needspace = 1; + continue; + } + if (trp->tp->type == LP) + parens++; + else + if (trp->tp->type == RP) + parens--; + trp->tp++; + ntok++; + } + trp->tp -= ntok; + /* Now trp->tp won't move underneath us */ + lp = bp = trp->tp + ntokp; + for (; parens >= 0; lp++) + { + if (lp->type == LP) + { + parens++; + continue; + } + if (lp->type == RP) + parens--; + if (lp->type == DSHARP) + lp->type = DSHARP1; /* ## not special in arg */ + if ((lp->type == COMMA && parens == 0) || + ( parens < 0 && ((lp - 1)->type != LP))) + { + if (*narg >= NARG - 1) + error(FATAL, "Sorry, too many macro arguments"); + ttr.bp = ttr.tp = bp; + ttr.lp = lp; + atr[(*narg)++] = normtokenrow(&ttr); + bp = lp + 1; + } + } + return ntok; +} + +/* + * substitute the argument list into the replacement string + * This would be simple except for ## and # + */ +void + substargs(Nlist * np, Tokenrow * rtr, Tokenrow ** atr) +{ + Tokenrow tatr; + Token *tp; + int ntok, argno; + + for (rtr->tp = rtr->bp; rtr->tp < rtr->lp;) + { + if (rtr->tp->type == SHARP) + { /* string operator */ + tp = rtr->tp; + rtr->tp += 1; + if ((argno = lookuparg(np, rtr->tp)) < 0) + { + error(ERROR, "# not followed by macro parameter"); + continue; + } + ntok = 1 + (int)(rtr->tp - tp); + rtr->tp = tp; + insertrow(rtr, ntok, stringify(atr[argno])); + continue; + } + if (rtr->tp->type == NAME + && (argno = lookuparg(np, rtr->tp)) >= 0) + { + if (((rtr->tp + 1) < rtr->lp && (rtr->tp + 1)->type == DSHARP) + || (rtr->tp != rtr->bp && (rtr->tp - 1)->type == DSHARP)) + { + copytokenrow(&tatr, atr[argno]); + makespace(&tatr, rtr->tp); + insertrow(rtr, 1, &tatr); + dofree(tatr.bp); + } + else + { + copytokenrow(&tatr, atr[argno]); + makespace(&tatr, rtr->tp); + expandrow(&tatr, "<macro>"); + insertrow(rtr, 1, &tatr); + dofree(tatr.bp); + } + continue; + } + rtr->tp++; + } +} + +/* + * Evaluate the ## operators in a tokenrow + */ +void + doconcat(Tokenrow * trp) +{ + Token *ltp, *ntp; + Tokenrow ntr; + size_t len; + + for (trp->tp = trp->bp; trp->tp < trp->lp; trp->tp++) + { + if (trp->tp->type == DSHARP1) + trp->tp->type = DSHARP; + else + if (trp->tp->type == DSHARP) + { + int i; + char tt[NCONCAT]; + + ltp = trp->tp - 1; + ntp = trp->tp + 1; + + if (ltp < trp->bp || ntp >= trp->lp) + { + error(ERROR, "## occurs at border of replacement"); + continue; + } + + ntp = ltp; + i = 1; + len = 0; + + do + { + if (len + ntp->len + ntp->wslen > sizeof(tt)) + { + error(ERROR, "## string concatenation buffer overrun"); + break; + } + + if (ntp != trp->tp + 1) + { + strncpy((char *) tt + len, (char *) ntp->t - ntp->wslen, + ntp->len + ntp->wslen); + len += ntp->len + ntp->wslen; + } + else + { + // remove spaces around ## + strncpy((char *) tt + len, (char *) ntp->t, ntp->len); + len += ntp->len; + } + + ntp = trp->tp + i; + i++; + } + while (ntp < trp->lp); + + tt[len] = '\0'; + setsource("<##>", -1, -1, tt, 0); + maketokenrow(3, &ntr); + // coverity[overrun-buffer-arg: FALSE] - a multiple of trp->max is allocated, not trp->max itself + gettokens(&ntr, 1); + unsetsource(); + if (ntr.bp->type == UNCLASS) + error(WARNING, "Bad token %r produced by ##", &ntr); + while ((ntr.lp-1)->len == 0 && ntr.lp != ntr.bp) + ntr.lp--; + + doconcat(&ntr); + trp->tp = ltp; + makespace(&ntr, ltp); + insertrow(trp, (int)(ntp - ltp), &ntr); + dofree(ntr.bp); + trp->tp--; + } + } +} + +/* + * tp is a potential parameter name of macro mac; + * look it up in mac's arglist, and if found, return the + * corresponding index in the argname array. Return -1 if not found. + */ +int + lookuparg(Nlist * mac, Token const * tp) +{ + Token *ap; + + if (tp->type != NAME || mac->ap == NULL) + return -1; + for (ap = mac->ap->bp; ap < mac->ap->lp; ap++) + { + if (ap->len == tp->len && strncmp((char *) ap->t, (char *) tp->t, ap->len) == 0) + return (int)(ap - mac->ap->bp); + } + return -1; +} + +/* + * Return a quoted version of the tokenrow (from # arg) + */ +#define STRLEN 512 +Tokenrow * + stringify(Tokenrow * vp) +{ + static Token t = {STRING, 0, 0, NULL, 0}; + static Tokenrow tr = {&t, &t, &t + 1, 1}; + Token *tp; + uchar s[STRLEN]; + uchar *sp = s, *cp; + int i, instring; + + *sp++ = '"'; + for (tp = vp->bp; tp < vp->lp; tp++) + { + instring = tp->type == STRING || tp->type == CCON; + if (sp + 2 * tp->len + tp->wslen >= &s[STRLEN - 10]) + { + error(ERROR, "Stringified macro arg is too long"); + break; + } + + // Change by np 31.10.2001, #93725 - begin + if ( tp->wslen > 0 ) + *sp++ = ' '; + // change end. + + for (i = 0, cp = tp->t; (unsigned int)i < tp->len; i++) + { + if (instring && (*cp == '"' || *cp == '\\')) + *sp++ = '\\'; + *sp++ = *cp++; + } + } + *sp++ = '"'; + *sp = '\0'; + sp = s; + t.len = strlen((char *) sp); + t.t = newstring(sp, t.len, 0); + return &tr; +} + +/* + * expand a builtin name + */ +void + builtin(Tokenrow * trp, int biname) +{ + char *op; + Token *tp; + Source *s; + + tp = trp->tp; + trp->tp++; + /* need to find the real source */ + s = cursource; + while (s && s->fd == -1) + s = s->next; + if (s == NULL) + s = cursource; + /* most are strings */ + tp->type = STRING; + if (tp->wslen) + { + *outptr++ = ' '; + tp->wslen = 1; + } + op = outptr; + *op++ = '"'; + switch (biname) + { + + case KLINENO: + tp->type = NUMBER; + op = outnum(op - 1, s->line); + break; + + case KFILE: + { + char *src = s->filename; + + while ((*op++ = *src++) != 0) + if (src[-1] == '\\') + *op++ = '\\'; + op--; + break; + } + + case KDATE: + strncpy(op, curtime + 4, 7); + strncpy(op + 7, curtime + 20, 4); + op += 11; + break; + + case KTIME: + strncpy(op, curtime + 11, 8); + op += 8; + break; + + default: + error(ERROR, "cpp botch: unknown internal macro"); + return; + } + if (tp->type == STRING) + *op++ = '"'; + tp->t = (uchar *) outptr; + tp->len = op - outptr; + outptr = op; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/soltools/cpp/_mcrvalid.c b/soltools/cpp/_mcrvalid.c new file mode 100644 index 000000000..637706530 --- /dev/null +++ b/soltools/cpp/_mcrvalid.c @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "cpp.h" + +void +mvl_init(MacroValidatorList * out_pValidators) +{ + out_pValidators->pFirst = NULL; + out_pValidators->nextFreeIdentifier = 1; +} + +void +mvl_destruct(MacroValidatorList * out_pValidators) +{ + MacroValidator * pV = out_pValidators->pFirst; + MacroValidator * pDel; + for ( pDel = out_pValidators->pFirst; + pDel != NULL; + pDel = pV ) + { + pV = pV->pNext; + + pDel->pMacro->flag &= (~ISACTIVE); + dofree(pDel); + } +} + + +#define INVALID_TILL_ENDOFROW 32000 + +/* If in_pTokenWhereMacroBecomesValid == 0, the macro is at row end + and therefore there does not exist any token, where the macro becomes + valid again. It is revalidated, when the row was processed complete. +*/ +void +mvl_add( MacroValidatorList * inout_pValidators, + Nlist * in_pMacro, + Token * in_pTokenWhereMacroBecomesValid ) +{ + + MacroValidator * pNew = new(MacroValidator); + pNew->pMacro = in_pMacro; + + if (in_pTokenWhereMacroBecomesValid == NULL) + { + pNew->nTokenWhereMacroBecomesValid = INVALID_TILL_ENDOFROW; + } + else if (in_pTokenWhereMacroBecomesValid->identifier > 0) + { + pNew->nTokenWhereMacroBecomesValid = in_pTokenWhereMacroBecomesValid->identifier; + } + else + { + pNew->nTokenWhereMacroBecomesValid = inout_pValidators->nextFreeIdentifier; + in_pTokenWhereMacroBecomesValid->identifier = inout_pValidators->nextFreeIdentifier; + inout_pValidators->nextFreeIdentifier++; + } + + pNew->pNext = inout_pValidators->pFirst; + inout_pValidators->pFirst = pNew; +} + +void +mvl_check( MacroValidatorList * inout_pValidators, + Token const * inout_pTokenToCheck) +{ + MacroValidator * pV; /* Running pointer */ + MacroValidator * pCheckedOnes; /* Here new list is built. */ + pCheckedOnes = NULL; + + for ( pV = inout_pValidators->pFirst; + pV != NULL; + pV = inout_pValidators->pFirst ) + { + inout_pValidators->pFirst = pV->pNext; + + if (pV->nTokenWhereMacroBecomesValid == inout_pTokenToCheck->identifier) + { + pV->pMacro->flag &= (~ISACTIVE); + dofree(pV); + } + else + { + pV->pNext = pCheckedOnes; + pCheckedOnes = pV; + } + } /* end for */ + + /* Assign new built list (too old ones were removed) to + original list: + */ + inout_pValidators->pFirst = pCheckedOnes; +} + + +void +tokenrow_zeroTokenIdentifiers(Tokenrow* trp) +{ + Token * tp; + for (tp = trp->bp; tp < trp->lp; tp++) + { + tp->identifier = 0; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/soltools/cpp/_nlist.c b/soltools/cpp/_nlist.c new file mode 100644 index 000000000..096cc525f --- /dev/null +++ b/soltools/cpp/_nlist.c @@ -0,0 +1,138 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "cpp.h" + +extern int Cplusplus; +Nlist *kwdefined; +char wd[128]; + +/* + ER: Table was made extra large, because there seems to be a problem with the + chaining. An nlist->next is sometimes overwritten somewhere, which + results in a SIGSEGV. I canceled the GDB with watchpoint after 2 days, though... + It works this way for now... + */ +#define NLSIZE 15000 + +static Nlist *nlist[NLSIZE]; + +struct kwtab +{ + char *kw; + int val; + int flag; +}; + +static const struct kwtab kwtab[] = +{ + {"if", KIF, ISKW}, + {"ifdef", KIFDEF, ISKW}, + {"ifndef", KIFNDEF, ISKW}, + {"elif", KELIF, ISKW}, + {"else", KELSE, ISKW}, + {"endif", KENDIF, ISKW}, + {"include", KINCLUDE, ISKW}, + {"include_next", KINCLUDENEXT, ISKW}, + {"import", KIMPORT, ISKW}, + {"define", KDEFINE, ISKW}, + {"undef", KUNDEF, ISKW}, + {"line", KLINE, ISKW}, + {"error", KERROR, ISKW}, + {"pragma", KPRAGMA, ISKW}, + {"ident", KIDENT, ISKW}, + {"eval", KEVAL, ISKW}, + {"defined", KDEFINED, ISDEFINED + ISUNCHANGE}, + {"machine", KMACHINE, ISDEFINED + ISUNCHANGE}, + {"__LINE__", KLINENO, ISMAC + ISUNCHANGE}, + {"__FILE__", KFILE, ISMAC + ISUNCHANGE}, + {"__DATE__", KDATE, ISMAC + ISUNCHANGE}, + {"__TIME__", KTIME, ISMAC + ISUNCHANGE}, + {"__STDC__", KSTDC, ISUNCHANGE}, + {NULL, 0, 0} +}; + +unsigned long namebit[077 + 1]; + +void + setup_kwtab(void) +{ + struct kwtab const *kp; + Nlist *np; + Token t; + static Token deftoken[1] = {{NAME, 0, 7, (uchar *) "defined", 0}}; + static Tokenrow deftr = {deftoken, deftoken, deftoken + 1, 1}; + + for (kp = kwtab; kp->kw; kp++) + { + t.t = (uchar *) kp->kw; + t.len = strlen(kp->kw); + np = lookup(&t, 1); + np->flag = (char) kp->flag; + np->val = (char) kp->val; + if (np->val == KDEFINED) + { + kwdefined = np; + np->val = NAME; + np->vp = &deftr; + np->ap = NULL; + } + } +} + +Nlist * + lookup(Token * tp, int install) +{ + unsigned int h; + Nlist *np; + uchar *cp, *cpe; + + h = 0; + for (cp = tp->t, cpe = cp + tp->len; cp < cpe;) + h += *cp++; + h %= NLSIZE; + np = nlist[h]; + while (np) + { + if (*tp->t == *np->name && tp->len == (unsigned int)np->len + && strncmp((char *)tp->t, (char *)np->name, tp->len) == 0) + return np; + np = np->next; + } + if (install) + { + np = new(Nlist); + np->vp = NULL; + np->ap = NULL; + np->flag = 0; + np->val = 0; + np->len = tp->len; + np->name = newstring(tp->t, tp->len, 0); + np->next = nlist[h]; + nlist[h] = np; + quickset(tp->t[0], tp->len > 1 ? tp->t[1] : 0); + return np; + } + return NULL; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/soltools/cpp/_tokens.c b/soltools/cpp/_tokens.c new file mode 100644 index 000000000..0a10cd34c --- /dev/null +++ b/soltools/cpp/_tokens.c @@ -0,0 +1,557 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#if (defined(_WIN32) || defined(__IBMC__)) +#include <io.h> +#else +#include <unistd.h> +#endif +#include "cpp.h" + + +static char wbuf[4 * OBS]; +static char *wbp = wbuf; +static int EBCDIC_ExternTokenDetected = 0; +static int EBCDIC_StartTokenDetected = 0; + +static unsigned char toLatin1[256] = +{ + 0x00, 0x01, 0x02, 0x03, 0x9c, 0x09, 0x86, 0x7f, 0x97, 0x8d, + 0x8e, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + 0x9d, 0x0a, 0x08, 0x87, 0x18, 0x19, 0x92, 0x8f, 0x1c, 0x1d, + 0x1e, 0x1f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x17, 0x1b, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x05, 0x06, 0x07, 0x90, 0x91, + 0x16, 0x93, 0x94, 0x95, 0x96, 0x04, 0x98, 0x99, 0x9a, 0x9b, + 0x14, 0x15, 0x9e, 0x1a, 0x20, 0xa0, 0xe2, 0xe4, 0xe0, 0xe1, + 0xe3, 0xe5, 0xe7, 0xf1, 0xa2, 0x2e, 0x3c, 0x28, 0x2b, 0x7c, + 0x26, 0xe9, 0xea, 0xeb, 0xe8, 0xed, 0xee, 0xef, 0xec, 0xdf, + 0x21, 0x24, 0x2a, 0x29, 0x3b, 0x5e, 0x2d, 0x2f, 0xc2, 0xc4, + 0xc0, 0xc1, 0xc3, 0xc5, 0xc7, 0xd1, 0xa6, 0x2c, 0x25, 0x5f, + 0x3e, 0x3f, 0xf8, 0xc9, 0xca, 0xcb, 0xc8, 0xcd, 0xce, 0xcf, + 0xcc, 0x60, 0x3a, 0x23, 0x40, 0x27, 0x3d, 0x22, + 0xd8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0xab, 0xbb, 0xf0, 0xfd, 0xfe, 0xb1, 0xb0, 0x6a, 0x6b, 0x6c, + 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0xaa, 0xba, 0xe6, 0xb8, + 0xc6, 0xa4, 0xb5, 0x7e, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0xa1, 0xbf, 0xd0, 0x5b, 0xde, 0xae, 0xac, 0xa3, + 0xa5, 0xb7, 0xa9, 0xa7, 0xb6, 0xbc, 0xbd, 0xbe, 0xdd, 0xa8, + 0xaf, 0x5d, 0xb4, 0xd7, 0x7b, 0x41, 0x42, 0x43, 0x44, 0x45, + 0x46, 0x47, 0x48, 0x49, 0xad, 0xf4, 0xf6, 0xf2, 0xf3, 0xf5, + 0x7d, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, + 0xb9, 0xfb, 0xfc, 0xf9, 0xfa, 0xff, 0x5c, 0xf7, 0x53, 0x54, + 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0xb2, 0xd4, 0xd6, 0xd2, + 0xd3, 0xd5, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0xb3, 0xdb, 0xdc, 0xd9, 0xda, 0x9f +}; + +#define MASK "\\x%x" + +static int + memcpy_EBCDIC( char * pwbuf, uchar const *p, int len ) +{ + int currpos = 0; + int processedchars = 0; + + if( len == 0 ) + return 0; + + if( len == 1 ) + { + *pwbuf = *p; + return 1; + } + + /* copy spaces until " or ' */ + while( (p[ processedchars ] != '\"') && (p[ processedchars ] != '\'') ) + pwbuf[ currpos++ ] = p[ processedchars++ ]; + + /* copy first " or ' */ + pwbuf[ currpos++ ] = p[ processedchars++ ]; + + /* convert all characters until " or ' */ + while( processedchars < (len - 1) ) + { + if( p[ processedchars ] == '\\' ) + { + switch( p[ ++processedchars ] ) + { + case 'n': + currpos += sprintf( &pwbuf[ currpos ], MASK, toLatin1['\n'] ); + processedchars++; + break; + + case 't': + currpos += sprintf( &pwbuf[ currpos ], MASK, toLatin1['\t'] ); + processedchars++; + break; + + case 'v': + currpos += sprintf( &pwbuf[ currpos ], MASK, toLatin1['\v'] ); + processedchars++; + break; + + case 'b': + currpos += sprintf( &pwbuf[ currpos ], MASK, toLatin1['\b'] ); + processedchars++; + break; + + case 'r': + currpos += sprintf( &pwbuf[ currpos ], MASK, toLatin1['\r'] ); + processedchars++; + break; + + case 'f': + currpos += sprintf( &pwbuf[ currpos ], MASK, toLatin1['\f'] ); + processedchars++; + break; + + case 'a': + currpos += sprintf( &pwbuf[ currpos ], MASK, toLatin1['\a'] ); + processedchars++; + break; + + case '\\': + currpos += sprintf( &pwbuf[ currpos ], MASK, toLatin1['\\'] ); + processedchars++; + break; + + case '?': + currpos += sprintf( &pwbuf[ currpos ], MASK, toLatin1['\?'] ); + processedchars++; + break; + + case '\'': + currpos += sprintf( &pwbuf[ currpos ], MASK, toLatin1['\''] ); + processedchars++; + break; + + case '"': + currpos += sprintf( &pwbuf[ currpos ], MASK, toLatin1['\"'] ); + processedchars++; + break; + + /* octal coded character? -> copy */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + int startpos = currpos; + + pwbuf[ currpos++ ] = '\\'; + + while( p[ processedchars ] >= '0' && p[ processedchars ] <= '7' && (currpos < startpos + 4) ) + pwbuf[ currpos++ ] = (unsigned char)p[ processedchars++ ]; + break; + } + + /* hex coded character? -> copy */ + case 'x': + case 'X': + { + int startpos = currpos; + + pwbuf[ currpos++ ] = '\\'; + pwbuf[ currpos++ ] = 'x'; + processedchars++; + + while( isxdigit( p[ processedchars ] ) && (currpos < startpos + 4) ) + pwbuf[ currpos++ ] = (unsigned char)p[ processedchars++ ]; + break; + } + + } + } + else + currpos += sprintf( &pwbuf[ currpos ], MASK, toLatin1[p[ processedchars++ ]] ); + + } + + /* copy last " or ' */ + pwbuf[ currpos++ ] = p[ processedchars ]; + + return currpos; +} + +void + maketokenrow(int size, Tokenrow * trp) +{ + trp->max = size; + if (size > 0) + trp->bp = (Token *) domalloc(size * sizeof(Token)); + else + trp->bp = NULL; + trp->tp = trp->bp; + trp->lp = trp->bp; +} + +Token * + growtokenrow(Tokenrow * trp) +{ + size_t ncur = trp->tp - trp->bp; + size_t nlast = trp->lp - trp->bp; + + trp->max = 3 * trp->max / 2 + 1; + trp->bp = (Token *) realloc(trp->bp, trp->max * sizeof(Token)); + assert(trp->bp); // realloc failure is OOM -> no point to handle + trp->lp = &trp->bp[nlast]; + trp->tp = &trp->bp[ncur]; + return trp->lp; +} + +/* + * Compare a row of tokens, ignoring the content of WS; return !=0 if different + */ +int + comparetokens(Tokenrow * tr1, Tokenrow * tr2) +{ + Token *tp1, *tp2; + + tp1 = tr1->tp; + tp2 = tr2->tp; + if (tr1->lp - tp1 != tr2->lp - tp2) + return 1; + for (; tp1 < tr1->lp; tp1++, tp2++) + { + if (tp1->type != tp2->type + || (tp1->wslen == 0) != (tp2->wslen == 0) + || tp1->len != tp2->len + || strncmp((char *) tp1->t, (char *) tp2->t, tp1->len) != 0) + return 1; + } + return 0; +} + +/* + * replace ntok tokens starting at dtr->tp with the contents of str. + * tp ends up pointing just beyond the replacement. + * Canonical whitespace is assured on each side. + */ +void + insertrow(Tokenrow * dtr, int ntok, Tokenrow const * str) +{ + int nrtok = (int)rowlen(str); + + dtr->tp += ntok; + adjustrow(dtr, nrtok - ntok); + dtr->tp -= ntok; + movetokenrow(dtr, str); + dtr->tp += nrtok; +} + +/* + * make sure there is WS before trp->tp, if tokens might merge in the output + */ +void + makespace(Tokenrow * trp, Token const * ntp) +{ + uchar *tt; + Token *tp = trp->tp; + + if (tp >= trp->lp) + return; + + if (ntp->wslen) + { + tt = newstring(tp->t, tp->len, ntp->wslen); + strncpy((char *)tt, (char *)ntp->t - ntp->wslen, ntp->wslen); + tp->t = tt + ntp->wslen; + tp->wslen = ntp->wslen; + } +} + +/* + * Copy an entire tokenrow into another, at tp. + * It is assumed that there is enough space. + * Not strictly conforming. + */ +void + movetokenrow(Tokenrow * dtr, Tokenrow const * str) +{ + size_t nby; + + nby = (char *) str->lp - (char *) str->bp; + if (nby) + memmove(dtr->tp, str->bp, nby); +} + +/* + * Move the tokens in a row, starting at tr->tp, rightward by nt tokens; + * nt may be negative (left move). + * The row may need to be grown. + * Non-strictly conforming because of the (char *), but easily fixed + */ +void + adjustrow(Tokenrow * trp, int nt) +{ + size_t nby, size; + + if (nt == 0) + return; + size = (trp->lp - trp->bp) + nt; + while (size > trp->max) + growtokenrow(trp); + nby = (char *) trp->lp - (char *) trp->tp; + if (nby) + memmove(trp->tp + nt, trp->tp, nby); + trp->lp += nt; +} + +/* + * Copy a row of tokens into the destination holder, allocating + * the space for the contents. Return the destination. + */ +Tokenrow * + copytokenrow(Tokenrow * dtr, Tokenrow const * str) +{ + int len = (int)rowlen(str); + + maketokenrow(len, dtr); + movetokenrow(dtr, str); + if (len != 0) + dtr->lp += len; + return dtr; +} + +/* + * Produce a copy of a row of tokens. Start at trp->tp. + * The value strings are copied as well. The first token + * has WS available. + */ +Tokenrow * + normtokenrow(Tokenrow * trp) +{ + Token *tp; + Tokenrow *ntrp = new(Tokenrow); + int len; + + len = (int)(trp->lp - trp->tp); + if (len <= 0) + len = 1; + maketokenrow(len, ntrp); + for (tp = trp->tp; tp < trp->lp; tp++) + { + *ntrp->lp = *tp; + if (tp->len) + { + ntrp->lp->t = newstring(tp->t, tp->len, 1); + *ntrp->lp->t++ = ' '; + if (tp->wslen) + ntrp->lp->wslen = 1; + } + ntrp->lp++; + } + if (ntrp->lp > ntrp->bp) + ntrp->bp->wslen = 0; + return ntrp; +} + +/* + * Debugging + */ +void + peektokens(Tokenrow * trp, char *str) +{ + Token *tp; + + tp = trp->tp; + flushout(); + if (str) + fprintf(stderr, "%s ", str); + if (tp < trp->bp || tp > trp->lp) + fprintf(stderr, "(tp offset %ld) ", (long int) (tp - trp->bp)); + for (tp = trp->bp; tp < trp->lp && tp < trp->bp + 32; tp++) + { + if (tp->type != NL) + { + int c = tp->t[tp->len]; + + tp->t[tp->len] = 0; + fprintf(stderr, "%s", tp->t); + tp->t[tp->len] = (uchar) c; + } + fprintf(stderr, tp == trp->tp ? "{%x*} " : "{%x} ", tp->type); + } + fprintf(stderr, "\n"); + fflush(stderr); +} + +void + puttokens(Tokenrow * trp) +{ + Token *tp; + int len; + uchar *p; + + if (Vflag) + peektokens(trp, ""); + tp = trp->bp; + for (; tp < trp->lp; tp++) + { + if (tp->type != NL) + { + len = (int)(tp->len + tp->wslen); + p = tp->t - tp->wslen; + + /* add parameter check to delete operator? */ + if( Dflag ) + { + if( (tp->type == NAME) && (strncmp( (char*)p, "delete", len ) == 0) ) + { + Token* ntp = tp; + ntp++; + + if( ntp->type == NAME ) + { + uchar* np = ntp->t - ntp->wslen; + int nlen = (int)(ntp->len + ntp->wslen); + + memcpy(wbp, "if(", 3 ); + wbp += 4; + memcpy(wbp, np, nlen ); + wbp += nlen; + memcpy(wbp, ")", 1 ); + wbp++; + + memcpy(wbp, p, len); + } + } + } + + /* EBCDIC to ANSI conversion requested? */ + if( Aflag ) + { + /* keyword __ToLatin1__ found? -> do conversion! */ + if( EBCDIC_StartTokenDetected ) + { + /* previous token was 'extern'? -> don't convert current token! */ + if( EBCDIC_ExternTokenDetected ) + { + EBCDIC_ExternTokenDetected = 0; + memcpy(wbp, p, len); + } + else + { + /* current token is keyword 'extern'? -> don't convert following token! */ + if( (tp->wslen == 0) && (strncmp( (char*)p, "extern", len ) == 0) ) + { + EBCDIC_ExternTokenDetected = 1; + memcpy(wbp, p, len); + } + else + { + /* token is string or char? -> process EBCDIC to ANSI conversion */ + if ((tp->type == STRING) || (tp->type == CCON)) + len = memcpy_EBCDIC(wbp, p, len); + else + memcpy(wbp, p, len); + } + } + } + else + /* keyword __ToLatin1__ found? -> don't copy keyword and start conversion */ + if( (tp->type == NAME) && (strncmp( (char*)p, "__ToLatin1__", len) == 0) ) + { + EBCDIC_StartTokenDetected = 1; + len = 0; + } + else + memcpy(wbp, p, len); + } + else + memcpy(wbp, p, len); + + wbp += len; + } + else + *wbp++ = '\n'; + + if (wbp >= &wbuf[OBS]) + { + if ( write(1, wbuf, OBS) != -1 ) { + if (wbp > &wbuf[OBS]) + memmove(wbuf, wbuf + OBS, wbp - &wbuf[OBS]); + wbp -= OBS; + } + else exit(1); + } + } + trp->tp = tp; + if (cursource->fd == 0) + flushout(); +} + +void + flushout(void) +{ + if (wbp > wbuf) + { + if ( write(1, wbuf, (int)(wbp - wbuf)) != -1) + wbp = wbuf; + else + exit(1); + } +} + +/* + * turn a row into just a newline + */ +void + setempty(Tokenrow * trp) +{ + trp->tp = trp->bp; + trp->lp = trp->bp + 1; + *trp->bp = nltoken; +} + +/* + * generate a number + */ +char * + outnum(char *p, int n) +{ + if (n >= 10) + p = outnum(p, n / 10); + *p++ = (char) (n % 10 + '0'); + return p; +} + +/* + * allocate and initialize a new string from s, of length l, at offset o + * Null terminated. + */ +uchar * + newstring(uchar const * s, size_t l, size_t o) +{ + uchar *ns = (uchar *) domalloc(l + o + 1); + + ns[l + o] = '\0'; + return (uchar *) strncpy((char *) ns + o, (char *) s, l) - o; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/soltools/cpp/_unix.c b/soltools/cpp/_unix.c new file mode 100644 index 000000000..1135bb08e --- /dev/null +++ b/soltools/cpp/_unix.c @@ -0,0 +1,226 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <stdio.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <fcntl.h> +#if (defined(_WIN32) || defined(__IBMC__)) +#include <io.h> +#else +#include <unistd.h> +#endif + +#include "cpp.h" + +#if defined(MACOSX) || defined(AIX) || defined(_WIN32) +#include "_getopt.h" +#else +#include <getopt.h> +#endif + +int Pflag = 0; /* print no line information */ +int Iflag = 0; /* print includes */ +int Mflag = 0; /* print macro expansion */ +int Aflag = 0; /* translate character sets */ +int Xflag = 0; /* print pragma for include/import */ +int Vflag = 0; /* verbose flag */ +int Cflag = 0; /* do not remove any comments */ +int Dflag = 0; /* add parameter check to delete op */ +int Cplusplus = 0; + +void + setup(int argc, char **argv) +{ + int c, fd, i, n; + char *fp, *dp; + Tokenrow tr; + + setup_kwtab(); +#if defined(MACOSX) || defined(AIX) || defined(_WIN32) + while ((c = stgetopt(argc, argv, "NOPV:I:D:U:F:A:X:u:l:+")) != -1) +#else + while ((c = getopt(argc, argv, "NOPV:I:D:U:F:A:X:u:l:+")) != -1) +#endif + switch (c) + { + case 'N': + for (i = 0; i < NINCLUDE; i++) + if (includelist[i].always == 1) + includelist[i].deleted = 1; + break; + + case 'I': + for (i = NINCLUDE - 2; i >= 0; i--) + { + if (includelist[i].file == NULL) + { + includelist[i].always = 1; + includelist[i].file = optarg; + break; + } + } + if (i < 0) + error(FATAL, "Too many -I directives"); + break; + + case 'D': + case 'U': + case 'A': + setsource("<cmdarg>", -1, -1, optarg, 0); + maketokenrow(3, &tr); + // coverity[overrun-buffer-arg: FALSE] - a multiple of trp->max is allocated, not trp->max itself + gettokens(&tr, 1); + doadefine(&tr, c); + dofree(tr.bp); + unsetsource(); + break; + + case 'P': /* Lineinfo */ + Pflag++; + break; + + case 'V': + for (n = 0;; n++) + { + c = optarg[n]; + if (c == '\0') + break; + switch (c) + { + case 'i': + Iflag++; + break; + + case 'm': + Mflag = 1; + break; + + case 'x': + Mflag = 2; + break; + + case 't': + Vflag++; + break; + + case 'v': + fprintf(stderr, "%s\n", argv[0]); + break; + + default: + error(WARNING, "Unknown verbose option %c", c); + } + } + break; + + case 'X': + for (n = 0;; n++) + { + c = optarg[n]; + if (c == '\0') + break; + switch (c) + { + case 'a': + Aflag++; + break; + + case 'i': + Xflag++; + break; + + case 'c': + Cflag++; + break; + + case 'd': + Dflag++; + break; + + case 'w': + dp = &optarg[n + 1]; + n += (int)strlen(dp); + while (isspace((unsigned char)*dp)) dp++; + + for (i = NINCLUDE - 1; i >= 0; i--) + { + if (wraplist[i].file == NULL) + { + wraplist[i].file = dp; + break; + } + } + if (i < 0) + error(WARNING, "Too many -Xw directives"); + break; + + default: + error(WARNING, "Unknown extension option %c", c); + } + } + break; + + case '+': + Cplusplus++; + break; + + case 'u': /* -undef for GCC (dummy) */ + case 'l': /* -lang-c++ for GCC (dummy) */ + break; + + default: + break; + } + dp = "."; + fp = "<stdin>"; + fd = 0; + if (optind < argc) + { + if ((fp = strrchr(argv[optind], '/')) != NULL) + { + int len = (int)(fp - argv[optind]); + + dp = (char *) newstring((uchar *) argv[optind], len + 1, 0); + dp[len] = '\0'; + } + fp = (char *) newstring((uchar *) argv[optind], strlen(argv[optind]), 0); + if ((fd = open(fp, O_RDONLY)) <= 0) + error(FATAL, "Can't open input file %s", fp); + } + + if (optind + 1 < argc) + { + int fdo = creat(argv[optind + 1], 0666); + + if (fdo < 0) + error(FATAL, "Can't open output file %s", argv[optind + 1]); + + dup2(fdo, 1); + // coverity[leaked_handle] - on purpose + } + includelist[NINCLUDE - 1].always = 0; + includelist[NINCLUDE - 1].file = dp; + setsource(fp, -1, fd, NULL, 0); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/soltools/cpp/cpp.h b/soltools/cpp/cpp.h new file mode 100644 index 000000000..ab5a89fc9 --- /dev/null +++ b/soltools/cpp/cpp.h @@ -0,0 +1,251 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <stdlib.h> +#include <string.h> + +#define INS 327680 /* input buffer */ +#define OBS 8092 /* output buffer */ +#define NARG 32 /* Max number arguments to a macro */ +#define NINCLUDE 48 /* Max number of include directories (-I) */ +#define NIF 64 /* depth of nesting of #if */ +#define NINC 32 /* depth of nesting of #include */ + +#ifndef EOF +#define EOF (-1) +#endif + +#ifndef NULL +#define NULL 0 +#endif + +typedef unsigned char uchar; + +enum toktype +{ + END, UNCLASS, NAME, NUMBER, STRING, CCON, NL, WS, DSHARP, + EQ, NEQ, LEQ, GEQ, LSH, RSH, LAND, LOR, PPLUS, MMINUS, + ARROW, SBRA, SKET, LP, RP, DOT, AND, STAR, PLUS, MINUS, + TILDE, NOT, SLASH, PCT, LT, GT, CIRC, OR, QUEST, + COLON, ASGN, COMMA, SHARP, SEMIC, CBRA, CKET, + ASPLUS, ASMINUS, ASSTAR, ASSLASH, ASPCT, ASCIRC, ASLSH, + ASRSH, ASOR, ASAND, ELLIPS, + DSHARP1, NAME1, NAME2, DEFINED, UMINUS, ARCHITECTURE, + COMMENT +}; + +enum kwtype +{ + KIF, KIFDEF, KIFNDEF, KELIF, KELSE, KENDIF, KINCLUDE, KINCLUDENEXT, + KIMPORT, KDEFINE, KUNDEF, KLINE, KERROR, KPRAGMA, KIDENT, KDEFINED, + KMACHINE, KLINENO, KFILE, KDATE, KTIME, KSTDC, KEVAL +}; + +extern void setup_kwtab(void); + +#define ISDEFINED 0x01 /* has #defined value */ +#define ISKW 0x02 /* is PP keyword */ +#define ISUNCHANGE 0x04 /* can't be #defined in PP */ +#define ISMAC 0x08 /* builtin macro, e.g. __LINE__ */ +#define ISARCHITECTURE 0x10 /* architecture */ +#define ISACTIVE 0x80 /* is macro currently expanded */ + +#define EOB 0xFE /* sentinel for end of input buffer */ +#define EOFC 0xFD /* sentinel for end of input file */ +#define XPWS 1 /* token flag: white space to assure token sep. */ +#define XTWS 2 + +typedef struct token +{ + unsigned char type; + size_t wslen; + size_t len; + uchar *t; + unsigned int identifier; /* used from macro processor to identify where a macro becomes valid again. */ +} Token; + +typedef struct tokenrow +{ + Token *tp; /* current one to scan */ + Token *bp; /* base (allocated value) */ + Token *lp; /* last+1 token used */ + size_t max; /* number allocated */ +} Tokenrow; + +typedef struct source +{ + char *filename; /* name of file of the source */ + int line; /* current line number */ + int lineinc; /* adjustment for \\n lines */ + uchar *inb; /* input buffer */ + uchar *inp; /* input pointer */ + uchar *inl; /* end of input */ + int fd; /* input source */ + int ifdepth; /* conditional nesting in include */ + int pathdepth; + int wrap; + struct source *next; /* stack for #include */ +} Source; + +typedef struct nlist +{ + struct nlist *next; + uchar *name; + size_t len; + Tokenrow *vp; /* value as macro */ + Tokenrow *ap; /* list of argument names, if any */ + char val; /* value as preprocessor name */ + char flag; /* is defined, is pp name */ + uchar *loc; /* location of definition */ +} Nlist; + +typedef struct includelist +{ + char deleted; + char always; + char *file; +} Includelist; + +typedef struct wraplist +{ + char *file; +} Wraplist; + +#define new(t) (t *)domalloc(sizeof(t)) +#define quicklook(a,b) (namebit[(a)&077] & (1U<<((b)&037))) +#define quickset(a,b) namebit[(a)&077] |= (1U<<((b)&037)) +extern unsigned long namebit[077 + 1]; + +enum errtype +{ + INFO, WARNING, ERROR, FATAL +}; + + +typedef struct macroValidator +{ + Nlist * pMacro; + unsigned int nTokenWhereMacroBecomesValid; + struct macroValidator * + pNext; +} MacroValidator; +typedef struct mvl +{ + MacroValidator * pFirst; + unsigned int nextFreeIdentifier; +} MacroValidatorList; + +void mvl_init( + MacroValidatorList * + out_pValidators); +void mvl_destruct( + MacroValidatorList * + out_pValidators); +/* Adds MacroValidator to the list. +*/ +void mvl_add( + MacroValidatorList * + inout_pValidators, + Nlist * in_pMacro, + Token * in_pTokenWhereMacroBecomesValid); + +/* Checks if one of the validators within the list points to + the token in_pTokenToCheck. If so, the macro is set valid and + the validator is removed. +*/ +void mvl_check( + MacroValidatorList * + inout_pValidators, + Token const * inout_pTokenToCheck); + +void tokenrow_zeroTokenIdentifiers(Tokenrow* trp); + +void expandlex(void); +void fixlex(void); +void setup(int, char **); +int gettokens(Tokenrow *, int); +int comparetokens(Tokenrow *, Tokenrow *); +Source *setsource(char *, int, int, char const *, int); +void unsetsource(void); +void puttokens(Tokenrow *); +void process(Tokenrow *); +void *domalloc(size_t); +void dofree(void *); +void error(enum errtype, char *,...); +void flushout(void); +int fillbuf(Source *); +int trigraph(Source *); +int foldline(Source *); +Nlist *lookup(Token *, int); +void control(Tokenrow *); +void dodefine(Tokenrow *); +void doadefine(Tokenrow *, int); +void doinclude(Tokenrow *, int, int); +void expand(Tokenrow *, Nlist *, MacroValidatorList *); +void builtin(Tokenrow *, int); +int gatherargs(Tokenrow *, Tokenrow **, int *); +void substargs(Nlist *, Tokenrow *, Tokenrow **); +void expandrow(Tokenrow *, char *); +void maketokenrow(int, Tokenrow *); +Tokenrow *copytokenrow(Tokenrow *, Tokenrow const *); +Token *growtokenrow(Tokenrow *); +Tokenrow *normtokenrow(Tokenrow *); +void adjustrow(Tokenrow *, int); +void movetokenrow(Tokenrow *, Tokenrow const *); +void insertrow(Tokenrow *, int, Tokenrow const *); +void peektokens(Tokenrow *, char *); +void doconcat(Tokenrow *); +Tokenrow *stringify(Tokenrow *); +int lookuparg(Nlist *, Token const *); +long eval(Tokenrow *, int); +void genline(void); +void genimport(char const *, int, char const *, int); +void genwrap(int); +void setempty(Tokenrow *); +void makespace(Tokenrow *, Token const *); +char *outnum(char *, int); +int digit(int); +uchar *newstring(uchar const *, size_t, size_t); + +#define rowlen(tokrow) ((tokrow)->lp - (tokrow)->bp) + +extern char *outptr; +extern Token nltoken; +extern Source *cursource; +extern char *curtime; +extern int incdepth; +extern int ifdepth; +extern int ifsatisfied[NIF]; +extern int Mflag; +extern int Iflag; +extern int Pflag; +extern int Aflag; +extern int Lflag; +extern int Xflag; +extern int Vflag; +extern int Cflag; +extern int Dflag; +extern int Cplusplus; +extern int skipping; +extern Nlist *kwdefined; +extern Includelist includelist[NINCLUDE]; +extern Wraplist wraplist[NINCLUDE]; +extern char wd[]; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |