/** * Save source/target and expand macro in u. * @param mb macro expansion state * @param u input macro, output expansion * @param ulen no. bytes in u buffer * @return result of expansion */ static int expandU(MacroBuf mb, char * u, size_t ulen) { const char *s = mb->s; char *t = mb->t; size_t nb = mb->nb; char *tbuf; int rc; tbuf = xcalloc(ulen + 1, sizeof(*tbuf)); mb->s = u; mb->t = tbuf; mb->nb = ulen; rc = expandMacro(mb); tbuf[ulen] = '\0'; /* XXX just in case */ if (ulen > mb->nb) strncpy(u, tbuf, (ulen - mb->nb + 1)); mb->s = s; mb->t = t; mb->nb = nb; _free(tbuf); return rc; }
int PreprocessorVisitor::visitNode(TextNode* const n) { if (n == 0) return 0; typedef std::map<std::string, PreprocessorSymbol*> SymbolsMap; const SymbolsMap& symbols = symbols_.getSymbolsMap(); std::string text = n->getRawText(); // Expand all macro invocations within the body until no further // expansions are performed. // // FIXME: recursive macro-definitions will cause this to hook up in // an infinite loop (and then crash). // for (bool expanded = true; expanded == true; ) { expanded = false; for (SymbolsMap::const_iterator it = symbols.begin(); it != symbols.end(); ++it) { if (it->second->isDefined()) { if (expandMacro(text, it->second) == true) expanded = true; } } } // for (it translation_ << text; return 1; }
/** * Macro-expand string src, return result in dynamically allocated buffer. * @param mb macro expansion state * @param src string to expand * @param slen input string length (or 0 for strlen()) * @retval target pointer to expanded string (malloced) * @return result of expansion */ static int expandThis(MacroBuf mb, const char * src, size_t slen, char **target) { struct MacroBuf_s umb; int rc; /* Copy other state from "parent", but we want a buffer of our own */ umb = *mb; umb.buf = NULL; rc = expandMacro(&umb, src, slen); *target = umb.buf; return rc; }
/** * Save source and expand field into target. * @param mb macro expansion state * @param f field * @param flen no. bytes in field * @return result of expansion */ static int expandT(MacroBuf mb, const char * f, size_t flen) { char *sbuf; const char *s = mb->s; int rc; sbuf = xcalloc(flen + 1, sizeof(*sbuf)); strncpy(sbuf, f, flen); sbuf[flen] = '\0'; mb->s = sbuf; rc = expandMacro(mb); mb->s = s; _free(sbuf); return rc; }
bool MacroExpander::pushMacro(const Macro ¯o, const Token &identifier) { assert(!macro.disabled); assert(!identifier.expansionDisabled()); assert(identifier.type == Token::IDENTIFIER); assert(identifier.text == macro.name); std::vector<Token> replacements; if (!expandMacro(macro, identifier, &replacements)) return false; // Macro is disabled for expansion until it is popped off the stack. macro.disabled = true; MacroContext *context = new MacroContext; context->macro = ¯o; context->replacements.swap(replacements); mContextStack.push_back(context); return true; }
bool MacroExpander::pushMacro(std::shared_ptr<Macro> macro, const Token &identifier) { ASSERT(!macro->disabled); ASSERT(!identifier.expansionDisabled()); ASSERT(identifier.type == Token::IDENTIFIER); ASSERT(identifier.text == macro->name); std::vector<Token> replacements; if (!expandMacro(*macro, identifier, &replacements)) return false; // Macro is disabled for expansion until it is popped off the stack. macro->disabled = true; MacroContext *context = new MacroContext; context->macro = macro; context->replacements.swap(replacements); mContextStack.push_back(context); mTotalTokensInContexts += context->replacements.size(); return true; }
int expandMacros(void * spec, rpmMacroContext mc, char * sbuf, size_t slen) { MacroBuf mb = xcalloc(1, sizeof(*mb)); char *tbuf = NULL; int rc = 0; if (sbuf == NULL || slen == 0) goto exit; if (mc == NULL) mc = rpmGlobalMacroContext; tbuf = xcalloc(slen + 1, sizeof(*tbuf)); mb->s = sbuf; mb->t = tbuf; mb->nb = slen; mb->depth = 0; mb->macro_trace = print_macro_trace; mb->expand_trace = print_expand_trace; mb->spec = spec; /* (future) %file expansion info */ mb->mc = mc; rc = expandMacro(mb); if (mb->nb == 0) rpmlog(RPMLOG_ERR, _("Target buffer overflow\n")); tbuf[slen] = '\0'; /* XXX just in case */ strncpy(sbuf, tbuf, (slen - mb->nb + 1)); exit: _free(mb); _free(tbuf); return rc; }
// // SourceTokenizerC::getExpand // SourceTokenC::Reference SourceTokenizerC::getExpand() { SourceTokenC::Reference tok = getRaw(); if (canExpand && tok->type == SourceTokenC::TT_NAM) { if (hasMacro(tok->data)) { SourceTokenC::Reference tmpTok = getExpand(); // Macro invocation! if (tmpTok->type == SourceTokenC::TT_PAREN_O) { expandMacro(tok); return getExpand(); } unget(tmpTok); } if (hasDefine(tok->data)) { expandDefine(tok); return getExpand(); } if (tok->data == "__FILE__") return SourceTokenC::create(tok->pos, tok->pos.filename, SourceTokenC::TT_STR); if (tok->data == "__LINE__") { std::ostringstream oss; oss << tok->pos.line; return SourceTokenC::create(tok->pos, oss.str(), SourceTokenC::TT_INT); } } return tok; }
/** * The main macro recursion loop. * @todo Dynamically reallocate target buffer. * @param mb macro expansion state * @return 0 on success, 1 on failure */ static int expandMacro(MacroBuf mb) { rpmMacroEntry *mep; rpmMacroEntry me; const char *s = mb->s, *se; const char *f, *fe; const char *g, *ge; size_t fn, gn; char *t = mb->t; /* save expansion pointer for printExpand */ int c; int rc = 0; int negate; const char * lastc; int chkexist; if (++mb->depth > max_macro_depth) { rpmlog(RPMLOG_ERR, _("Recursion depth(%d) greater than max(%d)\n"), mb->depth, max_macro_depth); mb->depth--; mb->expand_trace = 1; return 1; } while (rc == 0 && mb->nb > 0 && (c = *s) != '\0') { s++; /* Copy text until next macro */ switch(c) { case '%': if (*s) { /* Ensure not end-of-string. */ if (*s != '%') break; s++; /* skip first % in %% */ } default: SAVECHAR(mb, c); continue; break; } /* Expand next macro */ f = fe = NULL; g = ge = NULL; if (mb->depth > 1) /* XXX full expansion for outermost level */ t = mb->t; /* save expansion pointer for printExpand */ negate = 0; lastc = NULL; chkexist = 0; switch ((c = *s)) { default: /* %name substitution */ while (strchr("!?", *s) != NULL) { switch(*s++) { case '!': negate = ((negate + 1) % 2); break; case '?': chkexist++; break; } } f = se = s; if (*se == '-') se++; while((c = *se) && (risalnum(c) || c == '_')) se++; /* Recognize non-alnum macros too */ switch (*se) { case '*': se++; if (*se == '*') se++; break; case '#': se++; break; default: break; } fe = se; /* For "%name " macros ... */ if ((c = *fe) && isblank(c)) if ((lastc = strchr(fe,'\n')) == NULL) lastc = strchr(fe, '\0'); break; case '(': /* %(...) shell escape */ if ((se = matchchar(s, c, ')')) == NULL) { rpmlog(RPMLOG_ERR, _("Unterminated %c: %s\n"), (char)c, s); rc = 1; continue; } if (mb->macro_trace) printMacro(mb, s, se+1); s++; /* skip ( */ rc = doShellEscape(mb, s, (se - s)); se++; /* skip ) */ s = se; continue; break; case '{': /* %{...}/%{...:...} substitution */ if ((se = matchchar(s, c, '}')) == NULL) { rpmlog(RPMLOG_ERR, _("Unterminated %c: %s\n"), (char)c, s); rc = 1; continue; } f = s+1;/* skip { */ se++; /* skip } */ while (strchr("!?", *f) != NULL) { switch(*f++) { case '!': negate = ((negate + 1) % 2); break; case '?': chkexist++; break; } } for (fe = f; (c = *fe) && !strchr(" :}", c);) fe++; switch (c) { case ':': g = fe + 1; ge = se - 1; break; case ' ': lastc = se-1; break; default: break; } break; } /* XXX Everything below expects fe > f */ fn = (fe - f); gn = (ge - g); if ((fe - f) <= 0) { /* XXX Process % in unknown context */ c = '%'; /* XXX only need to save % */ SAVECHAR(mb, c); #if 0 rpmlog(RPMLOG_ERR, _("A %% is followed by an unparseable macro\n")); #endif s = se; continue; } if (mb->macro_trace) printMacro(mb, s, se); /* Expand builtin macros */ if (STREQ("global", f, fn)) { s = doDefine(mb, se, RMIL_GLOBAL, 1); continue; } if (STREQ("define", f, fn)) { s = doDefine(mb, se, mb->depth, 0); continue; } if (STREQ("undefine", f, fn)) { s = doUndefine(mb->mc, se); continue; } if (STREQ("echo", f, fn) || STREQ("warn", f, fn) || STREQ("error", f, fn)) { int waserror = 0; if (STREQ("error", f, fn)) waserror = 1; if (g != NULL && g < ge) doOutput(mb, waserror, g, gn); else doOutput(mb, waserror, f, fn); s = se; continue; } if (STREQ("trace", f, fn)) { /* XXX TODO restore expand_trace/macro_trace to 0 on return */ mb->expand_trace = mb->macro_trace = (negate ? 0 : mb->depth); if (mb->depth == 1) { print_macro_trace = mb->macro_trace; print_expand_trace = mb->expand_trace; } s = se; continue; } if (STREQ("dump", f, fn)) { rpmDumpMacroTable(mb->mc, NULL); while (iseol(*se)) se++; s = se; continue; } #ifdef WITH_LUA if (STREQ("lua", f, fn)) { rpmlua lua = NULL; /* Global state. */ const char *ls = s+sizeof("{lua:")-1; const char *lse = se-sizeof("}")+1; char *scriptbuf = (char *)xmalloc((lse-ls)+1); const char *printbuf; memcpy(scriptbuf, ls, lse-ls); scriptbuf[lse-ls] = '\0'; rpmluaSetPrintBuffer(lua, 1); if (rpmluaRunScript(lua, scriptbuf, NULL) == -1) rc = 1; printbuf = rpmluaGetPrintBuffer(lua); if (printbuf) { size_t len = strlen(printbuf); if (len > mb->nb) len = mb->nb; memcpy(mb->t, printbuf, len); mb->t += len; mb->nb -= len; } rpmluaSetPrintBuffer(lua, 0); free(scriptbuf); s = se; continue; } #endif /* XXX necessary but clunky */ if (STREQ("basename", f, fn) || STREQ("suffix", f, fn) || STREQ("expand", f, fn) || STREQ("verbose", f, fn) || STREQ("uncompress", f, fn) || STREQ("url2path", f, fn) || STREQ("u2p", f, fn) || STREQ("getenv", f, fn) || STREQ("S", f, fn) || STREQ("P", f, fn) || STREQ("F", f, fn)) { /* FIX: verbose may be set */ doFoo(mb, negate, f, fn, g, gn); s = se; continue; } /* Expand defined macros */ mep = findEntry(mb->mc, f, fn); me = (mep ? *mep : NULL); /* XXX Special processing for flags */ if (*f == '-') { if (me) me->used++; /* Mark macro as used */ if ((me == NULL && !negate) || /* Without -f, skip %{-f...} */ (me != NULL && negate)) { /* With -f, skip %{!-f...} */ s = se; continue; } if (g && g < ge) { /* Expand X in %{-f:X} */ rc = expandT(mb, g, gn); } else if (me && me->body && *me->body) {/* Expand %{-f}/%{-f*} */ rc = expandT(mb, me->body, strlen(me->body)); } s = se; continue; } /* XXX Special processing for macro existence */ if (chkexist) { if ((me == NULL && !negate) || /* Without -f, skip %{?f...} */ (me != NULL && negate)) { /* With -f, skip %{!?f...} */ s = se; continue; } if (g && g < ge) { /* Expand X in %{?f:X} */ rc = expandT(mb, g, gn); } else if (me && me->body && *me->body) { /* Expand %{?f}/%{?f*} */ rc = expandT(mb, me->body, strlen(me->body)); } s = se; continue; } if (me == NULL) { /* leave unknown %... as is */ #ifndef HACK #if DEAD /* XXX hack to skip over empty arg list */ if (fn == 1 && *f == '*') { s = se; continue; } #endif /* XXX hack to permit non-overloaded %foo to be passed */ c = '%'; /* XXX only need to save % */ SAVECHAR(mb, c); #else rpmlog(RPMLOG_ERR, _("Macro %%%.*s not found, skipping\n"), fn, f); s = se; #endif continue; } /* Setup args for "%name " macros with opts */ if (me && me->opts != NULL) { if (lastc != NULL) { se = grabArgs(mb, me, fe, lastc); } else { addMacro(mb->mc, "**", NULL, "", mb->depth); addMacro(mb->mc, "*", NULL, "", mb->depth); addMacro(mb->mc, "#", NULL, "0", mb->depth); addMacro(mb->mc, "0", NULL, me->name, mb->depth); } } /* Recursively expand body of macro */ if (me->body && *me->body) { mb->s = me->body; rc = expandMacro(mb); if (rc == 0) me->used++; /* Mark macro as used */ } /* Free args for "%name " macros with opts */ if (me->opts != NULL) freeArgs(mb); s = se; } *mb->t = '\0'; mb->s = s; mb->depth--; if (rc != 0 || mb->expand_trace) printExpansion(mb, t, mb->t); return rc; }
LEXTOKEN Lexan::checkKeyword(void) { // Check keywords if(m_string == "function") return LEX_FUNCTION; if(m_string == "return") return LEX_RETURN; if(m_string == "if") return LEX_IF; if(m_string == "else") return LEX_ELSE; if(m_string == "while") return LEX_WHILE; if(m_string == "for") return LEX_FOR; if(m_string == "foreach") return LEX_FOREACH; if(m_string == "break") return LEX_BREAK; if(m_string == "continue") return LEX_CONTINUE; if(m_string == "null") return LEX_NULL; if(m_string == "true") return LEX_TRUE; if(m_string == "false") return LEX_FALSE; if(m_string == "global") return LEX_GLOBAL; if(m_string == "__FILE__") { m_string = ID2STR(m_source.top()->getFile()); return LEX_STRING; } if(m_string == "__LINE__") { m_int = m_source.top()->getLine(); return LEX_INT; } if(m_string == "__FUNCTION__") { m_string = ID2STR(m_currently_processed_function); return LEX_STRING; } // Check include and define if(m_string == "include") { parseInclude(); return nextToken(); } if(m_string == "define") { parseDefine(); return nextToken(); } // Try to expand a macro if(expandMacro()) return nextToken(); // The string is variable or function name m_identifier = STR2ID(m_string); return LEX_IDENTIFIER; }