/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 2011 Gary Mills */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #include #include #include #include "m4.h" #define arg(n) (c < (n) ? nullstr: ap[n]) static void mkpid(char *); static void def(wchar_t **, int, int); static void dump(wchar_t *, wchar_t *); static void incl(wchar_t **, int, int); static int leftmatch(wchar_t *, wchar_t *); static void dochcom(wchar_t **ap, int c) { wchar_t *l = arg(1); wchar_t *r = arg(2); if (wcslen(l) > MAXSYM || wcslen(r) > MAXSYM) error2(gettext( "comment marker longer than %d chars"), MAXSYM); (void) wcscpy(lcom, l); (void) wcscpy(rcom, *r ? r : L"\n"); } static void docq(wchar_t **ap, int c) { wchar_t *l = arg(1); wchar_t *r = arg(2); if (wcslen(l) > MAXSYM || wcslen(r) > MAXSYM) error2(gettext( "quote marker longer than %d chars"), MAXSYM); if (c <= 1 && !*l) { l = L"`"; r = L"'"; } else if (c == 1) { r = l; } (void) wcscpy(lquote, l); (void) wcscpy(rquote, r); } static void dodecr(wchar_t **ap, int c) { pbnum(ctol(arg(1))-1); } void dodef(wchar_t **ap, int c) { def(ap, c, NOPUSH); } static void def(wchar_t **ap, int c, int mode) { wchar_t *s; if (c < 1) return; s = ap[1]; if (is_alpha(*s) || *s == '_') { s++; while (is_alnum(*s) || *s == '_') s++; } if (*s || s == ap[1]) error(gettext("bad macro name")); if ((ap[2] != NULL) && (wcscmp(ap[1], ap[2]) == 0)) error(gettext("macro defined as itself")); install(ap[1], arg(2), mode); } static void dodefn(wchar_t **ap, int c) { wchar_t *d; while (c > 0) if ((d = lookup(ap[c--])->def) != NULL) { putbak(*rquote); while (*d) putbak(*d++); putbak(*lquote); } } static void dodiv(wchar_t **ap, int c) { int f; f = wstoi(arg(1)); if (f >= 10 || f < 0) { cf = NULL; ofx = f; return; } tempfile[7] = 'a'+f; if (ofile[f] || (ofile[f] = xfopen(tempfile, "w"))) { ofx = f; cf = ofile[f]; } } /* ARGSUSED */ static void dodivnum(wchar_t **ap, int c) { pbnum((long)ofx); } /* ARGSUSED */ static void dodnl(wchar_t **ap, int c) { wchar_t t; while ((t = getchr()) != '\n' && t != WEOF) ; } static void dodump(wchar_t **ap, int c) { struct nlist *np; int i; if (c > 0) while (c--) { if ((np = lookup(*++ap))->name != NULL) dump(np->name, np->def); } else for (i = 0; i < hshsize; i++) for (np = hshtab[i]; np != NULL; np = np->next) dump(np->name, np->def); } /*ARGSUSED*/ static void dump(wchar_t *name, wchar_t *defnn) { wchar_t *s = defnn; #if !defined(__lint) /* lint doesn't grok "%ws" */ (void) fprintf(stderr, "%ws:\t", name); #endif while (*s++) ; --s; while (s > defnn) { --s; if (is_builtin(*s)) { #if !defined(__lint) /* lint doesn't grok "%ws" */ (void) fprintf(stderr, "<%ws>", barray[builtin_idx(*s)].bname); } else { #endif (void) fputwc(*s, stderr); } } (void) fputc('\n', stderr); } /*ARGSUSED*/ static void doerrp(wchar_t **ap, int c) { #if !defined(__lint) /* lint doesn't grok "%ws" */ if (c > 0) (void) fprintf(stderr, "%ws", ap[1]); #endif } long evalval; /* return value from yacc stuff */ wchar_t *pe; /* used by grammar */ static void doeval(wchar_t **ap, int c) { int base = wstoi(arg(2)); int pad = wstoi(arg(3)); extern int yyparse(void); evalval = 0; if (c > 0) { pe = ap[1]; if (yyparse() != 0) error(gettext( "invalid expression")); } pbnbr(evalval, base > 0 ? base:10, pad > 0 ? pad : 1); } /* * doexit * * Process m4exit macro. */ static void doexit(wchar_t **ap, int c) { delexit(wstoi(arg(1)), 1); } static void doif(wchar_t **ap, int c) { if (c < 3) return; while (c >= 3) { if (wcscmp(ap[1], ap[2]) == 0) { pbstr(ap[3]); return; } c -= 3; ap += 3; } if (c > 0) pbstr(ap[1]); } static void doifdef(wchar_t **ap, int c) { if (c < 2) return; while (c >= 2) { if (lookup(ap[1])->name != NULL) { pbstr(ap[2]); return; } c -= 2; ap += 2; } if (c > 0) pbstr(ap[1]); } static void doincl(wchar_t **ap, int c) { incl(ap, c, 1); } static void incl(wchar_t **ap, int c, int noisy) { if (c > 0 && wcslen(ap[1]) > 0) { if (ifx >= 9) error(gettext( "input file nesting too deep (9)")); if ((ifile[++ifx] = fopen(wstr2str(ap[1], 0), "r")) == NULL) { --ifx; if (noisy) errorf(gettext("cannot open file: %s"), strerror(errno)); } else { ipstk[ifx] = ipflr = ip; setfname(wstr2str(ap[1], 0)); } } } static void doincr(wchar_t **ap, int c) { pbnum(ctol(arg(1))+1); } static void doindex(wchar_t **ap, int c) { wchar_t *subj = arg(1); wchar_t *obj = arg(2); int i; for (i = 0; *subj; ++i) if (leftmatch(subj++, obj)) { pbnum((long)i); return; } pbnum((long)-1); } static int leftmatch(wchar_t *str, wchar_t *substr) { while (*substr) if (*str++ != *substr++) return (0); return (1); } static void dolen(wchar_t **ap, int c) { pbnum((long)wcslen(arg(1))); } static void domake(wchar_t **ap, int c) { char *path; if (c > 0) { path = wstr2str(ap[1], 1); mkpid(path); pbstr(str2wstr(path, 0)); free(path); } } static void dopopdef(wchar_t **ap, int c) { int i; for (i = 1; i <= c; ++i) (void) undef(ap[i]); } static void dopushdef(wchar_t **ap, int c) { def(ap, c, PUSH); } static void doshift(wchar_t **ap, int c) { if (c <= 1) return; for (;;) { pbstr(rquote); pbstr(ap[c--]); pbstr(lquote); if (c <= 1) break; pbstr(L","); } } static void dosincl(wchar_t **ap, int c) { incl(ap, c, 0); } static void dosubstr(wchar_t **ap, int c) { wchar_t *str; int inlen, outlen; int offset, ix; inlen = wcslen(str = arg(1)); offset = wstoi(arg(2)); if (offset < 0 || offset >= inlen) return; outlen = c >= 3 ? wstoi(ap[3]) : inlen; ix = min(offset+outlen, inlen); while (ix > offset) putbak(str[--ix]); } static void dosyscmd(wchar_t **ap, int c) { sysrval = 0; if (c > 0) { (void) fflush(stdout); sysrval = system(wstr2str(ap[1], 0)); } } /* ARGSUSED */ static void dosysval(wchar_t **ap, int c) { pbnum((long)(sysrval < 0 ? sysrval : (sysrval >> 8) & ((1 << 8) - 1)) | ((sysrval & ((1 << 8) - 1)) << 8)); } static void dotransl(wchar_t **ap, int c) { wchar_t *sink, *fr, *sto; wchar_t *source, *to; if (c < 1) return; sink = ap[1]; fr = arg(2); sto = arg(3); for (source = ap[1]; *source; source++) { wchar_t *i; to = sto; for (i = fr; *i; ++i) { if (*source == *i) break; if (*to) ++to; } if (*i) { if (*to) *sink++ = *to; } else *sink++ = *source; } *sink = EOS; pbstr(ap[1]); } static void dotroff(wchar_t **ap, int c) { struct nlist *np; trace = 0; while (c > 0) if ((np = lookup(ap[c--]))->name) np->tflag = 0; } static void dotron(wchar_t **ap, int c) { struct nlist *np; trace = !*arg(1); while (c > 0) if ((np = lookup(ap[c--]))->name) np->tflag = 1; } void doundef(wchar_t **ap, int c) { int i; for (i = 1; i <= c; ++i) while (undef(ap[i])) ; } int undef(wchar_t *nam) { struct nlist *np, *tnp; if ((np = lookup(nam))->name == NULL) return (0); tnp = hshtab[hshval]; /* lookup sets hshval */ if (tnp == np) /* it's in first place */ hshtab[hshval] = tnp->next; else { while (tnp->next != np) tnp = tnp->next; tnp->next = np->next; } free(np->name); free(np->def); free(np); return (1); } static void doundiv(wchar_t **ap, int c) { int i; if (c <= 0) for (i = 1; i < 10; i++) undiv(i, OK); else while (--c >= 0) undiv(wstoi(*++ap), OK); } /* * dowrap * * Process m4wrap macro. */ static void dowrap(wchar_t **ap, int c) { wchar_t *a = arg(1); struct Wrap *wrapentry; /* entry for list of "m4wrap" strings */ wrapentry = xmalloc(sizeof (struct Wrap)); /* store m4wrap string */ wrapentry->wrapstr = wstrdup(a); /* add this entry to the front of the list of Wrap entries */ wrapentry->nxt = wrapstart; wrapstart = wrapentry; } static void mkpid(char *as) { char *s = as; char *l; char *first_X; unsigned xcnt = 0; char my_pid[32]; int pid_len; int i = 0; /* * Count number of X. */ l = &s[strlen(s)-1]; while (l != as) { if (*l == 'X') { first_X = l; l--; xcnt++; } else if (xcnt == 0) l--; else { break; } } /* * 1) If there is no X in the passed string, * then it just return the passed string. * 2) If the length of the continuous right most X's of * the string is shorter than the length of pid, * then right most X's will be substitued with * upper digits of pid. * 3) If the length of the continuous right most X's of * the string is equat to the length of pid, * then X's will be replaced with pid. * 4) If the lenght of the continuous right most X's of * the string is longer than the length of pid, * then X's will have leading 0 followed by * pid. */ /* * If there were no X, don't do anything. */ if (xcnt == 0) return; /* * Get pid */ (void) snprintf(my_pid, sizeof (my_pid), "%d", (int)getpid()); pid_len = strlen(my_pid); if (pid_len > xcnt) my_pid[xcnt] = 0; else if (pid_len < xcnt) { while (xcnt != pid_len) { *first_X++ = '0'; xcnt--; } } /* * Copy pid */ while (i != xcnt) *first_X++ = my_pid[i++]; } struct bs barray[] = { dochcom, L"changecom", docq, L"changequote", dodecr, L"decr", dodef, L"define", dodefn, L"defn", dodiv, L"divert", dodivnum, L"divnum", dodnl, L"dnl", dodump, L"dumpdef", doerrp, L"errprint", doeval, L"eval", doexit, L"m4exit", doif, L"ifelse", doifdef, L"ifdef", doincl, L"include", doincr, L"incr", doindex, L"index", dolen, L"len", domake, L"maketemp", dopopdef, L"popdef", dopushdef, L"pushdef", doshift, L"shift", dosincl, L"sinclude", dosubstr, L"substr", dosyscmd, L"syscmd", dosysval, L"sysval", dotransl, L"translit", dotroff, L"traceoff", dotron, L"traceon", doundef, L"undefine", doundiv, L"undivert", dowrap, L"m4wrap", 0, 0 };