diff options
author | chin <none@none> | 2007-08-17 12:01:52 -0700 |
---|---|---|
committer | chin <none@none> | 2007-08-17 12:01:52 -0700 |
commit | da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968 (patch) | |
tree | 5280d3b78e289fe9551371ab6e7f15ef9944ea14 /usr/src/lib/libpp/common/ppcall.c | |
parent | 073dbf9103ef2a2b05d8a16e2d26db04e0374b0e (diff) | |
download | illumos-joyent-da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968.tar.gz |
6437624 RFE: Add ksh93 (as /usr/bin/ksh93) and libshell.so to OS/Net
6505835 AST tools and library (libpp) required for creating l10n messages for ksh93
PSARC/2006/550 Korn Shell 93 Integration
PSARC/2006/587 /etc/ksh.kshrc for ksh93
PSARC/2007/035 ksh93 Amendments
Contributed by Roland Mainz <roland.mainz@nrubsig.org>
--HG--
rename : usr/src/lib/libcmd/common/mapfile-vers => deleted_files/usr/src/lib/libcmd/common/mapfile-vers
rename : usr/src/lib/libcmd/common/placeholder.c => deleted_files/usr/src/lib/libcmd/common/placeholder.c
Diffstat (limited to 'usr/src/lib/libpp/common/ppcall.c')
-rw-r--r-- | usr/src/lib/libpp/common/ppcall.c | 452 |
1 files changed, 452 insertions, 0 deletions
diff --git a/usr/src/lib/libpp/common/ppcall.c b/usr/src/lib/libpp/common/ppcall.c new file mode 100644 index 0000000000..8e273dc92f --- /dev/null +++ b/usr/src/lib/libpp/common/ppcall.c @@ -0,0 +1,452 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * preprocessor macro call + */ + +#include "pplib.h" + +#include <ctype.h> + +/* + * call a macro by pushing its value on the input stream + * only the macro token itself has been consumed + * -1 returned if macro disabled + * 0 returned if tok==0 and sym->mac->value to be copied to output by caller + * 1 returned if value pushed on input + */ + +int +ppcall(register struct ppsymbol* sym, int tok) +{ + register int c; + register char* p; + register char* q; + register struct ppmacro* mac; + int n; + int m; + int ret; + int old_hidden; + int last_line; + long old_state; + char* last_file; + char* old_token; + struct ppmacstk* mp; + struct ppinstk* old_in; + struct ppinstk* kp; + struct pptuple* tp; + + ret = -1; + sym->flags |= SYM_NOTICED; + if (mac = sym->macro) + { + count(macro); + if ((sym->flags & SYM_PREDICATE) && (pp.state & (CONDITIONAL|WARN)) == (CONDITIONAL|WARN)) + error(1, "%s: macro definition overrides assertion: use #%s ...", sym->name, sym->name); + if (sym->flags & SYM_DISABLED) +#if COMPATIBLE + if ((pp.state & (COMPATIBILITY|TRANSITION)) != COMPATIBILITY || !mac->arity) +#endif + { + pp.mode |= MARKMACRO; +#if COMPATIBLE + if ((pp.state & (COMPATIBILITY|STRICT)) == (COMPATIBILITY|STRICT)) + error(1, "%s: macro recursion inhibited", sym->name); +#endif + goto disable; + } + if ((sym->flags & SYM_PREDEFINED) && !(pp.mode & (HOSTED|INACTIVE))) + { +#if COMPATIBLE + if (*sym->name != '_' && !(pp.state & COMPATIBILITY)) +#else + if (*sym->name != '_') +#endif + { + if (pp.state & STRICT) + { + error(1, "%s: obsolete predefined symbol expansion disabled", sym->name); + goto disable; + } + error(1, "%s: obsolete predefined symbol expanded%s", sym->name, (pp.state & DIRECTIVE) ? "" : " outside of directive"); + } + else if (!(pp.state & DIRECTIVE) && mac->value && (ppisdig(*mac->value) || *mac->value == '#')) + error(1, "%s: predefined symbol expanded outside of directive", sym->name); + } + debug((-5, "macro %s = %s", sym->name, mac->value)); + if (pp.macref) + (*pp.macref)(sym, error_info.file, error_info.line, (pp.state & CONDITIONAL) ? REF_IF : REF_NORMAL, 0L); + if (tp = mac->tuple) + { + old_state = pp.state; + pp.state |= DEFINITION|NOSPACE; + old_token = pp.token; + n = 2 * MAXTOKEN; + pp.token = p = oldof(0, char, 0, n); + q = p + MAXTOKEN; + *pp.token++ = ' '; + old_hidden = pp.hidden; + while (c = pplex()) + { + if (c == '\n') + { + pp.hidden++; + pp.state |= HIDDEN|NEWLINE; + old_state |= HIDDEN|NEWLINE; + error_info.line++; + } + else if (c == '#') + { + ungetchr(c); + break; + } + else + { + for (;;) + { + if (streq(pp.token, tp->token)) + { + if (!(tp = tp->match)) + break; + if (!tp->nomatch) + { + free(p); + pp.state = old_state; + pp.token = old_token; + PUSH_TUPLE(sym, tp->token); + ret = 1; + goto disable; + } + } + else if (!(tp = tp->nomatch)) + break; + } + if (!tp) + { + pp.token = pp.toknxt; + break; + } + } + if ((pp.token = pp.toknxt) > q) + { + c = pp.token - p; + p = newof(p, char, n += MAXTOKEN, 0); + q = p + n - MAXTOKEN; + pp.token = p + c; + } + *pp.token++ = ' '; + } + if (pp.token > p && *(pp.token - 1) == ' ') + pp.token--; + if (pp.hidden != old_hidden) + *pp.token++ = '\n'; + else + *pp.token++ = ' '; + *pp.token = 0; + pp.state = old_state; + pp.token = old_token; + if (*p) + PUSH_RESCAN(p); + else + free(p); + if (!mac->value) + goto disable; + } + if (sym->flags & SYM_FUNCTION) + { + /* + * a quick and dirty '(' peek to avoid possibly + * inappropriate ungetchr()'s below + */ + + for (p = pp.in->nextchr; isspace(*p); p++); + if ((c = *p) != '(' && c != '/' && c != 0 && c != MARK) + goto disable; + old_token = pp.token; + mp = pp.macp->next; + if ((pp.token = (char*)&mp->arg[mac->arity + 1]) > pp.maxmac) + error(3, "%s: too many nested function-like macros", sym->name); + old_hidden = pp.hidden; + old_state = pp.state; + pp.state |= DEFINITION|FILEPOP|NOSPACE; + while ((c = pplex()) == '\n') + { + pp.hidden++; + pp.state |= HIDDEN|NEWLINE; + old_state |= HIDDEN|NEWLINE; + error_info.line++; + } + if (c != '(') + { + pp.state = old_state; + if (c) + { + p = pp.toknxt; + while (p > pp.token) + ungetchr(*--p); +#if COMPATIBLE + if ((pp.state & (COMPATIBILITY|STRICT)) == (COMPATIBILITY|STRICT)) + error(1, "%s: macro arguments omitted", sym->name); +#endif + if (c == T_ID && !(pp.state & HIDDEN)) + ungetchr(' '); + } + if (pp.hidden != old_hidden) + { + ungetchr('\n'); + error_info.line--; + if (pp.hidden && !--pp.hidden) + pp.state &= ~HIDDEN; + } + pp.token = old_token; + goto disable; + } + pp.state = old_state; + + /* + * arg[i][-1] is an extra char for each actual i + * for a possible ungetchr('"') during IN_QUOTE + * arg[i][-1]==0 if arg i need not be expanded + * arg[0][-2] holds the actual arg count + */ + + c = 0; + m = 0; + n = 0; + mp = pp.macp->next; + p = pp.token = (char*)&mp->arg[mac->arity + 1]; + pp.state |= COLLECTING|NOEXPAND; + pp.state &= ~FILEPOP; + sym->flags |= SYM_ACTIVE; + old_in = pp.in; + last_line = error_info.line; + last_file = error_info.file; + mp->line = error_info.line; +#if MACKEYARGS + if (pp.option & KEYARGS) + { + for (c = 0; c < mac->arity; c++) + mp->arg[c] = mac->args.key[c].value + 1; + mp->arg[0]++; + } + else +#endif + { + *++p = ' '; + mp->arg[0] = ++p; + } +#if MACKEYARGS + keyarg: + if (pp.option & KEYARGS) + { + pp.state |= NOSPACE; + switch (pplex()) + { + case T_ID: + break; + case ')': /* no actual key args */ + if (!(pp.state & NOEXPAND)) + pp.state |= NOEXPAND; + for (c = 0; c < mac->arity; c++) + mp->arg[c][-1] = 0; + c = 0; + goto endactuals; + default: + error(3, "%s: invalid keyword macro argument", pp.token); + break; + } + for (c = 0; c < mac->arity; c++) + if (streq(pp.token, mac->args.key[c].name)) break; + if (c >= mac->arity) + error(2, "%s: invalid macro argument keyword", pp.token); + if (pplex() != '=') + error(2, "= expected in keyword macro argument"); + pp.state &= ~NOSPACE; + if (!c) + p++; + pp.token = mp->arg[c] = ++p; + } +#endif + for (;;) + { + if ((pp.mactop = pp.token = p) >= pp.maxmac) + error(3, "%s: too many nested function-like macros", sym->name); + switch (pplex()) + { + case '(': + n++; + break; + case ')': + if (!n--) + { + if (p > mp->arg[c] && *(p - 1) == ' ') + p--; + if (p > mp->arg[c] && *(p - 1) == '\\') + { + for (q = mp->arg[c]; q < p; q++) + if (*q == '\\') + q++; + if (q > p) + *p++ = '\\'; + } +#if MACKEYARGS + *p = 0; + m++; +#endif + goto endactuals; + } + break; + case ',': + if (!n && (m++, (c < mac->arity - 1 || !(sym->flags & SYM_VARIADIC)))) + { + if (p > mp->arg[c] && *(p - 1) == ' ') + p--; + *p++ = 0; + if (!(pp.state & NOEXPAND)) + pp.state |= NOEXPAND; + else + mp->arg[c][-1] = 0; +#if MACKEYARGS + if (pp.option & KEYARGS) + { + pp.token = p + 1; + goto keyarg; + } +#endif + { + if ((pp.state & STRICT) && p == mp->arg[c]) + error(1, "%s: macro call argument %d is null", sym->name, c + 1); + if (c < mac->arity) + c++; + *p++ = ' '; + } + pp.toknxt = mp->arg[c] = p; + } + break; + case 0: + if (pp.in == old_in) + kp = 0; + else + for (kp = pp.in; kp && kp != old_in; kp = kp->prev); + if (!kp) + { + error( +#if COMPATIBLE + (pp.state & COMPATIBILITY) ? 3 : +#endif + 2, "%s: %s in macro argument list", sym->name, pptokchr(0)); + goto endactuals; + } + continue; + case '\n': + pp.state |= HIDDEN; + error_info.line++; + pp.hidden++; + /*FALLTHROUGH*/ + case ' ': + if (p > mp->arg[c] && *(p - 1) != ' ') *p++ = ' '; + continue; + } + p = pp.toknxt; + if (error_info.line != last_line) + { + SETLINE(p, error_info.line); + last_line = error_info.line; + } + if (error_info.file != last_file) + { + SETFILE(p, error_info.file); + last_file = error_info.file; + } + } + endactuals: + if (pp.state & NOEXPAND) + mp->arg[c][-1] = 0; + pp.token = old_token; + if (pp.in != old_in) + { + for (kp = pp.in; kp && kp != old_in; kp = kp->prev); + if (kp) + error(2, "%s: macro call starts and ends in different files", sym->name); + } + pp.state &= ~(COLLECTING|FILEPOP|NOEXPAND); + sym->flags &= ~SYM_ACTIVE; +#if MACKEYARGS + if (!(pp.option & KEYARGS)) +#endif + { + if (p > mp->arg[0] && ++m || (sym->flags & SYM_VARIADIC)) + c++; + if (c != mac->arity && !(sym->flags & SYM_EMPTY)) + { + n = mac->arity; + if (!(sym->flags & SYM_VARIADIC)) + error(1, "%s: %d actual argument%s expected", sym->name, n, n == 1 ? "" : "s"); + else if (c < --n) + error(1, "%s: at least %d actual argument%s expected", sym->name, n, n == 1 ? "" : "s"); +#if COMPATIBLE + if (!c && (pp.state & (COMPATIBILITY|STRICT)) == (COMPATIBILITY|STRICT)) + goto disable; +#endif + } + if (!c) + ++c; + while (c < mac->arity) + mp->arg[c++] = (char*)"\0" + 1; + } + mp->arg[0][-2] = m; + *p++ = 0; + nextframe(mp, p); + count(function); + } + if (!tok && (sym->flags & SYM_NOEXPAND)) + { + if (sym->flags & SYM_FUNCTION) + popframe(mp); + ret = !mac->size; + } + else if (!(pp.state & HEADER) || (pp.option & HEADEREXPANDALL) || pp.in->type != IN_COPY) + { + if (sym->flags & SYM_MULTILINE) + PUSH_MULTILINE(sym); + else + PUSH_MACRO(sym); + ret = 1; + } + } + disable: + if (ret < 0 && sym->hidden && !(pp.mode & EXPOSE) && !(pp.state & HEADER) && (pp.in->type == IN_FILE || pp.in->type == IN_MACRO || pp.in->type == IN_EXPAND)) + { + struct ppinstk* inp; + + for (inp = pp.in; inp->type != IN_FILE && inp->prev; inp = inp->prev); + sfsprintf(pp.hidebuf, MAXTOKEN, "_%d_%s_hIDe", inp->index, sym->name); + PUSH_STRING(pp.hidebuf); + ret = 1; + } + pp.state &= ~NEWLINE; + pp.in->flags |= IN_tokens; + count(token); + return ret; +} |