# # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (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 (c) 1995 by Sun Microsystems, Inc. # All Rights Reserved. # # Copyright 2019 OmniOS Community Edition (OmniOSce) Association. # include ../../../Makefile.master # Hammerhead: amd64-only SUBDIRS= $(MACH64) CSRC= common/m4.c common/m4macs.c all : TARGET= all install : TARGET= install clean : TARGET= clean clobber : TARGET= clobber # for messaging catalog # POFILE= m4.po .KEEP_STATE: all clean clobber install: $(SUBDIRS) catalog: $(POFILE) $(POFILE): $(RM) $@ $(XGETTEXT) $(XGETFLAGS) $(CSRC) sed "/^domain/d" < messages.po > $@ $(RM) messages.po $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) FRC: # # This file and its contents are supplied under the terms of the # Common Development and Distribution License ("CDDL"), version 1.0. # Copyright 2025 Hammerhead Project # PROG = m4 include $(SRC)/cmd/Makefile.cmd include $(SRC)/cmd/sgs/Makefile.com # Hammerhead: Suppress dangling-else warning in legacy m4 code CERRWARN += -Wno-dangling-else # Hammerhead: yaccpar generates unused labels CERRWARN += -Wno-unused-label # Hammerhead: m4 needs all object files, including yacc-generated parser OBJS = m4.o m4ext.o m4macs.o m4y.o SRCS = $(OBJS:%.o=../common/%.c) .KEEP_STATE: all: $(PROG) $(PROG): $(OBJS) $(LINK.c) $(OBJS) -o $@ $(LDLIBS) $(POST_PROCESS) %.o: ../common/%.c $(COMPILE.c) $< m4y.c: ../common/m4y.y $(YACC.y) ../common/m4y.y $(MV) y.tab.c m4y.c clean: $(RM) $(OBJS) clobber: clean $(RM) $(PROG) install: all $(ROOTPROG) # # This file and its contents are supplied under the terms of the # Common Development and Distribution License ("CDDL"), version 1.0. # Copyright 2025 Hammerhead Project # include ../Makefile.com include $(SRC)/Makefile.master.64 ROOTPROG = $(ROOTPROG64) install: all $(ROOTPROG) /* * 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 (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright (c) 2011 Gary Mills */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 2018, Joyent, Inc. */ #include #include #include #include "m4.h" #if defined(__lint) extern int yydebug; #endif #define match(c, s) (c == *s && (!s[1] || inpmatch(s+1))) static char tmp_name[] = "/tmp/m4aXXXXX"; static wchar_t prev_char; static int mb_cur_max; static void getflags(int *, char ***, int *); static void initalloc(void); static void expand(wchar_t **, int); static void lnsync(FILE *); static void fpath(FILE *); static void puttok(wchar_t *); static void error3(void); static wchar_t itochr(int); /*LINTED: E_STATIC_UNUSED*/ static wchar_t *chkbltin(wchar_t *); static wchar_t *inpmatch(wchar_t *); static void chkspace(char **, int *, char ***); static void catchsig(int); static FILE *m4open(char ***, char *, int *); static void showwrap(void); static void sputchr(wchar_t, FILE *); static void putchr(wchar_t); static void *xcalloc(size_t, size_t); static wint_t myfgetwc(FILE *, int); static wint_t myfputwc(wchar_t, FILE *); static int myfeof(int); int main(int argc, char **argv) { wchar_t t; int i, opt_end = 0; int sigs[] = {SIGHUP, SIGINT, SIGPIPE, 0}; #if defined(__lint) yydebug = 0; #endif for (i = 0; sigs[i]; ++i) { if (signal(sigs[i], SIG_IGN) != SIG_IGN) (void) signal(sigs[i], catchsig); } tempfile = mktemp(tmp_name); (void) close(creat(tempfile, 0)); (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ #define TEXT_DOMAIN "SYS_TEST" #endif (void) textdomain(TEXT_DOMAIN); if ((mb_cur_max = MB_CUR_MAX) > 1) wide = 1; procnam = argv[0]; getflags(&argc, &argv, &opt_end); initalloc(); setfname("-"); if (argc > 1) { --argc; ++argv; if (strcmp(argv[0], "-")) { ifile[ifx] = m4open(&argv, "r", &argc); setfname(argv[0]); } } for (;;) { token[0] = t = getchr(); token[1] = EOS; if (t == WEOF) { if (ifx > 0) { (void) fclose(ifile[ifx]); ipflr = ipstk[--ifx]; continue; } getflags(&argc, &argv, &opt_end); if (argc <= 1) /* * If dowrap() has been called, the m4wrap * macro has been processed, and a linked * list of m4wrap strings has been created. * The list starts at wrapstart. */ if (wrapstart) { /* * Now that EOF has been processed, * display the m4wrap strings. */ showwrap(); continue; } else break; --argc; ++argv; if (ifile[ifx] != stdin) (void) fclose(ifile[ifx]); if (strcmp(argv[0], "-")) ifile[ifx] = m4open(&argv, "r", &argc); else ifile[ifx] = stdin; setfname(argv[0]); continue; } if (is_alpha(t) || t == '_') { wchar_t *tp = token+1; int tlim = toksize; struct nlist *macadd; /* temp variable */ while ((*tp = getchr()) != WEOF && (is_alnum(*tp) || *tp == '_')) { tp++; if (--tlim <= 0) error2(gettext( "more than %d chars in word"), toksize); } putbak(*tp); *tp = EOS; macadd = lookup(token); *Ap = (wchar_t *)macadd; if (macadd->def) { if ((wchar_t *)(++Ap) >= astklm) { --Ap; error2(gettext( "more than %d items on " "argument stack"), stksize); } if (Cp++ == NULL) Cp = callst; Cp->argp = Ap; *Ap++ = op; puttok(token); stkchr(EOS); t = getchr(); putbak(t); if (t != '(') pbstr(L"()"); else /* try to fix arg count */ *Ap++ = op; Cp->plev = 0; } else { puttok(token); } } else if (match(t, lquote)) { int qlev = 1; for (;;) { token[0] = t = getchr(); token[1] = EOS; if (match(t, rquote)) { if (--qlev > 0) puttok(token); else break; } else if (match(t, lquote)) { ++qlev; puttok(token); } else { if (t == WEOF) error(gettext( "EOF in quote")); putchr(t); } } } else if (match(t, lcom) && ((lcom[0] != L'#' || lcom[1] != L'\0') || prev_char != '$')) { /* * Don't expand commented macro (between lcom and * rcom). * What we know so far is that we have found the * left comment char (lcom). * Make sure we haven't found '#' (lcom) immediately * preceded by '$' because we want to expand "$#". */ puttok(token); for (;;) { token[0] = t = getchr(); token[1] = EOS; if (match(t, rcom)) { puttok(token); break; } else { if (t == WEOF) error(gettext( "EOF in comment")); putchr(t); } } } else if (Cp == NULL) { putchr(t); } else if (t == '(') { if (Cp->plev) stkchr(t); else { /* skip white before arg */ while ((t = getchr()) != WEOF && is_space(t)) ; putbak(t); } ++Cp->plev; } else if (t == ')') { --Cp->plev; if (Cp->plev == 0) { stkchr(EOS); expand(Cp->argp, Ap-Cp->argp-1); op = *Cp->argp; Ap = Cp->argp-1; if (--Cp < callst) Cp = NULL; } else stkchr(t); } else if (t == ',' && Cp->plev <= 1) { stkchr(EOS); *Ap = op; if ((wchar_t *)(++Ap) >= astklm) { --Ap; error2(gettext( "more than %d items on argument stack"), stksize); } while ((t = getchr()) != WEOF && is_space(t)) ; putbak(t); } else { stkchr(t); } } if (Cp != NULL) error(gettext( "EOF in argument list")); delexit(exitstat, 1); return (0); } static wchar_t * inpmatch(wchar_t *s) { wchar_t *tp = token+1; while (*s) { *tp = getchr(); if (*tp++ != *s++) { *tp = EOS; pbstr(token+1); return (0); } } *tp = EOS; return (token); } static void getflags(int *xargc, char ***xargv, int *option_end) { char *arg; char *t; wchar_t *s[3]; while (*xargc > 1) { arg = (*xargv)[1]; /* point arg to current argument */ /* * This argument is not an option if it equals "-" or if * "--" has already been parsed. */ if (arg[0] != '-' || arg[1] == EOS || *option_end) break; if (arg[0] == '-' && arg[1] == '-' && arg[2] == '\0') { *option_end = 1; } else { switch (arg[1]) { case 'B': chkspace(&arg, xargc, xargv); bufsize = atoi(&arg[2]); if (bufsize <= 0) { bufsize = DEF_BUFSIZE; } break; case 'D': initalloc(); chkspace(&arg, xargc, xargv); for (t = &arg[2]; *t; t++) { if (*t == '=') { *t++ = EOS; break; } } s[1] = str2wstr(&arg[2], 1); s[2] = str2wstr(t, 1); dodef(&s[0], 2); free(s[1]); free(s[2]); break; case 'H': chkspace(&arg, xargc, xargv); hshsize = atoi(&arg[2]); if (hshsize <= 0) { hshsize = DEF_HSHSIZE; } break; case 'S': chkspace(&arg, xargc, xargv); stksize = atoi(&arg[2]); if (stksize <= 0) { stksize = DEF_STKSIZE; } break; case 'T': chkspace(&arg, xargc, xargv); toksize = atoi(&arg[2]); if (toksize <= 0) { toksize = DEF_TOKSIZE; } break; case 'U': initalloc(); chkspace(&arg, xargc, xargv); s[1] = str2wstr(&arg[2], 1); doundef(&s[0], 1); free(s[1]); break; case 'e': setbuf(stdout, NULL); (void) signal(SIGINT, SIG_IGN); break; case 's': /* turn on line sync */ sflag = 1; break; default: (void) fprintf(stderr, gettext("%s: bad option: %s\n"), procnam, arg); delexit(NOT_OK, 0); } } /* end else not "--" */ (*xargv)++; --(*xargc); } /* end while options to process */ } /* * Function: chkspace * * If there is a space between the option and its argument, * adjust argptr so that &arg[2] will point to beginning of the option argument. * This will ensure that processing in getflags() will work, because &arg[2] * will point to the beginning of the option argument whether or not we have * a space between the option and its argument. If there is a space between * the option and its argument, also adjust xargv and xargc because we are * processing the next argument. */ static void chkspace(char **argptr, int *xargc, char ***xargv) { if ((*argptr)[2] == EOS) { /* there is a space between the option and its argument */ (*xargv)++; /* look at the next argument */ --(*xargc); /* * Adjust argptr if the option is followed by an * option argument. */ if (*xargc > 1) { *argptr = (*xargv)[1]; /* point &arg[2] to beginning of option argument */ *argptr -= 2; } } } static void initalloc(void) { static int done = 0; int t; if (done++) return; hshtab = xcalloc(hshsize, sizeof (struct nlist *)); callst = xcalloc(stksize/3+1, sizeof (struct call)); Ap = argstk = xcalloc(stksize+3, sizeof (wchar_t *)); ipstk[0] = ipflr = ip = ibuf = xcalloc(bufsize+1, sizeof (wchar_t)); op = obuf = xcalloc(bufsize+1, sizeof (wchar_t)); token = xcalloc(toksize+1, sizeof (wchar_t)); astklm = (wchar_t *)(&argstk[stksize]); ibuflm = &ibuf[bufsize]; obuflm = &obuf[bufsize]; toklm = &token[toksize]; for (t = 0; barray[t].bname; ++t) { wchar_t p[2] = {0, EOS}; p[0] = builtin(t); install(barray[t].bname, p, NOPUSH); } install(L"unix", nullstr, NOPUSH); } void install(wchar_t *nam, wchar_t *val, int mode) { struct nlist *np; wchar_t *cp; int l; if (mode == PUSH) (void) lookup(nam); /* lookup sets hshval */ else while (undef(nam)) /* undef calls lookup */ ; np = xcalloc(1, sizeof (*np)); np->name = wstrdup(nam); np->next = hshtab[hshval]; hshtab[hshval] = np; cp = xcalloc((l = wcslen(val))+1, sizeof (*val)); np->def = cp; cp = &cp[l]; while (*val) *--cp = *val++; } struct nlist * lookup(wchar_t *str) { wchar_t *s1; struct nlist *np; static struct nlist nodef; s1 = str; for (hshval = 0; *s1; ) hshval += *s1++; hshval %= hshsize; for (np = hshtab[hshval]; np != NULL; np = np->next) { if (*str == *np->name && wcscmp(str, np->name) == 0) return (np); } return (&nodef); } static void expand(wchar_t **a1, int c) { wchar_t *dp; struct nlist *sp; sp = (struct nlist *)a1[-1]; if (sp->tflag || trace) { #if !defined(__lint) /* lint doesn't grok "%ws" */ int i; (void) fprintf(stderr, "Trace(%d): %ws", Cp-callst, a1[0]); #endif if (c > 0) { #if !defined(__lint) /* lint doesn't grok "%ws" */ (void) fprintf(stderr, "(%ws", chkbltin(a1[1])); for (i = 2; i <= c; ++i) (void) fprintf(stderr, ",%ws", chkbltin(a1[i])); #endif (void) fprintf(stderr, ")"); } (void) fprintf(stderr, "\n"); } dp = sp->def; for (; *dp; ++dp) { if (is_builtin(*dp)) { (*barray[builtin_idx(*dp)].bfunc)(a1, c); } else if (dp[1] == '$') { if (is_digit(*dp)) { int n; if ((n = *dp-'0') <= c) pbstr(a1[n]); ++dp; } else if (*dp == '#') { pbnum((long)c); ++dp; } else if (*dp == '*' || *dp == '@') { int i = c; wchar_t **a = a1; if (i > 0) for (;;) { if (*dp == '@') pbstr(rquote); pbstr(a[i--]); if (*dp == '@') pbstr(lquote); if (i <= 0) break; pbstr(L","); } ++dp; } else putbak(*dp); } else putbak(*dp); } } void setfname(char *s) { if (fname[ifx]) free(fname[ifx]); if ((fname[ifx] = strdup(s)) == NULL) error(gettext("out of storage")); fline[ifx] = 1; nflag = 1; lnsync(stdout); } static void lnsync(FILE *iop) { static int cline = 0; static int cfile = 0; if (!sflag || iop != stdout) return; if (nflag || ifx != cfile) { nflag = 0; cfile = ifx; (void) fprintf(iop, "#line %d \"", cline = fline[ifx]); fpath(iop); (void) fprintf(iop, "\"\n"); } else if (++cline != fline[ifx]) (void) fprintf(iop, "#line %d\n", cline = fline[ifx]); } static void fpath(FILE *iop) { int i; if (fname[0] == NULL) return; (void) fprintf(iop, "%s", fname[0]); for (i = 1; i <= ifx; ++i) (void) fprintf(iop, ":%s", fname[i]); } /* ARGSUSED */ static void catchsig(int i) { (void) signal(SIGHUP, SIG_IGN); (void) signal(SIGINT, SIG_IGN); delexit(NOT_OK, 0); } void delexit(int code, int flushio) { int i; cf = stdout; /* * if (ofx != 0) { * ofx = 0; * code = NOT_OK; * } */ ofx = 0; /* ensure that everything comes out */ for (i = 1; i < 10; i++) undiv(i, code); tempfile[7] = 'a'; (void) unlink(tempfile); /* flush standard I/O buffers, ie: call exit() not _exit() */ if (flushio) exit(code); _exit(code); } static void puttok(wchar_t *tp) { if (Cp) { while (*tp) stkchr(*tp++); } else if (cf) { while (*tp) { sputchr(*tp++, cf); } } } void pbstr(wchar_t *str) { wchar_t *p; for (p = str + wcslen(str); --p >= str; ) putbak(*p); } void undiv(int i, int code) { FILE *fp; wint_t c; if (i < 1 || i > 9 || i == ofx || !ofile[i]) return; (void) fclose(ofile[i]); tempfile[7] = 'a'+i; if (code == OK && cf) { fp = xfopen(tempfile, "r"); if (wide) { while ((c = myfgetwc(fp, -1)) != WEOF) sputchr((wchar_t)c, cf); } else { while ((c = (wint_t)getc(fp)) != WEOF) sputchr((wchar_t)c, cf); } (void) fclose(fp); } (void) unlink(tempfile); ofile[i] = NULL; } void pbnum(long num) { pbnbr(num, 10, 1); } void pbnbr(long nbr, int base, int len) { int neg = 0; if (base <= 0) return; if (nbr < 0) neg = 1; else nbr = -nbr; while (nbr < 0) { int i; if (base > 1) { i = nbr%base; nbr /= base; #if (-3 % 2) != -1 while (i > 0) { i -= base; ++nbr; } #endif i = -i; } else { i = 1; ++nbr; } putbak(itochr(i)); --len; } while (--len >= 0) putbak('0'); if (neg) putbak('-'); } static wchar_t itochr(int i) { if (i > 9) return ((wchar_t)(i-10+'A')); else return ((wchar_t)(i+'0')); } long ctol(wchar_t *str) { int sign; long num; while (is_space(*str)) ++str; num = 0; if (*str == '-') { sign = -1; ++str; } else sign = 1; while (is_digit(*str)) num = num*10 + *str++ - '0'; return (sign * num); } int min(int a, int b) { if (a > b) return (b); return (a); } FILE * xfopen(char *name, char *mode) { FILE *fp; if ((fp = fopen(name, mode)) == NULL) errorf(gettext("cannot open file: %s"), strerror(errno)); return (fp); } /* * m4open * * Continue processing files when unable to open the given file argument. */ FILE * m4open(char ***argvec, char *mode, int *argcnt) { FILE *fp; char *arg; while (*argcnt > 0) { arg = (*argvec)[0]; /* point arg to current file name */ if (arg[0] == '-' && arg[1] == EOS) return (stdin); else { if ((fp = fopen(arg, mode)) == NULL) { (void) fprintf(stderr, gettext( "m4: cannot open %s: "), arg); perror(""); if (*argcnt == 1) { /* last arg therefore exit */ error3(); } else { exitstat = 1; (*argvec)++; /* try next arg */ (*argcnt)--; } } else break; } } return (fp); } void * xmalloc(size_t size) { void *ptr; if ((ptr = malloc(size)) == NULL) error(gettext("out of storage")); return (ptr); } static void * xcalloc(size_t nbr, size_t size) { void *ptr; ptr = xmalloc(nbr * size); (void) memset(ptr, '\0', nbr * size); return (ptr); } /* Typical format: "cannot open file: %s" */ /* PRINTFLIKE1 */ void errorf(char *str, char *serr) { char buf[500]; (void) snprintf(buf, sizeof (buf), str, serr); error(buf); } /* PRINTFLIKE1 */ void error2(char *str, int num) { char buf[500]; (void) snprintf(buf, sizeof (buf), str, num); error(buf); } void error(char *str) { (void) fprintf(stderr, "\n%s:", procnam); fpath(stderr); (void) fprintf(stderr, ":%d %s\n", fline[ifx], str); error3(); } static void error3() { if (Cp) { struct call *mptr; /* fix limit */ *op = EOS; (Cp+1)->argp = Ap+1; for (mptr = callst; mptr <= Cp; ++mptr) { wchar_t **aptr, **lim; aptr = mptr->argp; lim = (mptr+1)->argp-1; if (mptr == callst) (void) fputws(*aptr, stderr); ++aptr; (void) fputs("(", stderr); if (aptr < lim) for (;;) { (void) fputws(*aptr++, stderr); if (aptr >= lim) break; (void) fputs(",", stderr); } } while (--mptr >= callst) (void) fputs(")", stderr); (void) fputs("\n", stderr); } delexit(NOT_OK, 1); } static wchar_t * chkbltin(wchar_t *s) { static wchar_t buf[24]; if (is_builtin(*s)) { (void) swprintf(buf, sizeof (buf)/sizeof (wchar_t), L"<%ls>", barray[builtin_idx(*s)].bname); return (buf); } return (s); } wchar_t getchr() { static wchar_t C; prev_char = C; if (ip > ipflr) return (*--ip); if (wide) { C = (wchar_t)(myfeof(ifx) ? WEOF : myfgetwc(NULL, ifx)); } else { C = (wchar_t)(feof(ifile[ifx]) ? WEOF : (wint_t)getc(ifile[ifx])); } if (C == '\n') fline[ifx]++; return (C); } /* * showwrap * * Loop through the list of m4wrap strings. Call pbstr() so that the * string will be displayed, then delete the list entry and free the memory * allocated for it. */ static void showwrap() { struct Wrap *prev; while (wrapstart) { pbstr(wrapstart->wrapstr); free(wrapstart->wrapstr); prev = wrapstart; wrapstart = wrapstart->nxt; free(prev); } } static void sputchr(wchar_t c, FILE *f) { wint_t ret; if (is_builtin(c)) return; if (wide) ret = myfputwc(c, f); else ret = (wint_t)putc((int)c, f); if (ret == WEOF) error(gettext("output error")); if (ret == '\n') lnsync(f); } static void putchr(wchar_t c) { wint_t ret; if (Cp) stkchr(c); else if (cf) { if (sflag) sputchr(c, cf); else { if (is_builtin(c)) return; if (wide) ret = myfputwc(c, cf); else ret = (wint_t)putc((int)c, cf); if (ret == WEOF) { error(gettext("output error")); } } } } wchar_t * wstrdup(wchar_t *p) { size_t len = wcslen(p); wchar_t *ret; ret = xmalloc((len + 1) * sizeof (wchar_t)); (void) wcscpy(ret, p); return (ret); } int wstoi(wchar_t *p) { return ((int)wcstol(p, NULL, 10)); } char * wstr2str(wchar_t *from, int alloc) { static char *retbuf; static size_t bsiz; char *p, *ret; if (alloc) { ret = p = xmalloc(wcslen(from) * mb_cur_max + 1); } else { while (bsiz < (wcslen(from) * mb_cur_max + 1)) { if ((p = realloc(retbuf, bsiz + 256)) == NULL) error(gettext("out of storage")); bsiz += 256; retbuf = p; } ret = p = retbuf; } if (wide) { while (*from) { int len; if (*from & INVALID_CHAR) { *p = (char)(*from & ~INVALID_CHAR); len = 1; } else { if ((len = wctomb(p, *from)) == -1) { *p = (char)*from; len = 1; } } p += len; from++; } } else { while (*from) *p++ = (char)*from++; } *p = '\0'; return (ret); } wchar_t * str2wstr(char *from, int alloc) { static wchar_t *retbuf; static size_t bsiz; wchar_t *p, *ret; if (alloc) { ret = p = xmalloc((strlen(from) + 1) * sizeof (wchar_t)); } else { while (bsiz < (strlen(from) + 1)) { if ((p = realloc(retbuf, (bsiz + 256) * sizeof (wchar_t))) == NULL) { error(gettext("out of storage")); } bsiz += 256; retbuf = p; } ret = p = retbuf; } if (wide) { while (*from) { int len; wchar_t wc; if ((len = mbtowc(&wc, from, mb_cur_max)) <= 0) { wc = *from | INVALID_CHAR; len = 1; } *p++ = wc; from += len; } } else { while (*from) *p++ = (unsigned char) *from++; } *p = 0; return (ret); } static wint_t myfgetwc(FILE *fp, int idx) { int i, c, len, nb; wchar_t wc; unsigned char *buf; if (fp == NULL) fp = ifile[idx]; else idx = 10; /* extra slot */ buf = ibuffer[idx].buffer; nb = ibuffer[idx].nbytes; len = 0; for (i = 1; i <= mb_cur_max; i++) { if (nb < i) { c = getc(fp); if (c == EOF) { if (nb == 0) return (WEOF); else break; } buf[nb++] = (unsigned char)c; } if ((len = mbtowc(&wc, (char *)buf, i)) >= 0) break; } if (len <= 0) { wc = buf[0] | INVALID_CHAR; len = 1; } nb -= len; if (nb > 0) { for (i = 0; i < nb; i++) buf[i] = buf[i + len]; } ibuffer[idx].nbytes = nb; return (wc); } static wint_t myfputwc(wchar_t wc, FILE *fp) { if (wc & INVALID_CHAR) { wc &= ~INVALID_CHAR; return (fputc((int)wc, fp)); } return (fputwc(wc, fp)); } static int myfeof(int idx) { return (ibuffer[idx].nbytes == 0 && feof(ifile[idx])); } /* * 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 (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright (c) 2011 Gary Mills */ #ifndef _M4_H #define _M4_H #include #include #include #include #include #include #include #include #include #define EOS ((wchar_t)0) #define MAXSYM 5 #define PUSH 1 #define NOPUSH 0 #define OK 0 #define NOT_OK 1 /* Used in m4.c and m4ext.c */ #define DEF_HSHSIZE 199 /* default hash table size (prime). */ #define DEF_BUFSIZE 4096 /* default pushback & arg text buffers size */ #define DEF_STKSIZE 100 /* default call stack size */ #define DEF_TOKSIZE 512 /* default token buffer size */ #define BUILTIN 0x40000000 #define INVALID_CHAR 0x80000000 #define builtin(x) ((x) | BUILTIN) #define builtin_idx(x) ((x) & (wchar_t)~BUILTIN) #define is_builtin(x) ((x) != WEOF && ((x) & BUILTIN)) /* * Since we have expanded char to wchar_t, large vaule(has BUILTIN set) * can be given to the ctype macros. First check BUILTIN, and return * FALSE if it was set. EOF/WEOF will be in this case. */ #define is_alpha(x) (!is_builtin(x) && \ (wide ? iswalpha(x) : isalpha(x))) #define is_alnum(x) (!is_builtin(x) && \ (wide ? iswalnum(x) : isalnum(x))) #define is_space(x) (!is_builtin(x) && \ (wide ? iswspace(x) : isspace(x))) #define is_digit(x) (!is_builtin(x) && iswascii(x) && isdigit(x)) struct bs { void (*bfunc)(wchar_t **, int); wchar_t *bname; }; struct call { wchar_t **argp; int plev; }; struct nlist { wchar_t *name; wchar_t *def; char tflag; struct nlist *next; }; struct Wrap { wchar_t *wrapstr; struct Wrap *nxt; }; typedef struct { unsigned char buffer[MB_LEN_MAX + 1]; char nbytes; } ibuf_t; extern FILE *cf; extern FILE *ifile[]; extern FILE *ofile[]; extern FILE *xfopen(char *, char *); extern wchar_t **Ap; extern wchar_t **argstk; extern wchar_t *astklm; extern void *xmalloc(size_t); extern char *fname[]; extern wchar_t *ibuf; extern wchar_t *ibuflm; extern wchar_t *ip; extern wchar_t *ipflr; extern wchar_t *ipstk[10]; extern wchar_t *obuf; extern wchar_t *obuflm; extern wchar_t *op; extern char *procnam; extern char *tempfile; extern wchar_t *token; extern wchar_t *toklm; extern wchar_t C; extern wchar_t getchr(); extern wchar_t lcom[]; extern wchar_t lquote[]; extern wchar_t nullstr[]; extern wchar_t rcom[]; extern wchar_t rquote[]; extern int bufsize; extern int fline[]; extern int hshsize; extern unsigned int hshval; extern int ifx; extern int nflag; extern int ofx; extern int sflag; extern int stksize; extern int sysrval; extern int toksize; extern int trace; extern int exitstat; extern long ctol(wchar_t *); extern struct bs barray[]; extern struct call *Cp; extern struct call *callst; extern struct nlist **hshtab; extern void install(); extern struct nlist *lookup(); extern struct Wrap *wrapstart; extern int wide; extern ibuf_t ibuffer[]; extern void setfname(char *); extern void pbstr(wchar_t *); extern void pbnum(long); extern void pbnbr(long, int, int); extern void undiv(int, int); extern void delexit(int, int); extern void error(char *); extern int min(int, int); extern void putbak(wchar_t); extern void stkchr(wchar_t); extern void errorf(char *, char *); extern void error2(char *, int); extern wchar_t *wstrdup(wchar_t *); extern int wstoi(wchar_t *); extern char *wstr2str(wchar_t *, int); extern wchar_t *str2wstr(char *, int); extern void dodef(wchar_t **, int); extern void doundef(wchar_t **, int); extern int undef(wchar_t *); /* * macros for performance reason. */ #define putbak(c) \ if (ip < ibuflm) \ *ip++ = (c); \ else \ error2(gettext("pushed back more than %d chars"), bufsize) #define stkchr(c) \ if (op < obuflm) \ *op++ = (c); \ else \ error2(gettext("more than %d chars of argument text"), bufsize) #endif /* _M4_H */ /* * 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 (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. */ #include "m4.h" /* storage params */ int hshsize = DEF_HSHSIZE; /* hash table size (prime) */ int bufsize = DEF_BUFSIZE; /* pushback & arg text buffers */ int stksize = DEF_STKSIZE; /* call stack */ int toksize = DEF_TOKSIZE; /* biggest word ([a-z_][a-z0-9_]*) */ /* pushback buffer */ wchar_t *ibuf; /* buffer */ wchar_t *ibuflm; /* highest buffer addr */ wchar_t *ip; /* current position */ wchar_t *ipflr; /* buffer floor */ wchar_t *ipstk[10]; /* stack for "ipflr"s */ /* arg collection buffer */ wchar_t *obuf; /* buffer */ wchar_t *obuflm; /* high address */ wchar_t *op; /* current position */ /* call stack */ struct call *callst; /* stack */ struct call *Cp = NULL; /* position */ /* token storage */ wchar_t *token; /* buffer */ wchar_t *toklm; /* high addr */ /* file name and current line storage for line sync and diagnostics */ char *fname[11]; /* file name ptr stack */ int fline[10]; /* current line nbr stack */ /* input file stuff for "include"s */ FILE *ifile[10] = {stdin}; /* stack */ int ifx; /* stack index */ ibuf_t ibuffer[11]; /* input buffer */ /* stuff for output diversions */ FILE *cf = stdout; /* current output file */ FILE *ofile[11] = {stdout}; /* output file stack */ int ofx; /* stack index */ /* comment markers */ wchar_t lcom[MAXSYM+1] = L"#"; wchar_t rcom[MAXSYM+1] = L"\n"; /* quote markers */ wchar_t lquote[MAXSYM+1] = L"`"; wchar_t rquote[MAXSYM+1] = L"\'"; /* argument ptr stack */ wchar_t **argstk; wchar_t *astklm; /* high address */ wchar_t **Ap; /* current position */ /* symbol table */ struct nlist **hshtab; /* hash table */ unsigned int hshval; /* last hash val */ /* misc */ char *procnam; /* argv[0] */ char *tempfile; /* used for diversion files */ struct Wrap *wrapstart = NULL; /* first entry in of list of "m4wrap" strings */ wchar_t nullstr[] = {0}; int nflag = 1; /* name flag, used for line sync code */ int sflag; /* line sync flag */ int sysrval; /* return val from syscmd */ int trace; /* global trace flag */ int exitstat = OK; /* global exit status */ int wide; /* multi-byte locale */ /* * 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 }; %{ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (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 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ %{ extern long evalval; #define YYSTYPE long %} %term DIGITS %left OROR %left ANDAND %left '|' '^' %left '&' %right '!' '~' %nonassoc GT GE LT LE NE EQ %left '+' '-' %left '*' '/' '%' %right POWER %right UMINUS %% s : e { evalval = $1; } | { evalval = 0; } ; e : e OROR e { $$ = ($1 != 0 || $3 != 0) ? 1 : 0; } | e ANDAND e { $$ = ($1 != 0 && $3 != 0) ? 1 : 0; } | '!' e { $$ = $2 == 0; } | '~' e { $$ = ~$2; } | e EQ e { $$ = $1 == $3; } | e NE e { $$ = $1 != $3; } | e GT e { $$ = $1 > $3; } | e GE e { $$ = $1 >= $3; } | e LT e { $$ = $1 < $3; } | e LE e { $$ = $1 <= $3; } | e '|' e { $$ = ($1 | $3); } | e '&' e { $$ = ($1 & $3); } | e '^' e { $$ = ($1 ^ $3); } | e '+' e { $$ = ($1 + $3); } | e '-' e { $$ = ($1 - $3); } | e '*' e { $$ = ($1 * $3); } | e '/' e { $$ = ($1 / $3); } | e '%' e { $$ = ($1 % $3); } | '(' e ')' { $$ = ($2); } | e POWER e { for ($$ = 1; $3-- > 0; $$ *= $1); } | '-' e %prec UMINUS { $$ = $2-1; $$ = -$2; } | '+' e %prec UMINUS { $$ = $2-1; $$ = $2; } | DIGITS { $$ = evalval; } ; %% #include "m4.h" extern wchar_t *pe; static int peek(int c, int r1, int r2); int yylex(void) { while (*pe == ' ' || *pe == '\t' || *pe == '\n') pe++; switch (*pe) { case '\0': case '+': case '-': case '/': case '%': case '^': case '~': case '(': case ')': return (*pe++); case '*': return (peek('*', POWER, '*')); case '>': return (peek('=', GE, GT)); case '<': return (peek('=', LE, LT)); case '=': return (peek('=', EQ, EQ)); case '|': return (peek('|', OROR, '|')); case '&': return (peek('&', ANDAND, '&')); case '!': return (peek('=', NE, '!')); default: { int base; evalval = 0; if (*pe == '0') { if (*++pe == 'x' || *pe == 'X') { base = 16; ++pe; } else base = 8; } else base = 10; for (;;) { int c, dig; c = *pe; if (is_digit(c)) dig = c - '0'; else if (c >= 'a' && c <= 'f') dig = c - 'a' + 10; else if (c >= 'A' && c <= 'F') dig = c - 'A' + 10; else break; evalval = evalval*base + dig; ++pe; } return (DIGITS); } } } static int peek(int c, int r1, int r2) { if (*++pe != c) return (r2); ++pe; return (r1); } /* Hammerhead: not static — bison generates a non-static forward declaration */ int yyerror(const char *msg __unused) { return (0); } %{ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (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 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ %{ extern long evalval; #define YYSTYPE long %} %term DIGITS %left OROR %left ANDAND %left '|' %left '^' %left '&' %nonassoc EQ NE %nonassoc LE GE LT GT %left LSHIFT RSHIFT %left '+' '-' %left '*' '/' '%' %right POWER %right '!' '~' UMINUS %% s : e { evalval = $1; } | { evalval = 0; } ; e : e OROR e { $$ = ($1 != 0 || $3 != 0) ? 1 : 0; } | e ANDAND e { $$ = ($1 != 0 && $3 != 0) ? 1 : 0; } | '!' e { $$ = $2 == 0; } | '~' e { $$ = ~$2; } | e EQ e { $$ = $1 == $3; } | e NE e { $$ = $1 != $3; } | e GT e { $$ = $1 > $3; } | e GE e { $$ = $1 >= $3; } | e LT e { $$ = $1 < $3; } | e LE e { $$ = $1 <= $3; } | e LSHIFT e { $$ = $1 << $3; } | e RSHIFT e { $$ = $1 >> $3; } | e '|' e { $$ = ($1 | $3); } | e '&' e { $$ = ($1 & $3); } | e '^' e { $$ = ($1 ^ $3); } | e '+' e { $$ = ($1 + $3); } | e '-' e { $$ = ($1 - $3); } | e '*' e { $$ = ($1 * $3); } | e '/' e { $$ = ($1 / $3); } | e '%' e { $$ = ($1 % $3); } | '(' e ')' { $$ = ($2); } | e POWER e { for ($$ = 1; $3-- > 0; $$ *= $1); } | '-' e %prec UMINUS { $$ = $2-1; $$ = -$2; } | '+' e %prec UMINUS { $$ = $2-1; $$ = $2; } | DIGITS { $$ = evalval; } ; %% #include "m4.h" extern wchar_t *pe; static int peek(char c, int r1, int r2); static int peek3(char c1, int rc1, char c2, int rc2, int rc3); int yylex(void) { while (*pe == ' ' || *pe == '\t' || *pe == '\n') pe++; switch (*pe) { case '\0': case '+': case '-': case '/': case '%': case '^': case '~': case '(': case ')': return (*pe++); case '*': return (peek('*', POWER, '*')); case '>': return (peek3('=', GE, '>', RSHIFT, GT)); case '<': return (peek3('=', LE, '<', LSHIFT, LT)); case '=': return (peek('=', EQ, EQ)); case '|': return (peek('|', OROR, '|')); case '&': return (peek('&', ANDAND, '&')); case '!': return (peek('=', NE, '!')); default: { int base; evalval = 0; if (*pe == '0') { if (*++pe == 'x' || *pe == 'X') { base = 16; ++pe; } else base = 8; } else base = 10; for (;;) { int c, dig; c = *pe; if (is_digit(c)) dig = c - '0'; else if (c >= 'a' && c <= 'f') dig = c - 'a' + 10; else if (c >= 'A' && c <= 'F') dig = c - 'A' + 10; else break; evalval = evalval*base + dig; ++pe; } return (DIGITS); } } } static int peek(char c, int r1, int r2) { if (*++pe != c) return (r2); ++pe; return (r1); } static int peek3(char c1, int rc1, char c2, int rc2, int rc3) { ++pe; if (*pe == c1) { ++pe; return (rc1); } if (*pe == c2) { ++pe; return (rc2); } return (rc3); } static int yyerror(const char *msg __unused) { return (0); }