m4macs.c revision 1dd08564e4a3aafe66b00aee6f222b0885346fe8
/*
* 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) 1988 AT&T */
/* All Rights Reserved */
#pragma ident "%Z%%M% %I% %E% SMI"
#include <limits.h>
#include <unistd.h>
#include <sys/types.h>
#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)
error(gettext(
"can't open file"));
} 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
};