Synchronize with laster version of m4 from OpenBSD and NetBSD
This bring better compatibility with gnum4 Reviewed by: cognet Approved by: cognet Obtained from: OpenBSD, NetBSD
This commit is contained in:
parent
273ffa0653
commit
0d5c584942
@ -5,8 +5,20 @@
|
||||
# if you want the paste & spaste macros.
|
||||
|
||||
PROG= m4
|
||||
CFLAGS+=-DEXTENDED
|
||||
CFLAGS+=-DEXTENDED -I${.CURDIR}/lib
|
||||
LDADD= -ly -ll
|
||||
# clang needs 1 while with gcc we can use 2
|
||||
#WARNS= 1
|
||||
|
||||
SRCS= eval.c expr.c look.c main.c misc.c gnum4.c trace.c
|
||||
SRCS= eval.c expr.c look.c main.c misc.c gnum4.c trace.c parser.y tokenizer.l
|
||||
.PATH: ${.CURDIR}/lib
|
||||
SRCS+= ohash_create_entry.c ohash_delete.c ohash_do.c ohash_entries.c \
|
||||
ohash_enum.c ohash_init.c ohash_int.h ohash_interval.c \
|
||||
ohash_lookup_interval.c ohash_lookup_memory.c ohash_qlookup.c \
|
||||
ohash_qlookupi.c
|
||||
|
||||
tokenizer.o: parser.h
|
||||
|
||||
CLEANFILES+= parser.c parser.h tokenizer.o
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: eval.c,v 1.44 2002/04/26 16:15:16 espie Exp $ */
|
||||
/* $OpenBSD: eval.c,v 1.69 2011/03/24 11:23:08 espie Exp $ */
|
||||
/* $NetBSD: eval.c,v 1.7 1996/11/10 21:21:29 pk Exp $ */
|
||||
|
||||
/*
|
||||
@ -16,7 +16,7 @@
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
@ -33,19 +33,10 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)eval.c 8.2 (Berkeley) 4/27/95";
|
||||
#else
|
||||
#if 0
|
||||
static char rcsid[] = "$OpenBSD: eval.c,v 1.44 2002/04/26 16:15:16 espie Exp $";
|
||||
#endif
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
|
||||
/*
|
||||
* eval.c
|
||||
* Facility: m4 macro processor
|
||||
@ -53,21 +44,21 @@ __FBSDID("$FreeBSD$");
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <err.h>
|
||||
#include "mdef.h"
|
||||
#include "stdd.h"
|
||||
#include "extern.h"
|
||||
#include "pathnames.h"
|
||||
|
||||
#define BUILTIN_MARKER "__builtin_"
|
||||
|
||||
static void dodefn(const char *);
|
||||
static void dopushdef(const char *, const char *);
|
||||
static void dodump(const char *[], int);
|
||||
@ -75,10 +66,9 @@ static void dotrace(const char *[], int, int);
|
||||
static void doifelse(const char *[], int);
|
||||
static int doincl(const char *);
|
||||
static int dopaste(const char *);
|
||||
static void gnu_dochq(const char *[], int);
|
||||
static void dochq(const char *[], int);
|
||||
static void gnu_dochc(const char *[], int);
|
||||
static void dochc(const char *[], int);
|
||||
static void dom4wrap(const char *);
|
||||
static void dodiv(int);
|
||||
static void doundiv(const char *[], int);
|
||||
static void dosub(const char *[], int);
|
||||
@ -86,7 +76,7 @@ static void map(char *, const char *, const char *, const char *);
|
||||
static const char *handledash(char *, char *, const char *);
|
||||
static void expand_builtin(const char *[], int, int);
|
||||
static void expand_macro(const char *[], int);
|
||||
static void dump_one_def(ndptr);
|
||||
static void dump_one_def(const char *, struct macro_definition *);
|
||||
|
||||
unsigned long expansion_id;
|
||||
|
||||
@ -95,7 +85,7 @@ unsigned long expansion_id;
|
||||
* argc - number of elements in argv.
|
||||
* argv - element vector :
|
||||
* argv[0] = definition of a user
|
||||
* macro or nil if built-in.
|
||||
* macro or NULL if built-in.
|
||||
* argv[1] = name of the macro or
|
||||
* built-in.
|
||||
* argv[2] = parameters to user-defined
|
||||
@ -110,21 +100,20 @@ unsigned long expansion_id;
|
||||
* argc is 3 for macro-or-builtin() and 2 for macro-or-builtin
|
||||
*/
|
||||
void
|
||||
eval(const char *argv[], int argc, int td)
|
||||
eval(const char *argv[], int argc, int td, int is_traced)
|
||||
{
|
||||
ssize_t mark = -1;
|
||||
size_t mark = SIZE_MAX;
|
||||
|
||||
expansion_id++;
|
||||
if (td & RECDEF)
|
||||
errx(1, "%s at line %lu: expanding recursive definition for %s",
|
||||
CURRENT_NAME, CURRENT_LINE, argv[1]);
|
||||
if (traced_macros && is_traced(argv[1]))
|
||||
m4errx(1, "expanding recursive definition for %s.", argv[1]);
|
||||
if (is_traced)
|
||||
mark = trace(argv, argc, infile+ilevel);
|
||||
if (td == MACRTYPE)
|
||||
expand_macro(argv, argc);
|
||||
else
|
||||
expand_builtin(argv, argc, td);
|
||||
if (mark != -1)
|
||||
if (mark != SIZE_MAX)
|
||||
finish_trace(mark);
|
||||
}
|
||||
|
||||
@ -150,9 +139,12 @@ expand_builtin(const char *argv[], int argc, int td)
|
||||
* have macro-or-builtin() type call. We adjust
|
||||
* argc to avoid further checking..
|
||||
*/
|
||||
ac = argc;
|
||||
/* we keep the initial value for those built-ins that differentiate
|
||||
* between builtin() and builtin.
|
||||
*/
|
||||
ac = argc;
|
||||
|
||||
if (argc == 3 && !*(argv[2]))
|
||||
if (argc == 3 && !*(argv[2]) && !mimic_gnu)
|
||||
argc--;
|
||||
|
||||
switch (td & TYPEMASK) {
|
||||
@ -184,9 +176,27 @@ expand_builtin(const char *argv[], int argc, int td)
|
||||
* doexpr - evaluate arithmetic
|
||||
* expression
|
||||
*/
|
||||
{
|
||||
int base = 10;
|
||||
int maxdigits = 0;
|
||||
const char *errstr;
|
||||
|
||||
if (argc > 3) {
|
||||
base = strtonum(argv[3], 2, 36, &errstr);
|
||||
if (errstr) {
|
||||
m4errx(1, "expr: base %s invalid.", argv[3]);
|
||||
}
|
||||
}
|
||||
if (argc > 4) {
|
||||
maxdigits = strtonum(argv[4], 0, INT_MAX, &errstr);
|
||||
if (errstr) {
|
||||
m4errx(1, "expr: maxdigits %s invalid.", argv[4]);
|
||||
}
|
||||
}
|
||||
if (argc > 2)
|
||||
pbnum(expr(argv[2]));
|
||||
pbnumbase(expr(argv[2]), base, maxdigits);
|
||||
break;
|
||||
}
|
||||
|
||||
case IFELTYPE:
|
||||
if (argc > 4)
|
||||
@ -200,7 +210,7 @@ expand_builtin(const char *argv[], int argc, int td)
|
||||
* another definition
|
||||
*/
|
||||
if (argc > 3) {
|
||||
if (lookup(argv[2]) != nil)
|
||||
if (lookup_macro_definition(argv[2]) != NULL)
|
||||
pbstr(argv[3]);
|
||||
else if (argc > 4)
|
||||
pbstr(argv[4]);
|
||||
@ -238,7 +248,7 @@ expand_builtin(const char *argv[], int argc, int td)
|
||||
* dosys - execute system command
|
||||
*/
|
||||
if (argc > 2) {
|
||||
fflush(NULL);
|
||||
fflush(stdout);
|
||||
sysval = system(argv[2]);
|
||||
}
|
||||
break;
|
||||
@ -255,7 +265,7 @@ expand_builtin(const char *argv[], int argc, int td)
|
||||
case ESYSCMDTYPE:
|
||||
if (argc > 2)
|
||||
doesyscmd(argv[2]);
|
||||
break;
|
||||
break;
|
||||
case INCLTYPE:
|
||||
if (argc > 2)
|
||||
if (!doincl(argv[2]))
|
||||
@ -271,7 +281,7 @@ expand_builtin(const char *argv[], int argc, int td)
|
||||
case PASTTYPE:
|
||||
if (argc > 2)
|
||||
if (!dopaste(argv[2]))
|
||||
err(1, "%s at line %lu: paste(%s)",
|
||||
err(1, "%s at line %lu: paste(%s)",
|
||||
CURRENT_NAME, CURRENT_LINE, argv[2]);
|
||||
break;
|
||||
|
||||
@ -279,19 +289,16 @@ expand_builtin(const char *argv[], int argc, int td)
|
||||
if (argc > 2)
|
||||
(void) dopaste(argv[2]);
|
||||
break;
|
||||
case FORMATTYPE:
|
||||
doformat(argv, argc);
|
||||
break;
|
||||
#endif
|
||||
case CHNQTYPE:
|
||||
if (mimic_gnu)
|
||||
gnu_dochq(argv, ac);
|
||||
else
|
||||
dochq(argv, argc);
|
||||
dochq(argv, ac);
|
||||
break;
|
||||
|
||||
case CHNCTYPE:
|
||||
if (mimic_gnu)
|
||||
gnu_dochc(argv, ac);
|
||||
else
|
||||
dochc(argv, argc);
|
||||
dochc(argv, argc);
|
||||
break;
|
||||
|
||||
case SUBSTYPE:
|
||||
@ -314,7 +321,7 @@ expand_builtin(const char *argv[], int argc, int td)
|
||||
pbstr(rquote);
|
||||
pbstr(argv[n]);
|
||||
pbstr(lquote);
|
||||
putback(COMMA);
|
||||
pushback(COMMA);
|
||||
}
|
||||
pbstr(rquote);
|
||||
pbstr(argv[3]);
|
||||
@ -350,7 +357,7 @@ expand_builtin(const char *argv[], int argc, int td)
|
||||
*/
|
||||
if (argc > 2)
|
||||
for (n = 2; n < argc; n++)
|
||||
remhash(argv[n], ALL);
|
||||
macro_undefine(argv[n]);
|
||||
break;
|
||||
|
||||
case POPDTYPE:
|
||||
@ -361,7 +368,7 @@ expand_builtin(const char *argv[], int argc, int td)
|
||||
*/
|
||||
if (argc > 2)
|
||||
for (n = 2; n < argc; n++)
|
||||
remhash(argv[n], TOP);
|
||||
macro_popdef(argv[n]);
|
||||
break;
|
||||
|
||||
case MKTMTYPE:
|
||||
@ -395,7 +402,7 @@ expand_builtin(const char *argv[], int argc, int td)
|
||||
if (argc > 3) {
|
||||
char *temp;
|
||||
|
||||
temp = xalloc(strlen(argv[2])+1);
|
||||
temp = xalloc(strlen(argv[2])+1, NULL);
|
||||
if (argc > 4)
|
||||
map(temp, argv[2], argv[3], argv[4]);
|
||||
else
|
||||
@ -441,7 +448,8 @@ expand_builtin(const char *argv[], int argc, int td)
|
||||
* dom4wrap - set up for
|
||||
* wrap-up/wind-down activity
|
||||
*/
|
||||
m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
|
||||
if (argc > 2)
|
||||
dom4wrap(argv[2]);
|
||||
break;
|
||||
|
||||
case EXITTYPE:
|
||||
@ -488,8 +496,7 @@ expand_builtin(const char *argv[], int argc, int td)
|
||||
pbstr(lquote);
|
||||
break;
|
||||
default:
|
||||
errx(1, "%s at line %lu: eval: major botch.",
|
||||
CURRENT_NAME, CURRENT_LINE);
|
||||
m4errx(1, "eval: major botch.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -512,7 +519,7 @@ expand_macro(const char *argv[], int argc)
|
||||
p--; /* last character of defn */
|
||||
while (p > t) {
|
||||
if (*(p - 1) != ARGFLAG)
|
||||
PUTBACK(*p);
|
||||
PUSHBACK(*p);
|
||||
else {
|
||||
switch (*p) {
|
||||
|
||||
@ -536,10 +543,10 @@ expand_macro(const char *argv[], int argc)
|
||||
if (argc > 2) {
|
||||
for (n = argc - 1; n > 2; n--) {
|
||||
pbstr(argv[n]);
|
||||
putback(COMMA);
|
||||
pushback(COMMA);
|
||||
}
|
||||
pbstr(argv[2]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '@':
|
||||
if (argc > 2) {
|
||||
@ -547,7 +554,7 @@ expand_macro(const char *argv[], int argc)
|
||||
pbstr(rquote);
|
||||
pbstr(argv[n]);
|
||||
pbstr(lquote);
|
||||
putback(COMMA);
|
||||
pushback(COMMA);
|
||||
}
|
||||
pbstr(rquote);
|
||||
pbstr(argv[2]);
|
||||
@ -555,8 +562,8 @@ expand_macro(const char *argv[], int argc)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
PUTBACK(*p);
|
||||
PUTBACK('$');
|
||||
PUSHBACK(*p);
|
||||
PUSHBACK('$');
|
||||
break;
|
||||
}
|
||||
p--;
|
||||
@ -564,42 +571,20 @@ expand_macro(const char *argv[], int argc)
|
||||
p--;
|
||||
}
|
||||
if (p == t) /* do last character */
|
||||
PUTBACK(*p);
|
||||
PUSHBACK(*p);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* dodefine - install definition in the table
|
||||
*/
|
||||
void
|
||||
dodefine(const char *name, const char *defn)
|
||||
{
|
||||
ndptr p;
|
||||
int n;
|
||||
|
||||
if (!*name)
|
||||
errx(1, "%s at line %lu: null definition.", CURRENT_NAME,
|
||||
CURRENT_LINE);
|
||||
if ((p = lookup(name)) == nil)
|
||||
p = addent(name);
|
||||
else if (p->defn != null)
|
||||
free((char *) p->defn);
|
||||
if (strncmp(defn, BUILTIN_MARKER, sizeof(BUILTIN_MARKER)-1) == 0) {
|
||||
n = builtin_type(defn+sizeof(BUILTIN_MARKER)-1);
|
||||
if (n != -1) {
|
||||
p->type = n & TYPEMASK;
|
||||
if ((n & NOARGS) == 0)
|
||||
p->type |= NEEDARGS;
|
||||
p->defn = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!*defn)
|
||||
p->defn = null;
|
||||
if (!*name && !mimic_gnu)
|
||||
m4errx(1, "null definition.");
|
||||
else
|
||||
p->defn = xstrdup(defn);
|
||||
p->type = MACRTYPE;
|
||||
if (STREQ(name, defn))
|
||||
p->type |= RECDEF;
|
||||
macro_define(name, defn);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -609,16 +594,15 @@ dodefine(const char *name, const char *defn)
|
||||
static void
|
||||
dodefn(const char *name)
|
||||
{
|
||||
ndptr p;
|
||||
const char *real;
|
||||
struct macro_definition *p;
|
||||
|
||||
if ((p = lookup(name)) != nil) {
|
||||
if (p->defn != null) {
|
||||
if ((p = lookup_macro_definition(name)) != NULL) {
|
||||
if ((p->type & TYPEMASK) == MACRTYPE) {
|
||||
pbstr(rquote);
|
||||
pbstr(p->defn);
|
||||
pbstr(lquote);
|
||||
} else if ((real = builtin_realname(p->type)) != NULL) {
|
||||
pbstr(real);
|
||||
} else {
|
||||
pbstr(p->defn);
|
||||
pbstr(BUILTIN_MARKER);
|
||||
}
|
||||
}
|
||||
@ -634,40 +618,28 @@ dodefn(const char *name)
|
||||
static void
|
||||
dopushdef(const char *name, const char *defn)
|
||||
{
|
||||
ndptr p;
|
||||
|
||||
if (!*name)
|
||||
errx(1, "%s at line %lu: null definition", CURRENT_NAME,
|
||||
CURRENT_LINE);
|
||||
p = addent(name);
|
||||
if (!*defn)
|
||||
p->defn = null;
|
||||
if (!*name && !mimic_gnu)
|
||||
m4errx(1, "null definition.");
|
||||
else
|
||||
p->defn = xstrdup(defn);
|
||||
p->type = MACRTYPE;
|
||||
if (STREQ(name, defn))
|
||||
p->type |= RECDEF;
|
||||
macro_pushdef(name, defn);
|
||||
}
|
||||
|
||||
/*
|
||||
* dump_one_def - dump the specified definition.
|
||||
*/
|
||||
static void
|
||||
dump_one_def(ndptr p)
|
||||
dump_one_def(const char *name, struct macro_definition *p)
|
||||
{
|
||||
const char *real;
|
||||
|
||||
if (!traceout)
|
||||
traceout = stderr;
|
||||
if (mimic_gnu) {
|
||||
if ((p->type & TYPEMASK) == MACRTYPE)
|
||||
fprintf(traceout, "%s:\t%s\n", p->name, p->defn);
|
||||
fprintf(traceout, "%s:\t%s\n", name, p->defn);
|
||||
else {
|
||||
real = builtin_realname(p->type);
|
||||
if (real == NULL)
|
||||
real = null;
|
||||
fprintf(traceout, "%s:\t<%s>\n", p->name, real);
|
||||
}
|
||||
fprintf(traceout, "%s:\t<%s>\n", name, p->defn);
|
||||
}
|
||||
} else
|
||||
fprintf(traceout, "`%s'\t`%s'\n", p->name, p->defn);
|
||||
fprintf(traceout, "`%s'\t`%s'\n", name, p->defn);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -679,17 +651,14 @@ static void
|
||||
dodump(const char *argv[], int argc)
|
||||
{
|
||||
int n;
|
||||
ndptr p;
|
||||
struct macro_definition *p;
|
||||
|
||||
if (argc > 2) {
|
||||
for (n = 2; n < argc; n++)
|
||||
if ((p = lookup(argv[n])) != nil)
|
||||
dump_one_def(p);
|
||||
} else {
|
||||
for (n = 0; n < HASHSIZE; n++)
|
||||
for (p = hashtab[n]; p != nil; p = p->nxtptr)
|
||||
dump_one_def(p);
|
||||
}
|
||||
if ((p = lookup_macro_definition(argv[n])) != NULL)
|
||||
dump_one_def(argv[n], p);
|
||||
} else
|
||||
macro_for_all(dump_one_def);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -734,15 +703,10 @@ static int
|
||||
doincl(const char *ifile)
|
||||
{
|
||||
if (ilevel + 1 == MAXINP)
|
||||
errx(1, "%s at line %lu: too many include files.",
|
||||
CURRENT_NAME, CURRENT_LINE);
|
||||
m4errx(1, "too many include files.");
|
||||
if (fopen_trypath(infile+ilevel+1, ifile) != NULL) {
|
||||
ilevel++;
|
||||
if ((inname[ilevel] = strdup(ifile)) == NULL)
|
||||
err(1, NULL);
|
||||
inlineno[ilevel] = 1;
|
||||
bbase[ilevel] = bufbase = bp;
|
||||
emitline();
|
||||
return (1);
|
||||
} else
|
||||
return (0);
|
||||
@ -760,97 +724,74 @@ dopaste(const char *pfile)
|
||||
int c;
|
||||
|
||||
if ((pf = fopen(pfile, "r")) != NULL) {
|
||||
fprintf(active, "#line 1 \"%s\"\n", pfile);
|
||||
if (synch_lines)
|
||||
fprintf(active, "#line 1 \"%s\"\n", pfile);
|
||||
while ((c = getc(pf)) != EOF)
|
||||
putc(c, active);
|
||||
(void) fclose(pf);
|
||||
emitline();
|
||||
emit_synchline();
|
||||
return (1);
|
||||
} else
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
gnu_dochq(const char *argv[], int ac)
|
||||
{
|
||||
/* In gnu-m4 mode, the only way to restore quotes is to have no
|
||||
* arguments at all. */
|
||||
if (ac == 2) {
|
||||
lquote[0] = LQUOTE, lquote[1] = EOS;
|
||||
rquote[0] = RQUOTE, rquote[1] = EOS;
|
||||
} else {
|
||||
strlcpy(lquote, argv[2], sizeof(lquote));
|
||||
if(ac > 3)
|
||||
strlcpy(rquote, argv[3], sizeof(rquote));
|
||||
else
|
||||
rquote[0] = EOS;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* dochq - change quote characters
|
||||
*/
|
||||
static void
|
||||
dochq(const char *argv[], int argc)
|
||||
dochq(const char *argv[], int ac)
|
||||
{
|
||||
if (argc > 2) {
|
||||
if (*argv[2])
|
||||
strlcpy(lquote, argv[2], sizeof(lquote));
|
||||
else {
|
||||
lquote[0] = LQUOTE;
|
||||
lquote[1] = EOS;
|
||||
}
|
||||
if (argc > 3) {
|
||||
if (*argv[3])
|
||||
strlcpy(rquote, argv[3], sizeof(rquote));
|
||||
} else
|
||||
strcpy(rquote, lquote);
|
||||
if (ac == 2) {
|
||||
lquote[0] = LQUOTE; lquote[1] = EOS;
|
||||
rquote[0] = RQUOTE; rquote[1] = EOS;
|
||||
} else {
|
||||
lquote[0] = LQUOTE, lquote[1] = EOS;
|
||||
rquote[0] = RQUOTE, rquote[1] = EOS;
|
||||
strlcpy(lquote, argv[2], sizeof(lquote));
|
||||
if (ac > 3) {
|
||||
strlcpy(rquote, argv[3], sizeof(rquote));
|
||||
} else {
|
||||
rquote[0] = ECOMMT; rquote[1] = EOS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gnu_dochc(const char *argv[], int ac)
|
||||
{
|
||||
/* In gnu-m4 mode, no arguments mean no comment
|
||||
* arguments at all. */
|
||||
if (ac == 2) {
|
||||
scommt[0] = EOS;
|
||||
ecommt[0] = EOS;
|
||||
} else {
|
||||
if (*argv[2])
|
||||
strlcpy(scommt, argv[2], sizeof(scommt));
|
||||
else
|
||||
scommt[0] = SCOMMT, scommt[1] = EOS;
|
||||
if(ac > 3 && *argv[3])
|
||||
strlcpy(ecommt, argv[3], sizeof(ecommt));
|
||||
else
|
||||
ecommt[0] = ECOMMT, ecommt[1] = EOS;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* dochc - change comment characters
|
||||
*/
|
||||
static void
|
||||
dochc(const char *argv[], int argc)
|
||||
{
|
||||
if (argc > 2) {
|
||||
if (*argv[2])
|
||||
strlcpy(scommt, argv[2], sizeof(scommt));
|
||||
if (argc > 3) {
|
||||
if (*argv[3])
|
||||
strlcpy(ecommt, argv[3], sizeof(ecommt));
|
||||
/* XXX Note that there is no difference between no argument and a single
|
||||
* empty argument.
|
||||
*/
|
||||
if (argc == 2) {
|
||||
scommt[0] = EOS;
|
||||
ecommt[0] = EOS;
|
||||
} else {
|
||||
strlcpy(scommt, argv[2], sizeof(scommt));
|
||||
if (argc == 3) {
|
||||
ecommt[0] = ECOMMT; ecommt[1] = EOS;
|
||||
} else {
|
||||
strlcpy(ecommt, argv[3], sizeof(ecommt));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* dom4wrap - expand text at EOF
|
||||
*/
|
||||
static void
|
||||
dom4wrap(const char *text)
|
||||
{
|
||||
if (wrapindex >= maxwraps) {
|
||||
if (maxwraps == 0)
|
||||
maxwraps = 16;
|
||||
else
|
||||
ecommt[0] = ECOMMT, ecommt[1] = EOS;
|
||||
}
|
||||
else {
|
||||
scommt[0] = SCOMMT, scommt[1] = EOS;
|
||||
ecommt[0] = ECOMMT, ecommt[1] = EOS;
|
||||
maxwraps *= 2;
|
||||
m4wraps = xrealloc(m4wraps, maxwraps * sizeof(*m4wraps),
|
||||
"too many m4wraps");
|
||||
}
|
||||
m4wraps[wrapindex++] = xstrdup(text);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -867,14 +808,14 @@ dodiv(int n)
|
||||
resizedivs(n + 10);
|
||||
else
|
||||
n = 0; /* bitbucket */
|
||||
}
|
||||
}
|
||||
|
||||
if (n < 0)
|
||||
n = 0; /* bitbucket */
|
||||
if (outfile[n] == NULL) {
|
||||
char fname[] = _PATH_DIVNAME;
|
||||
|
||||
if ((fd = mkstemp(fname)) < 0 ||
|
||||
if ((fd = mkstemp(fname)) < 0 ||
|
||||
(outfile[n] = fdopen(fd, "w+")) == NULL)
|
||||
err(1, "%s: cannot divert", fname);
|
||||
if (unlink(fname) == -1)
|
||||
@ -895,10 +836,15 @@ doundiv(const char *argv[], int argc)
|
||||
|
||||
if (argc > 2) {
|
||||
for (ind = 2; ind < argc; ind++) {
|
||||
n = atoi(argv[ind]);
|
||||
if (n > 0 && n < maxout && outfile[n] != NULL)
|
||||
getdiv(n);
|
||||
|
||||
const char *errstr;
|
||||
n = strtonum(argv[ind], 1, INT_MAX, &errstr);
|
||||
if (errstr) {
|
||||
if (errno == EINVAL && mimic_gnu)
|
||||
getdivfile(argv[ind]);
|
||||
} else {
|
||||
if (n < maxout && outfile[n] != NULL)
|
||||
getdiv(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -931,7 +877,7 @@ dosub(const char *argv[], int argc)
|
||||
#endif
|
||||
if (fc >= ap && fc < ap + strlen(ap))
|
||||
for (k = fc + nc - 1; k >= fc; k--)
|
||||
putback(*k);
|
||||
pushback(*k);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -939,25 +885,11 @@ dosub(const char *argv[], int argc)
|
||||
* map every character of s1 that is specified in from
|
||||
* into s3 and replace in s. (source s1 remains untouched)
|
||||
*
|
||||
* This is a standard implementation of map(s,from,to) function of ICON
|
||||
* language. Within mapvec, we replace every character of "from" with
|
||||
* the corresponding character in "to". If "to" is shorter than "from",
|
||||
* than the corresponding entries are null, which means that those
|
||||
* characters dissapear altogether. Furthermore, imagine
|
||||
* map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
|
||||
* `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
|
||||
* ultimately maps to `*'. In order to achieve this effect in an efficient
|
||||
* manner (i.e. without multiple passes over the destination string), we
|
||||
* loop over mapvec, starting with the initial source character. if the
|
||||
* character value (dch) in this location is different than the source
|
||||
* character (sch), sch becomes dch, once again to index into mapvec, until
|
||||
* the character value stabilizes (i.e. sch = dch, in other words
|
||||
* mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
|
||||
* character, it will stabilize, since mapvec[0] == 0 at all times. At the
|
||||
* end, we restore mapvec* back to normal where mapvec[n] == n for
|
||||
* 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
|
||||
* about 5 times faster than any algorithm that makes multiple passes over
|
||||
* destination string.
|
||||
* This is derived from the a standard implementation of map(s,from,to)
|
||||
* function of ICON language. Within mapvec, we replace every character
|
||||
* of "from" with the corresponding character in "to".
|
||||
* If "to" is shorter than "from", than the corresponding entries are null,
|
||||
* which means that those characters dissapear altogether.
|
||||
*/
|
||||
static void
|
||||
map(char *dest, const char *src, const char *from, const char *to)
|
||||
@ -966,6 +898,8 @@ map(char *dest, const char *src, const char *from, const char *to)
|
||||
unsigned char sch, dch;
|
||||
static char frombis[257];
|
||||
static char tobis[257];
|
||||
int i;
|
||||
char seen[256];
|
||||
static unsigned char mapvec[256] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
|
||||
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
|
||||
@ -1000,17 +934,21 @@ map(char *dest, const char *src, const char *from, const char *to)
|
||||
* create a mapping between "from" and
|
||||
* "to"
|
||||
*/
|
||||
while (*from)
|
||||
mapvec[(unsigned char)(*from++)] = (*to) ?
|
||||
(unsigned char)(*to++) : 0;
|
||||
for (i = 0; i < 256; i++)
|
||||
seen[i] = 0;
|
||||
while (*from) {
|
||||
if (!seen[(unsigned char)(*from)]) {
|
||||
mapvec[(unsigned char)(*from)] = (unsigned char)(*to);
|
||||
seen[(unsigned char)(*from)] = 1;
|
||||
}
|
||||
from++;
|
||||
if (*to)
|
||||
to++;
|
||||
}
|
||||
|
||||
while (*src) {
|
||||
sch = (unsigned char)(*src++);
|
||||
dch = mapvec[sch];
|
||||
while (dch != sch) {
|
||||
sch = dch;
|
||||
dch = mapvec[sch];
|
||||
}
|
||||
if ((*dest = (char)dch))
|
||||
dest++;
|
||||
}
|
||||
@ -1040,12 +978,23 @@ handledash(char *buffer, char *end, const char *src)
|
||||
while(*src) {
|
||||
if (src[1] == '-' && src[2]) {
|
||||
unsigned char i;
|
||||
for (i = (unsigned char)src[0];
|
||||
i <= (unsigned char)src[2]; i++) {
|
||||
*p++ = i;
|
||||
if (p == end) {
|
||||
*p = '\0';
|
||||
return buffer;
|
||||
if ((unsigned char)src[0] <= (unsigned char)src[2]) {
|
||||
for (i = (unsigned char)src[0];
|
||||
i <= (unsigned char)src[2]; i++) {
|
||||
*p++ = i;
|
||||
if (p == end) {
|
||||
*p = '\0';
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i = (unsigned char)src[0];
|
||||
i >= (unsigned char)src[2]; i--) {
|
||||
*p++ = i;
|
||||
if (p == end) {
|
||||
*p = '\0';
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
src += 3;
|
||||
|
@ -1,640 +1,47 @@
|
||||
/* $OpenBSD: expr.c,v 1.14 2002/04/26 16:15:16 espie Exp $ */
|
||||
/* $NetBSD: expr.c,v 1.7 1995/09/28 05:37:31 tls Exp $ */
|
||||
|
||||
/* $OpenBSD: expr.c,v 1.18 2010/09/07 19:58:09 marco Exp $ */
|
||||
/*
|
||||
* Copyright (c) 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* Copyright (c) 2004 Marc Espie <espie@cvs.openbsd.org>
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Ozan Yigit at York University.
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)expr.c 8.2 (Berkeley) 4/29/95";
|
||||
#else
|
||||
#if 0
|
||||
static char rcsid[] = "$OpenBSD: expr.c,v 1.14 2002/04/26 16:15:16 espie Exp $";
|
||||
#endif
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include "mdef.h"
|
||||
#include "extern.h"
|
||||
|
||||
/*
|
||||
* expression evaluator: performs a standard recursive
|
||||
* descent parse to evaluate any expression permissible
|
||||
* within the following grammar:
|
||||
*
|
||||
* expr : query EOS
|
||||
* query : lor
|
||||
* | lor "?" query ":" query
|
||||
* lor : land { "||" land }
|
||||
* land : bor { "&&" bor }
|
||||
* bor : xor { "|" xor }
|
||||
* xor : band { "^" eqrel }
|
||||
* band : eqrel { "&" eqrel }
|
||||
* eqrel : nerel { ("==" | "!=") nerel }
|
||||
* nerel : shift { ("<" | ">" | "<=" | ">=") shift }
|
||||
* shift : primary { ("<<" | ">>") primary }
|
||||
* primary : term { ("+" | "-") term }
|
||||
* term : exponent { ("*" | "/" | "%") exponent }
|
||||
* exponent: unary { "**" unary }
|
||||
* unary : factor
|
||||
* | ("+" | "-" | "~" | "!") unary
|
||||
* factor : constant
|
||||
* | "(" query ")"
|
||||
* constant: num
|
||||
* | "'" CHAR "'"
|
||||
* num : DIGIT
|
||||
* | DIGIT num
|
||||
*
|
||||
*
|
||||
* This expression evaluator is lifted from a public-domain
|
||||
* C Pre-Processor included with the DECUS C Compiler distribution.
|
||||
* It is hacked somewhat to be suitable for m4.
|
||||
*
|
||||
* Originally by: Mike Lutz
|
||||
* Bob Harper
|
||||
*/
|
||||
int32_t end_result;
|
||||
const char *copy_toeval;
|
||||
int yyerror(const char *msg);
|
||||
|
||||
#define EQL 0
|
||||
#define NEQ 1
|
||||
#define LSS 2
|
||||
#define LEQ 3
|
||||
#define GTR 4
|
||||
#define GEQ 5
|
||||
#define OCTAL 8
|
||||
#define DECIMAL 10
|
||||
#define HEX 16
|
||||
|
||||
static const char *nxtch; /* Parser scan pointer */
|
||||
static const char *where;
|
||||
|
||||
static int query(int mayeval);
|
||||
static int lor(int mayeval);
|
||||
static int land(int mayeval);
|
||||
static int bor(int mayeval);
|
||||
static int xor(int mayeval);
|
||||
static int band(int mayeval);
|
||||
static int eqrel(int mayeval);
|
||||
static int nerel(int mayeval);
|
||||
static int shift(int mayeval);
|
||||
static int primary(int mayeval);
|
||||
static int term(int mayeval);
|
||||
static int exponent(int mayeval);
|
||||
static int unary(int mayeval);
|
||||
static int factor(int mayeval);
|
||||
static int constant(int mayeval);
|
||||
static int num(int mayeval);
|
||||
static int skipws(void);
|
||||
static void experr(const char *);
|
||||
|
||||
/*
|
||||
* For longjmp
|
||||
*/
|
||||
#include <setjmp.h>
|
||||
static jmp_buf expjump;
|
||||
|
||||
/*
|
||||
* macros:
|
||||
* ungetch - Put back the last character examined.
|
||||
* getch - return the next character from expr string.
|
||||
*/
|
||||
#define ungetch() nxtch--
|
||||
#define getch() *nxtch++
|
||||
extern void yy_scan_string(const char *);
|
||||
extern int yyparse(void);
|
||||
|
||||
int
|
||||
expr(const char *expbuf)
|
||||
yyerror(const char *msg)
|
||||
{
|
||||
int rval;
|
||||
|
||||
nxtch = expbuf;
|
||||
where = expbuf;
|
||||
if (setjmp(expjump) != 0)
|
||||
return FALSE;
|
||||
|
||||
rval = query(1);
|
||||
if (skipws() == EOS)
|
||||
return rval;
|
||||
|
||||
printf("m4: ill-formed expression.\n");
|
||||
return FALSE;
|
||||
fprintf(stderr, "m4: %s in expr %s\n", msg, copy_toeval);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* query : lor | lor '?' query ':' query
|
||||
*/
|
||||
static int
|
||||
query(int mayeval)
|
||||
int
|
||||
expr(const char *toeval)
|
||||
{
|
||||
int result, true_val, false_val;
|
||||
|
||||
result = lor(mayeval);
|
||||
if (skipws() != '?') {
|
||||
ungetch();
|
||||
return result;
|
||||
}
|
||||
|
||||
true_val = query(result);
|
||||
if (skipws() != ':')
|
||||
experr("bad query: missing \":\"");
|
||||
|
||||
false_val = query(!result);
|
||||
return result ? true_val : false_val;
|
||||
}
|
||||
|
||||
/*
|
||||
* lor : land { '||' land }
|
||||
*/
|
||||
static int
|
||||
lor(int mayeval)
|
||||
{
|
||||
int c, vl, vr;
|
||||
|
||||
vl = land(mayeval);
|
||||
while ((c = skipws()) == '|') {
|
||||
if (getch() != '|') {
|
||||
ungetch();
|
||||
break;
|
||||
}
|
||||
if (vl != 0)
|
||||
mayeval = 0;
|
||||
vr = land(mayeval);
|
||||
vl = vl || vr;
|
||||
}
|
||||
|
||||
ungetch();
|
||||
return vl;
|
||||
}
|
||||
|
||||
/*
|
||||
* land : not { '&&' not }
|
||||
*/
|
||||
static int
|
||||
land(int mayeval)
|
||||
{
|
||||
int c, vl, vr;
|
||||
|
||||
vl = bor(mayeval);
|
||||
while ((c = skipws()) == '&') {
|
||||
if (getch() != '&') {
|
||||
ungetch();
|
||||
break;
|
||||
}
|
||||
if (vl == 0)
|
||||
mayeval = 0;
|
||||
vr = bor(mayeval);
|
||||
vl = vl && vr;
|
||||
}
|
||||
|
||||
ungetch();
|
||||
return vl;
|
||||
}
|
||||
|
||||
/*
|
||||
* bor : xor { "|" xor }
|
||||
*/
|
||||
static int
|
||||
bor(int mayeval)
|
||||
{
|
||||
int vl, vr, c, cr;
|
||||
|
||||
vl = xor(mayeval);
|
||||
while ((c = skipws()) == '|') {
|
||||
cr = getch();
|
||||
ungetch();
|
||||
if (cr == '|')
|
||||
break;
|
||||
vr = xor(mayeval);
|
||||
vl |= vr;
|
||||
}
|
||||
ungetch();
|
||||
return (vl);
|
||||
}
|
||||
|
||||
/*
|
||||
* xor : band { "^" band }
|
||||
*/
|
||||
static int
|
||||
xor(int mayeval)
|
||||
{
|
||||
int vl, vr, c;
|
||||
|
||||
vl = band(mayeval);
|
||||
while ((c = skipws()) == '^') {
|
||||
vr = band(mayeval);
|
||||
vl ^= vr;
|
||||
}
|
||||
ungetch();
|
||||
return (vl);
|
||||
}
|
||||
|
||||
/*
|
||||
* band : eqrel { "&" eqrel }
|
||||
*/
|
||||
static int
|
||||
band(int mayeval)
|
||||
{
|
||||
int c, cr, vl, vr;
|
||||
|
||||
vl = eqrel(mayeval);
|
||||
while ((c = skipws()) == '&') {
|
||||
cr = getch();
|
||||
ungetch();
|
||||
if (cr == '&')
|
||||
break;
|
||||
vr = eqrel(mayeval);
|
||||
vl &= vr;
|
||||
}
|
||||
ungetch();
|
||||
return vl;
|
||||
}
|
||||
|
||||
/*
|
||||
* eqrel : nerel { ("==" | "!=" ) nerel }
|
||||
*/
|
||||
static int
|
||||
eqrel(int mayeval)
|
||||
{
|
||||
int vl, vr, c, cr;
|
||||
|
||||
vl = nerel(mayeval);
|
||||
while ((c = skipws()) == '!' || c == '=') {
|
||||
if ((cr = getch()) != '=') {
|
||||
ungetch();
|
||||
break;
|
||||
}
|
||||
vr = nerel(mayeval);
|
||||
switch (c) {
|
||||
case '=':
|
||||
vl = (vl == vr);
|
||||
break;
|
||||
case '!':
|
||||
vl = (vl != vr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ungetch();
|
||||
return vl;
|
||||
}
|
||||
|
||||
/*
|
||||
* nerel : shift { ("<=" | ">=" | "<" | ">") shift }
|
||||
*/
|
||||
static int
|
||||
nerel(int mayeval)
|
||||
{
|
||||
int vl, vr, c, cr;
|
||||
|
||||
vl = shift(mayeval);
|
||||
while ((c = skipws()) == '<' || c == '>') {
|
||||
if ((cr = getch()) != '=') {
|
||||
ungetch();
|
||||
cr = '\0';
|
||||
}
|
||||
vr = shift(mayeval);
|
||||
switch (c) {
|
||||
case '<':
|
||||
vl = (cr == '\0') ? (vl < vr) : (vl <= vr);
|
||||
break;
|
||||
case '>':
|
||||
vl = (cr == '\0') ? (vl > vr) : (vl >= vr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ungetch();
|
||||
return vl;
|
||||
}
|
||||
|
||||
/*
|
||||
* shift : primary { ("<<" | ">>") primary }
|
||||
*/
|
||||
static int
|
||||
shift(int mayeval)
|
||||
{
|
||||
int vl, vr, c;
|
||||
|
||||
vl = primary(mayeval);
|
||||
while (((c = skipws()) == '<' || c == '>') && getch() == c) {
|
||||
vr = primary(mayeval);
|
||||
|
||||
if (c == '<')
|
||||
vl <<= vr;
|
||||
else
|
||||
vl >>= vr;
|
||||
}
|
||||
|
||||
if (c == '<' || c == '>')
|
||||
ungetch();
|
||||
ungetch();
|
||||
return vl;
|
||||
}
|
||||
|
||||
/*
|
||||
* primary : term { ("+" | "-") term }
|
||||
*/
|
||||
static int
|
||||
primary(int mayeval)
|
||||
{
|
||||
int c, vl, vr;
|
||||
|
||||
vl = term(mayeval);
|
||||
while ((c = skipws()) == '+' || c == '-') {
|
||||
vr = term(mayeval);
|
||||
|
||||
if (c == '+')
|
||||
vl += vr;
|
||||
else
|
||||
vl -= vr;
|
||||
}
|
||||
|
||||
ungetch();
|
||||
return vl;
|
||||
}
|
||||
|
||||
/*
|
||||
* term : exponent { ("*" | "/" | "%") exponent }
|
||||
*/
|
||||
static int
|
||||
term(int mayeval)
|
||||
{
|
||||
int c, vl, vr;
|
||||
|
||||
vl = exponent(mayeval);
|
||||
while ((c = skipws()) == '*' || c == '/' || c == '%') {
|
||||
vr = exponent(mayeval);
|
||||
|
||||
switch (c) {
|
||||
case '*':
|
||||
vl *= vr;
|
||||
break;
|
||||
case '/':
|
||||
if (!mayeval)
|
||||
/* short-circuit */;
|
||||
else if (vr == 0)
|
||||
errx(1, "division by zero in eval.");
|
||||
else
|
||||
vl /= vr;
|
||||
break;
|
||||
case '%':
|
||||
if (!mayeval)
|
||||
/* short-circuit */;
|
||||
else if (vr == 0)
|
||||
errx(1, "modulo zero in eval.");
|
||||
else
|
||||
vl %= vr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ungetch();
|
||||
return vl;
|
||||
}
|
||||
|
||||
/*
|
||||
* exponent : unary { "**" exponent }
|
||||
*/
|
||||
static int
|
||||
exponent(int mayeval)
|
||||
{
|
||||
int c, vl, vr, n;
|
||||
|
||||
vl = unary(mayeval);
|
||||
while ((c = skipws()) == '*') {
|
||||
if (getch() != '*') {
|
||||
ungetch();
|
||||
break;
|
||||
}
|
||||
vr = unary(mayeval);
|
||||
n = 1;
|
||||
while (vr-- > 0)
|
||||
n *= vl;
|
||||
return n;
|
||||
}
|
||||
|
||||
ungetch();
|
||||
return vl;
|
||||
}
|
||||
|
||||
/*
|
||||
* unary : factor | ("+" | "-" | "~" | "!") unary
|
||||
*/
|
||||
static int
|
||||
unary(int mayeval)
|
||||
{
|
||||
int val, c;
|
||||
|
||||
if ((c = skipws()) == '+' || c == '-' || c == '~' || c == '!') {
|
||||
val = unary(mayeval);
|
||||
|
||||
switch (c) {
|
||||
case '+':
|
||||
return val;
|
||||
case '-':
|
||||
return -val;
|
||||
case '~':
|
||||
return ~val;
|
||||
case '!':
|
||||
return !val;
|
||||
}
|
||||
}
|
||||
|
||||
ungetch();
|
||||
return factor(mayeval);
|
||||
}
|
||||
|
||||
/*
|
||||
* factor : constant | '(' query ')'
|
||||
*/
|
||||
static int
|
||||
factor(int mayeval)
|
||||
{
|
||||
int val;
|
||||
|
||||
if (skipws() == '(') {
|
||||
val = query(mayeval);
|
||||
if (skipws() != ')')
|
||||
experr("bad factor: missing \")\"");
|
||||
return val;
|
||||
}
|
||||
|
||||
ungetch();
|
||||
return constant(mayeval);
|
||||
}
|
||||
|
||||
/*
|
||||
* constant: num | 'char'
|
||||
* Note: constant() handles multi-byte constants
|
||||
*/
|
||||
static int
|
||||
constant(int mayeval)
|
||||
{
|
||||
int i;
|
||||
int value;
|
||||
int c;
|
||||
int v[sizeof(int)];
|
||||
|
||||
if (skipws() != '\'') {
|
||||
ungetch();
|
||||
return num(mayeval);
|
||||
}
|
||||
for (i = 0; i < (ssize_t)sizeof(int); i++) {
|
||||
if ((c = getch()) == '\'') {
|
||||
ungetch();
|
||||
break;
|
||||
}
|
||||
if (c == '\\') {
|
||||
switch (c = getch()) {
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
ungetch();
|
||||
c = num(mayeval);
|
||||
break;
|
||||
case 'n':
|
||||
c = 012;
|
||||
break;
|
||||
case 'r':
|
||||
c = 015;
|
||||
break;
|
||||
case 't':
|
||||
c = 011;
|
||||
break;
|
||||
case 'b':
|
||||
c = 010;
|
||||
break;
|
||||
case 'f':
|
||||
c = 014;
|
||||
break;
|
||||
}
|
||||
}
|
||||
v[i] = c;
|
||||
}
|
||||
if (i == 0 || getch() != '\'')
|
||||
experr("illegal character constant");
|
||||
for (value = 0; --i >= 0;) {
|
||||
value <<= 8;
|
||||
value += v[i];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* num : digit | num digit
|
||||
*/
|
||||
static int
|
||||
num(int mayeval __unused)
|
||||
{
|
||||
int rval, c, base;
|
||||
int ndig;
|
||||
|
||||
rval = 0;
|
||||
ndig = 0;
|
||||
c = skipws();
|
||||
if (c == '0') {
|
||||
c = skipws();
|
||||
if (c == 'x' || c == 'X') {
|
||||
base = HEX;
|
||||
c = skipws();
|
||||
} else {
|
||||
base = OCTAL;
|
||||
ndig++;
|
||||
}
|
||||
} else
|
||||
base = DECIMAL;
|
||||
for(;;) {
|
||||
switch(c) {
|
||||
case '8': case '9':
|
||||
if (base == OCTAL)
|
||||
goto bad_digit;
|
||||
/*FALLTHRU*/
|
||||
case '0': case '1': case '2': case '3':
|
||||
case '4': case '5': case '6': case '7':
|
||||
rval *= base;
|
||||
rval += c - '0';
|
||||
break;
|
||||
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
|
||||
c = tolower(c);
|
||||
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
|
||||
if (base == HEX) {
|
||||
rval *= base;
|
||||
rval += c - 'a' + 10;
|
||||
break;
|
||||
}
|
||||
/*FALLTHRU*/
|
||||
default:
|
||||
goto bad_digit;
|
||||
}
|
||||
c = getch();
|
||||
ndig++;
|
||||
}
|
||||
bad_digit:
|
||||
ungetch();
|
||||
|
||||
if (ndig == 0)
|
||||
experr("bad constant");
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip over any white space and return terminating char.
|
||||
*/
|
||||
static int
|
||||
skipws(void)
|
||||
{
|
||||
int c;
|
||||
|
||||
while ((c = getch()) <= ' ' && c > EOS)
|
||||
;
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
* resets environment to eval(), prints an error
|
||||
* and forces eval to return FALSE.
|
||||
*/
|
||||
static void
|
||||
experr(const char *msg)
|
||||
{
|
||||
printf("m4: %s in expr %s.\n", msg, where);
|
||||
longjmp(expjump, -1);
|
||||
copy_toeval = toeval;
|
||||
yy_scan_string(toeval);
|
||||
yyparse();
|
||||
return end_result;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: extern.h,v 1.29 2002/02/16 21:27:48 millert Exp $ */
|
||||
/* $OpenBSD: extern.h,v 1.51 2011/09/27 07:24:02 espie Exp $ */
|
||||
/* $NetBSD: extern.h,v 1.3 1996/01/13 23:25:24 pk Exp $ */
|
||||
|
||||
/*-
|
||||
@ -16,7 +16,7 @@
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
@ -37,7 +37,7 @@
|
||||
*/
|
||||
|
||||
/* eval.c */
|
||||
extern void eval(const char *[], int, int);
|
||||
extern void eval(const char *[], int, int, int);
|
||||
extern void dodefine(const char *, const char *);
|
||||
extern unsigned long expansion_id;
|
||||
|
||||
@ -45,7 +45,7 @@ extern unsigned long expansion_id;
|
||||
extern int expr(const char *);
|
||||
|
||||
/* gnum4.c */
|
||||
extern void addtoincludepath(const char *);
|
||||
extern void addtoincludepath(const char *);
|
||||
extern struct input_file *fopen_trypath(struct input_file *, const char *);
|
||||
extern void doindir(const char *[], int);
|
||||
extern void dobuiltin(const char *[], int);
|
||||
@ -56,45 +56,67 @@ extern void doprintlineno(struct input_file *);
|
||||
extern void doprintfilename(struct input_file *);
|
||||
|
||||
extern void doesyscmd(const char *);
|
||||
|
||||
extern void getdivfile(const char *);
|
||||
extern void doformat(const char *[], int);
|
||||
|
||||
/* look.c */
|
||||
extern ndptr addent(const char *);
|
||||
extern unsigned hash(const char *);
|
||||
|
||||
#define FLAG_UNTRACED 0
|
||||
#define FLAG_TRACED 1
|
||||
#define FLAG_NO_TRACE 2
|
||||
|
||||
extern void init_macros(void);
|
||||
extern ndptr lookup(const char *);
|
||||
extern void remhash(const char *, int);
|
||||
extern void mark_traced(const char *, int);
|
||||
extern struct ohash macros;
|
||||
|
||||
extern struct macro_definition *lookup_macro_definition(const char *);
|
||||
extern void macro_define(const char *, const char *);
|
||||
extern void macro_pushdef(const char *, const char *);
|
||||
extern void macro_popdef(const char *);
|
||||
extern void macro_undefine(const char *);
|
||||
extern void setup_builtin(const char *, unsigned int);
|
||||
extern void macro_for_all(void (*)(const char *, struct macro_definition *));
|
||||
#define macro_getdef(p) ((p)->d)
|
||||
#define macro_name(p) ((p)->name)
|
||||
#define macro_builtin_type(p) ((p)->builtin_type)
|
||||
#define is_traced(p) ((p)->trace_flags == FLAG_NO_TRACE ? (trace_flags & TRACE_ALL) : (p)->trace_flags)
|
||||
|
||||
extern ndptr macro_getbuiltin(const char *);
|
||||
|
||||
/* main.c */
|
||||
extern void outputstr(const char *);
|
||||
extern int builtin_type(const char *);
|
||||
extern const char *builtin_realname(int);
|
||||
extern void emitline(void);
|
||||
extern void do_emit_synchline(void);
|
||||
#define emit_synchline() do { if (synch_lines) do_emit_synchline(); } while(0)
|
||||
|
||||
/* misc.c */
|
||||
extern void chrsave(int);
|
||||
extern char *compute_prevep(void);
|
||||
extern char *compute_prevep(void);
|
||||
extern void getdiv(int);
|
||||
extern ptrdiff_t indx(const char *, const char *);
|
||||
extern void initspaces(void);
|
||||
extern void initspaces(void);
|
||||
extern void killdiv(void);
|
||||
extern void onintr(int);
|
||||
extern void pbnum(int);
|
||||
extern void pbnumbase(int, int, int);
|
||||
extern void pbunsigned(unsigned long);
|
||||
extern void pbstr(const char *);
|
||||
extern void putback(int);
|
||||
extern void *xalloc(size_t);
|
||||
extern void pushback(int);
|
||||
extern void *xalloc(size_t, const char *fmt, ...);
|
||||
extern void *xrealloc(void *, size_t, const char *fmt, ...);
|
||||
extern char *xstrdup(const char *);
|
||||
extern void usage(void);
|
||||
extern void resizedivs(int);
|
||||
extern size_t buffer_mark(void);
|
||||
extern void dump_buffer(FILE *, size_t);
|
||||
extern void m4errx(int, const char *, ...);
|
||||
|
||||
extern int obtain_char(struct input_file *);
|
||||
extern int obtain_char(struct input_file *);
|
||||
extern void set_input(struct input_file *, FILE *, const char *);
|
||||
extern void release_input(struct input_file *);
|
||||
|
||||
/* speeded-up versions of chrsave/putback */
|
||||
#define PUTBACK(c) \
|
||||
/* speeded-up versions of chrsave/pushback */
|
||||
#define PUSHBACK(c) \
|
||||
do { \
|
||||
if (bp >= endpbb) \
|
||||
enlarge_bufspace(); \
|
||||
@ -111,60 +133,44 @@ extern void release_input(struct input_file *);
|
||||
/* and corresponding exposure for local symbols */
|
||||
extern void enlarge_bufspace(void);
|
||||
extern void enlarge_strspace(void);
|
||||
extern char *endpbb;
|
||||
extern unsigned char *endpbb;
|
||||
extern char *endest;
|
||||
|
||||
/* trace.c */
|
||||
extern void mark_traced(const char *, int);
|
||||
extern int is_traced(const char *);
|
||||
extern unsigned int trace_flags;
|
||||
#define TRACE_ALL 512
|
||||
extern void trace_file(const char *);
|
||||
extern ssize_t trace(const char **, int, struct input_file *);
|
||||
extern size_t trace(const char **, int, struct input_file *);
|
||||
extern void finish_trace(size_t);
|
||||
extern int traced_macros;
|
||||
extern void set_trace_flags(const char *);
|
||||
extern FILE *traceout;
|
||||
|
||||
extern ndptr hashtab[]; /* hash table for macros etc. */
|
||||
extern stae *mstack; /* stack of m4 machine */
|
||||
extern char *sstack; /* shadow stack, for string space extension */
|
||||
extern FILE *active; /* active output file pointer */
|
||||
extern struct input_file infile[];/* input file stack (0=stdin) */
|
||||
extern char *inname[]; /* names of these input files */
|
||||
extern int inlineno[]; /* current number in each input file */
|
||||
extern FILE **outfile; /* diversion array(0=bitbucket) */
|
||||
extern int maxout; /* maximum number of diversions */
|
||||
extern int fp; /* m4 call frame pointer */
|
||||
extern int fp; /* m4 call frame pointer */
|
||||
extern int ilevel; /* input file stack pointer */
|
||||
extern int oindex; /* diversion index. */
|
||||
extern int sp; /* current m4 stack pointer */
|
||||
extern char *bp; /* first available character */
|
||||
extern char *buf; /* push-back buffer */
|
||||
extern char *bufbase; /* buffer base for this ilevel */
|
||||
extern char *bbase[]; /* buffer base per ilevel */
|
||||
extern unsigned char *bp; /* first available character */
|
||||
extern unsigned char *buf; /* push-back buffer */
|
||||
extern unsigned char *bufbase; /* buffer base for this ilevel */
|
||||
extern unsigned char *bbase[]; /* buffer base per ilevel */
|
||||
extern char ecommt[MAXCCHARS+1];/* end character for comment */
|
||||
extern char *ep; /* first free char in strspace */
|
||||
extern char lquote[MAXCCHARS+1];/* left quote character (`) */
|
||||
extern const char *m4wraps; /* m4wrap string default. */
|
||||
extern char null[]; /* as it says.. just a null. */
|
||||
extern char **m4wraps; /* m4wrap string default. */
|
||||
extern int maxwraps; /* size of m4wraps array */
|
||||
extern int wrapindex; /* current index in m4wraps */
|
||||
|
||||
extern const char *null; /* as it says.. just a null. */
|
||||
extern char rquote[MAXCCHARS+1];/* right quote character (') */
|
||||
extern char scommt[MAXCCHARS+1];/* start character for comment */
|
||||
extern int synccpp; /* Line synchronisation for C preprocessor */
|
||||
extern int synch_lines; /* line synchronisation directives */
|
||||
|
||||
extern int mimic_gnu; /* behaves like gnu-m4 */
|
||||
extern int prefix_builtins; /* prefix builtin macros with m4_ */
|
||||
|
||||
/* get a possibly pushed-back-character, increment lineno if need be */
|
||||
static __inline int gpbc(void)
|
||||
{
|
||||
int chscratch; /* Scratch space. */
|
||||
|
||||
if (bp > bufbase) {
|
||||
if (*--bp)
|
||||
return ((unsigned char)*bp);
|
||||
else
|
||||
return (EOF);
|
||||
}
|
||||
chscratch = obtain_char(infile+ilevel);
|
||||
if (chscratch == '\n')
|
||||
++inlineno[ilevel];
|
||||
return (chscratch);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: gnum4.c,v 1.18 2002/04/26 16:15:16 espie Exp $ */
|
||||
/* $OpenBSD: gnum4.c,v 1.42 2011/11/06 12:25:43 espie Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1999 Marc Espie
|
||||
@ -24,7 +24,6 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
@ -36,13 +35,13 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <paths.h>
|
||||
#include <regex.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include "mdef.h"
|
||||
@ -60,7 +59,7 @@ int mimic_gnu = 0;
|
||||
* Then M4PATH env variable
|
||||
*/
|
||||
|
||||
static struct path_entry {
|
||||
struct path_entry {
|
||||
char *name;
|
||||
struct path_entry *next;
|
||||
} *first, *last;
|
||||
@ -133,7 +132,7 @@ dopath(struct input_file *i, const char *filename)
|
||||
|
||||
for (pe = first; pe; pe = pe->next) {
|
||||
snprintf(path, sizeof(path), "%s/%s", pe->name, filename);
|
||||
if ((f = fopen(path, "r")) != NULL) {
|
||||
if ((f = fopen(path, "r")) != 0) {
|
||||
set_input(i, f, path);
|
||||
return i;
|
||||
}
|
||||
@ -162,25 +161,28 @@ fopen_trypath(struct input_file *i, const char *filename)
|
||||
void
|
||||
doindir(const char *argv[], int argc)
|
||||
{
|
||||
ndptr p;
|
||||
ndptr n;
|
||||
struct macro_definition *p = NULL;
|
||||
|
||||
p = lookup(argv[2]);
|
||||
if (p == NULL)
|
||||
errx(1, "undefined macro %s", argv[2]);
|
||||
n = lookup(argv[2]);
|
||||
if (n == NULL || (p = macro_getdef(n)) == NULL)
|
||||
m4errx(1, "indir: undefined macro %s.", argv[2]);
|
||||
argv[1] = p->defn;
|
||||
eval(argv+1, argc-1, p->type);
|
||||
|
||||
eval(argv+1, argc-1, p->type, is_traced(n));
|
||||
}
|
||||
|
||||
void
|
||||
dobuiltin(const char *argv[], int argc)
|
||||
{
|
||||
int n;
|
||||
ndptr p;
|
||||
|
||||
argv[1] = NULL;
|
||||
n = builtin_type(argv[2]);
|
||||
if (n != -1)
|
||||
eval(argv+1, argc-1, n);
|
||||
p = macro_getbuiltin(argv[2]);
|
||||
if (p != NULL)
|
||||
eval(argv+1, argc-1, macro_builtin_type(p), is_traced(p));
|
||||
else
|
||||
errx(1, "unknown builtin %s", argv[2]);
|
||||
m4errx(1, "unknown builtin %s.", argv[2]);
|
||||
}
|
||||
|
||||
|
||||
@ -198,7 +200,7 @@ static void exit_regerror(int, regex_t *);
|
||||
static void do_subst(const char *, regex_t *, const char *, regmatch_t *);
|
||||
static void do_regexpindex(const char *, regex_t *, regmatch_t *);
|
||||
static void do_regexp(const char *, regex_t *, const char *, regmatch_t *);
|
||||
static void add_sub(size_t, const char *, regex_t *, regmatch_t *);
|
||||
static void add_sub(int, const char *, regex_t *, regmatch_t *);
|
||||
static void add_replace(const char *, regex_t *, const char *, regmatch_t *);
|
||||
#define addconstantstring(s) addchars((s), sizeof(s)-1)
|
||||
|
||||
@ -212,9 +214,7 @@ addchars(const char *c, size_t n)
|
||||
bufsize = 1024;
|
||||
else
|
||||
bufsize *= 2;
|
||||
buffer = realloc(buffer, bufsize);
|
||||
if (buffer == NULL)
|
||||
errx(1, "out of memory");
|
||||
buffer = xrealloc(buffer, bufsize, NULL);
|
||||
}
|
||||
memcpy(buffer+current, c, n);
|
||||
current += n;
|
||||
@ -228,9 +228,7 @@ addchar(int c)
|
||||
bufsize = 1024;
|
||||
else
|
||||
bufsize *= 2;
|
||||
buffer = realloc(buffer, bufsize);
|
||||
if (buffer == NULL)
|
||||
errx(1, "out of memory");
|
||||
buffer = xrealloc(buffer, bufsize, NULL);
|
||||
}
|
||||
buffer[current++] = c;
|
||||
}
|
||||
@ -247,20 +245,21 @@ getstring(void)
|
||||
static void
|
||||
exit_regerror(int er, regex_t *re)
|
||||
{
|
||||
size_t errlen;
|
||||
char *errbuf;
|
||||
size_t errlen;
|
||||
char *errbuf;
|
||||
|
||||
errlen = regerror(er, re, NULL, 0);
|
||||
errbuf = xalloc(errlen);
|
||||
errbuf = xalloc(errlen,
|
||||
"malloc in regerror: %lu", (unsigned long)errlen);
|
||||
regerror(er, re, errbuf, errlen);
|
||||
errx(1, "regular expression error: %s", errbuf);
|
||||
m4errx(1, "regular expression error: %s.", errbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
add_sub(size_t n, const char *string, regex_t *re, regmatch_t *pm)
|
||||
add_sub(int n, const char *string, regex_t *re, regmatch_t *pm)
|
||||
{
|
||||
if (n > re->re_nsub)
|
||||
warnx("No subexpression %zu", n);
|
||||
if (n > (int)re->re_nsub)
|
||||
warnx("No subexpression %d", n);
|
||||
/* Subexpressions that did not match are
|
||||
* not an error. */
|
||||
else if (pm[n].rm_so != -1 &&
|
||||
@ -302,7 +301,7 @@ add_replace(const char *string, regex_t *re, const char *replace, regmatch_t *pm
|
||||
continue;
|
||||
}
|
||||
}
|
||||
addchar(*p);
|
||||
addchar(*p);
|
||||
}
|
||||
}
|
||||
|
||||
@ -386,6 +385,14 @@ do_regexpindex(const char *string, regex_t *re, regmatch_t *pm)
|
||||
static char *
|
||||
twiddle(const char *p)
|
||||
{
|
||||
/* + at start of regexp is a normal character for Gnu m4 */
|
||||
if (*p == '^') {
|
||||
addchar(*p);
|
||||
p++;
|
||||
}
|
||||
if (*p == '+') {
|
||||
addchar('\\');
|
||||
}
|
||||
/* This could use strcspn for speed... */
|
||||
while (*p != '\0') {
|
||||
if (*p == '\\') {
|
||||
@ -431,25 +438,46 @@ twiddle(const char *p)
|
||||
void
|
||||
dopatsubst(const char *argv[], int argc)
|
||||
{
|
||||
int error;
|
||||
regex_t re;
|
||||
regmatch_t *pmatch;
|
||||
|
||||
if (argc <= 3) {
|
||||
warnx("Too few arguments to patsubst");
|
||||
return;
|
||||
}
|
||||
error = regcomp(&re, mimic_gnu ? twiddle(argv[3]) : argv[3],
|
||||
REG_NEWLINE | REG_EXTENDED);
|
||||
if (error != 0)
|
||||
exit_regerror(error, &re);
|
||||
/* special case: empty regexp */
|
||||
if (argv[3][0] == '\0') {
|
||||
const char *s;
|
||||
size_t len;
|
||||
if (argc > 4 && argv[4])
|
||||
len = strlen(argv[4]);
|
||||
else
|
||||
len = 0;
|
||||
for (s = argv[2]; *s != '\0'; s++) {
|
||||
addchars(argv[4], len);
|
||||
addchar(*s);
|
||||
}
|
||||
} else {
|
||||
int error;
|
||||
regex_t re;
|
||||
regmatch_t *pmatch;
|
||||
int mode = REG_EXTENDED;
|
||||
size_t l = strlen(argv[3]);
|
||||
|
||||
pmatch = xalloc(sizeof(regmatch_t) * (re.re_nsub+1));
|
||||
do_subst(argv[2], &re,
|
||||
argc != 4 && argv[4] != NULL ? argv[4] : "", pmatch);
|
||||
if (!mimic_gnu ||
|
||||
(argv[3][0] == '^') ||
|
||||
(l > 0 && argv[3][l-1] == '$'))
|
||||
mode |= REG_NEWLINE;
|
||||
|
||||
error = regcomp(&re, mimic_gnu ? twiddle(argv[3]) : argv[3],
|
||||
mode);
|
||||
if (error != 0)
|
||||
exit_regerror(error, &re);
|
||||
|
||||
pmatch = xalloc(sizeof(regmatch_t) * (re.re_nsub+1), NULL);
|
||||
do_subst(argv[2], &re,
|
||||
argc > 4 && argv[4] != NULL ? argv[4] : "", pmatch);
|
||||
free(pmatch);
|
||||
regfree(&re);
|
||||
}
|
||||
pbstr(getstring());
|
||||
free(pmatch);
|
||||
regfree(&re);
|
||||
}
|
||||
|
||||
void
|
||||
@ -463,13 +491,20 @@ doregexp(const char *argv[], int argc)
|
||||
warnx("Too few arguments to regexp");
|
||||
return;
|
||||
}
|
||||
/* special gnu case */
|
||||
if (argv[3][0] == '\0' && mimic_gnu) {
|
||||
if (argc == 4 || argv[4] == NULL)
|
||||
return;
|
||||
else
|
||||
pbstr(argv[4]);
|
||||
}
|
||||
error = regcomp(&re, mimic_gnu ? twiddle(argv[3]) : argv[3],
|
||||
REG_EXTENDED);
|
||||
REG_EXTENDED|REG_NEWLINE);
|
||||
if (error != 0)
|
||||
exit_regerror(error, &re);
|
||||
|
||||
pmatch = xalloc(sizeof(regmatch_t) * (re.re_nsub+1));
|
||||
if (argv[4] == NULL || argc == 4)
|
||||
pmatch = xalloc(sizeof(regmatch_t) * (re.re_nsub+1), NULL);
|
||||
if (argc == 4 || argv[4] == NULL)
|
||||
do_regexpindex(argv[2], &re, pmatch);
|
||||
else
|
||||
do_regexp(argv[2], &re, argv[4], pmatch);
|
||||
@ -477,17 +512,112 @@ doregexp(const char *argv[], int argc)
|
||||
regfree(&re);
|
||||
}
|
||||
|
||||
void
|
||||
doformat(const char *argv[], int argc)
|
||||
{
|
||||
const char *format = argv[2];
|
||||
int pos = 3;
|
||||
int left_padded;
|
||||
long width;
|
||||
size_t l;
|
||||
const char *thisarg = NULL;
|
||||
char temp[2];
|
||||
long extra;
|
||||
|
||||
while (*format != 0) {
|
||||
if (*format != '%') {
|
||||
addchar(*format++);
|
||||
continue;
|
||||
}
|
||||
|
||||
format++;
|
||||
if (*format == '%') {
|
||||
addchar(*format++);
|
||||
continue;
|
||||
}
|
||||
if (*format == 0) {
|
||||
addchar('%');
|
||||
break;
|
||||
}
|
||||
|
||||
if (*format == '*') {
|
||||
format++;
|
||||
if (pos >= argc)
|
||||
m4errx(1,
|
||||
"Format with too many format specifiers.");
|
||||
width = strtol(argv[pos++], NULL, 10);
|
||||
} else {
|
||||
width = strtol(format, __DECONST(char **,&format), 10);
|
||||
}
|
||||
if (width < 0) {
|
||||
left_padded = 1;
|
||||
width = -width;
|
||||
} else {
|
||||
left_padded = 0;
|
||||
}
|
||||
if (*format == '.') {
|
||||
format++;
|
||||
if (*format == '*') {
|
||||
format++;
|
||||
if (pos >= argc)
|
||||
m4errx(1,
|
||||
"Format with too many format specifiers.");
|
||||
extra = strtol(argv[pos++], NULL, 10);
|
||||
} else {
|
||||
extra = strtol(format, __DECONST(char **, &format), 10);
|
||||
}
|
||||
} else {
|
||||
extra = LONG_MAX;
|
||||
}
|
||||
if (pos >= argc)
|
||||
m4errx(1, "Format with too many format specifiers.");
|
||||
switch(*format) {
|
||||
case 's':
|
||||
thisarg = argv[pos++];
|
||||
break;
|
||||
case 'c':
|
||||
temp[0] = strtoul(argv[pos++], NULL, 10);
|
||||
temp[1] = 0;
|
||||
thisarg = temp;
|
||||
break;
|
||||
default:
|
||||
m4errx(1, "Unsupported format specification: %s.",
|
||||
argv[2]);
|
||||
}
|
||||
format++;
|
||||
l = strlen(thisarg);
|
||||
if ((long)l > extra)
|
||||
l = extra;
|
||||
if (!left_padded) {
|
||||
while ((long)l < width--)
|
||||
addchar(' ');
|
||||
}
|
||||
addchars(thisarg, l);
|
||||
if (left_padded) {
|
||||
while ((long)l < width--)
|
||||
addchar(' ');
|
||||
}
|
||||
}
|
||||
pbstr(getstring());
|
||||
}
|
||||
|
||||
void
|
||||
doesyscmd(const char *cmd)
|
||||
{
|
||||
int p[2];
|
||||
pid_t pid, cpid;
|
||||
char *argv[4];
|
||||
int cc;
|
||||
int status;
|
||||
|
||||
/* Follow gnu m4 documentation: first flush buffers. */
|
||||
fflush(NULL);
|
||||
|
||||
argv[0] = __DECONST(char *, "sh");
|
||||
argv[1] = __DECONST(char *, "-c");
|
||||
argv[2] = __DECONST(char *, cmd);
|
||||
argv[3] = NULL;
|
||||
|
||||
/* Just set up standard output, share stderr and stdin with m4 */
|
||||
if (pipe(p) == -1)
|
||||
err(1, "bad pipe");
|
||||
@ -499,7 +629,7 @@ doesyscmd(const char *cmd)
|
||||
(void) close(p[0]);
|
||||
(void) dup2(p[1], 1);
|
||||
(void) close(p[1]);
|
||||
execl(_PATH_BSHELL, "sh", "-c", cmd, (char *)NULL);
|
||||
execv(_PATH_BSHELL, argv);
|
||||
exit(1);
|
||||
default:
|
||||
/* Read result in two stages, since m4's buffer is
|
||||
@ -518,3 +648,18 @@ doesyscmd(const char *cmd)
|
||||
pbstr(getstring());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
getdivfile(const char *name)
|
||||
{
|
||||
FILE *f;
|
||||
int c;
|
||||
|
||||
f = fopen(name, "r");
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
while ((c = getc(f))!= EOF)
|
||||
putc(c, active);
|
||||
(void) fclose(f);
|
||||
}
|
||||
|
75
usr.bin/m4/lib/ohash.h
Normal file
75
usr.bin/m4/lib/ohash.h
Normal file
@ -0,0 +1,75 @@
|
||||
#ifndef OHASH_H
|
||||
#define OHASH_H
|
||||
/* $OpenBSD: ohash.h,v 1.8 2005/12/29 18:54:47 jaredy Exp $ */
|
||||
/* ex:ts=8 sw=4:
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/* Open hashing support.
|
||||
* Open hashing was chosen because it is much lighter than other hash
|
||||
* techniques, and more efficient in most cases.
|
||||
*/
|
||||
|
||||
struct ohash_info {
|
||||
ptrdiff_t key_offset;
|
||||
void *data; /* user data */
|
||||
void *(*halloc)(size_t, void *);
|
||||
void (*hfree)(void *, size_t, void *);
|
||||
void *(*alloc)(size_t, void *);
|
||||
};
|
||||
|
||||
struct _ohash_record;
|
||||
|
||||
struct ohash {
|
||||
struct _ohash_record *t;
|
||||
struct ohash_info info;
|
||||
unsigned int size;
|
||||
unsigned int total;
|
||||
unsigned int deleted;
|
||||
};
|
||||
|
||||
/* For this to be tweakable, we use small primitives, and leave part of the
|
||||
* logic to the client application. e.g., hashing is left to the client
|
||||
* application. We also provide a simple table entry lookup that yields
|
||||
* a hashing table index (opaque) to be used in find/insert/remove.
|
||||
* The keys are stored at a known position in the client data.
|
||||
*/
|
||||
__BEGIN_DECLS
|
||||
void ohash_init(struct ohash *, unsigned, struct ohash_info *);
|
||||
void ohash_delete(struct ohash *);
|
||||
|
||||
unsigned int ohash_lookup_interval(struct ohash *, const char *,
|
||||
const char *, u_int32_t);
|
||||
unsigned int ohash_lookup_memory(struct ohash *, const char *,
|
||||
size_t, u_int32_t);
|
||||
void *ohash_find(struct ohash *, unsigned int);
|
||||
void *ohash_remove(struct ohash *, unsigned int);
|
||||
void *ohash_insert(struct ohash *, unsigned int, void *);
|
||||
void *ohash_first(struct ohash *, unsigned int *);
|
||||
void *ohash_next(struct ohash *, unsigned int *);
|
||||
unsigned int ohash_entries(struct ohash *);
|
||||
|
||||
void *ohash_create_entry(struct ohash_info *, const char *, const char **);
|
||||
u_int32_t ohash_interval(const char *, const char **);
|
||||
|
||||
unsigned int ohash_qlookupi(struct ohash *, const char *, const char **);
|
||||
unsigned int ohash_qlookup(struct ohash *, const char *);
|
||||
__END_DECLS
|
||||
#endif
|
||||
|
40
usr.bin/m4/lib/ohash_create_entry.c
Normal file
40
usr.bin/m4/lib/ohash_create_entry.c
Normal file
@ -0,0 +1,40 @@
|
||||
/* $OpenBSD: ohash_create_entry.c,v 1.2 2004/06/22 20:00:16 espie Exp $ */
|
||||
/* ex:ts=8 sw=4:
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "ohash_int.h"
|
||||
|
||||
/* This handles the common case of variable length keys, where the
|
||||
* key is stored at the end of the record.
|
||||
*/
|
||||
void *
|
||||
ohash_create_entry(struct ohash_info *i, const char *start, const char **end)
|
||||
{
|
||||
char *p;
|
||||
|
||||
if (!*end)
|
||||
*end = start + strlen(start);
|
||||
p = (i->alloc)(i->key_offset + (*end - start) + 1, i->data);
|
||||
if (p) {
|
||||
memcpy(p+i->key_offset, start, *end-start);
|
||||
p[i->key_offset + (*end - start)] = '\0';
|
||||
}
|
||||
return (void *)p;
|
||||
}
|
33
usr.bin/m4/lib/ohash_delete.c
Normal file
33
usr.bin/m4/lib/ohash_delete.c
Normal file
@ -0,0 +1,33 @@
|
||||
/* $OpenBSD: ohash_delete.c,v 1.2 2004/06/22 20:00:16 espie Exp $ */
|
||||
/* ex:ts=8 sw=4:
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "ohash_int.h"
|
||||
/* hash_delete only frees the hash structure. Use hash_first/hash_next
|
||||
* to free entries as well. */
|
||||
void
|
||||
ohash_delete(struct ohash *h)
|
||||
{
|
||||
(h->info.hfree)(h->t, sizeof(struct _ohash_record) * h->size,
|
||||
h->info.data);
|
||||
#ifndef NDEBUG
|
||||
h->t = NULL;
|
||||
#endif
|
||||
}
|
113
usr.bin/m4/lib/ohash_do.c
Normal file
113
usr.bin/m4/lib/ohash_do.c
Normal file
@ -0,0 +1,113 @@
|
||||
/* $OpenBSD: ohash_do.c,v 1.4 2004/06/22 20:00:16 espie Exp $ */
|
||||
/* ex:ts=8 sw=4:
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "ohash_int.h"
|
||||
|
||||
static void ohash_resize(struct ohash *);
|
||||
|
||||
static void
|
||||
ohash_resize(struct ohash *h)
|
||||
{
|
||||
struct _ohash_record *n;
|
||||
unsigned int ns, j;
|
||||
unsigned int i, incr;
|
||||
|
||||
if (4 * h->deleted < h->total)
|
||||
ns = h->size << 1;
|
||||
else if (3 * h->deleted > 2 * h->total)
|
||||
ns = h->size >> 1;
|
||||
else
|
||||
ns = h->size;
|
||||
if (ns < MINSIZE)
|
||||
ns = MINSIZE;
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_EXPAND++;
|
||||
STAT_HASH_SIZE += ns - h->size;
|
||||
#endif
|
||||
n = (h->info.halloc)(sizeof(struct _ohash_record) * ns, h->info.data);
|
||||
if (!n)
|
||||
return;
|
||||
|
||||
for (j = 0; j < h->size; j++) {
|
||||
if (h->t[j].p != NULL && h->t[j].p != DELETED) {
|
||||
i = h->t[j].hv % ns;
|
||||
incr = ((h->t[j].hv % (ns - 2)) & ~1) + 1;
|
||||
while (n[i].p != NULL) {
|
||||
i += incr;
|
||||
if (i >= ns)
|
||||
i -= ns;
|
||||
}
|
||||
n[i].hv = h->t[j].hv;
|
||||
n[i].p = h->t[j].p;
|
||||
}
|
||||
}
|
||||
(h->info.hfree)(h->t, sizeof(struct _ohash_record) * h->size,
|
||||
h->info.data);
|
||||
h->t = n;
|
||||
h->size = ns;
|
||||
h->total -= h->deleted;
|
||||
h->deleted = 0;
|
||||
}
|
||||
|
||||
void *
|
||||
ohash_remove(struct ohash *h, unsigned int i)
|
||||
{
|
||||
void *result = __DECONST(void *, h->t[i].p);
|
||||
|
||||
if (result == NULL || result == DELETED)
|
||||
return NULL;
|
||||
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_ENTRIES--;
|
||||
#endif
|
||||
h->t[i].p = DELETED;
|
||||
h->deleted++;
|
||||
if (h->deleted >= MINDELETED && 4 * h->deleted > h->total)
|
||||
ohash_resize(h);
|
||||
return result;
|
||||
}
|
||||
|
||||
void *
|
||||
ohash_find(struct ohash *h, unsigned int i)
|
||||
{
|
||||
if (h->t[i].p == DELETED)
|
||||
return NULL;
|
||||
else
|
||||
return __DECONST(void *, h->t[i].p);
|
||||
}
|
||||
|
||||
void *
|
||||
ohash_insert(struct ohash *h, unsigned int i, void *p)
|
||||
{
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_ENTRIES++;
|
||||
#endif
|
||||
if (h->t[i].p == DELETED) {
|
||||
h->deleted--;
|
||||
h->t[i].p = p;
|
||||
} else {
|
||||
h->t[i].p = p;
|
||||
/* Arbitrary resize boundary. Tweak if not efficient enough. */
|
||||
if (++h->total * 4 > h->size * 3)
|
||||
ohash_resize(h);
|
||||
}
|
||||
return p;
|
||||
}
|
28
usr.bin/m4/lib/ohash_entries.c
Normal file
28
usr.bin/m4/lib/ohash_entries.c
Normal file
@ -0,0 +1,28 @@
|
||||
/* $OpenBSD: ohash_entries.c,v 1.2 2004/06/22 20:00:16 espie Exp $ */
|
||||
/* ex:ts=8 sw=4:
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "ohash_int.h"
|
||||
|
||||
unsigned int
|
||||
ohash_entries(struct ohash *h)
|
||||
{
|
||||
return h->total - h->deleted;
|
||||
}
|
38
usr.bin/m4/lib/ohash_enum.c
Normal file
38
usr.bin/m4/lib/ohash_enum.c
Normal file
@ -0,0 +1,38 @@
|
||||
/* $OpenBSD: ohash_enum.c,v 1.3 2004/06/22 20:00:16 espie Exp $ */
|
||||
/* ex:ts=8 sw=4:
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "ohash_int.h"
|
||||
|
||||
void *
|
||||
ohash_first(struct ohash *h, unsigned int *pos)
|
||||
{
|
||||
*pos = 0;
|
||||
return ohash_next(h, pos);
|
||||
}
|
||||
|
||||
void *
|
||||
ohash_next(struct ohash *h, unsigned int *pos)
|
||||
{
|
||||
for (; *pos < h->size; (*pos)++)
|
||||
if (h->t[*pos].p != DELETED && h->t[*pos].p != NULL)
|
||||
return __DECONST(void *, h->t[(*pos)++].p);
|
||||
return NULL;
|
||||
}
|
231
usr.bin/m4/lib/ohash_init.3
Normal file
231
usr.bin/m4/lib/ohash_init.3
Normal file
@ -0,0 +1,231 @@
|
||||
.\" $OpenBSD: ohash_init.3,v 1.14 2007/05/31 19:19:30 jmc Exp $
|
||||
.\" Copyright (c) 1999 Marc Espie <espie@openbsd.org>
|
||||
.\"
|
||||
.\" Permission to use, copy, modify, and distribute this software for any
|
||||
.\" purpose with or without fee is hereby granted, provided that the above
|
||||
.\" copyright notice and this permission notice appear in all copies.
|
||||
.\"
|
||||
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd $Mdocdate: May 31 2007 $
|
||||
.Dt OPEN_HASH 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm ohash_init ,
|
||||
.Nm ohash_delete ,
|
||||
.Nm ohash_lookup_interval ,
|
||||
.Nm ohash_lookup_memory ,
|
||||
.Nm ohash_find ,
|
||||
.Nm ohash_remove ,
|
||||
.Nm ohash_insert ,
|
||||
.Nm ohash_first ,
|
||||
.Nm ohash_next ,
|
||||
.Nm ohash_entries
|
||||
.Nd light-weight open hashing
|
||||
.Sh SYNOPSIS
|
||||
.Fd #include <stdint.h>
|
||||
.Fd #include <stddef.h>
|
||||
.Fd #include <ohash.h>
|
||||
.Ft void
|
||||
.Fn ohash_init "struct ohash *h" "unsigned int size" "struct ohash_info *info"
|
||||
.Ft void
|
||||
.Fn ohash_delete "struct ohash *h"
|
||||
.Ft "unsigned int"
|
||||
.Fn ohash_lookup_interval "struct ohash *h" "const char *start" "const char *end" "uint32_t hv"
|
||||
.Ft "unsigned int"
|
||||
.Fn ohash_lookup_memory "struct ohash *h" "const char *k" "size_t s" "uint32_t hv"
|
||||
.Ft void *
|
||||
.Fn ohash_find "struct ohash *h" "unsigned int i"
|
||||
.Ft void *
|
||||
.Fn ohash_remove "struct ohash *h" "unsigned int i"
|
||||
.Ft void *
|
||||
.Fn ohash_insert "struct ohash *h" "unsigned int i" "void *p"
|
||||
.Ft void *
|
||||
.Fn ohash_first "struct ohash *h" "unsigned int *i"
|
||||
.Ft void *
|
||||
.Fn ohash_next "struct ohash *h" "unsigned int *i"
|
||||
.Ft "unsigned int"
|
||||
.Fn ohash_entries "struct ohash *h"
|
||||
.Sh DESCRIPTION
|
||||
These functions have been designed as a fast, extensible alternative to
|
||||
the usual hash table functions.
|
||||
They provide storage and retrieval of records indexed by keys,
|
||||
where a key is a contiguous sequence of bytes at a fixed position in
|
||||
each record.
|
||||
Keys can either be NUL-terminated strings or fixed-size memory areas.
|
||||
All functions take a pointer to an ohash structure as the
|
||||
.Fa h
|
||||
function argument.
|
||||
Storage for this structure should be provided by user code.
|
||||
.Pp
|
||||
.Fn ohash_init
|
||||
initializes the table to store roughly 2 to the power
|
||||
.Fa size
|
||||
elements.
|
||||
.Fa info
|
||||
holds the position of the key in each record, and two pointers to
|
||||
.Xr calloc 3
|
||||
and
|
||||
.Xr free 3 Ns -like
|
||||
functions, to use for managing the table internal storage.
|
||||
.Pp
|
||||
.Fn ohash_delete
|
||||
frees storage internal to
|
||||
.Fa h .
|
||||
Elements themselves should be freed by the user first, using for instance
|
||||
.Fn ohash_first
|
||||
and
|
||||
.Fn ohash_next .
|
||||
.Pp
|
||||
.Fn ohash_lookup_interval
|
||||
and
|
||||
.Fn ohash_lookup_memory
|
||||
are the basic look-up element functions.
|
||||
The hashing function result is provided by the user as
|
||||
.Fa hv .
|
||||
These return a
|
||||
.Qq slot
|
||||
in the ohash table
|
||||
.Fa h ,
|
||||
to be used with
|
||||
.Fn ohash_find ,
|
||||
.Fn ohash_insert ,
|
||||
or
|
||||
.Fn ohash_remove .
|
||||
This slot is only valid up to the next call to
|
||||
.Fn ohash_insert
|
||||
or
|
||||
.Fn ohash_remove .
|
||||
.Pp
|
||||
.Fn ohash_lookup_interval
|
||||
handles string-like keys.
|
||||
.Fn ohash_lookup_interval
|
||||
assumes the key is the interval between
|
||||
.Fa start
|
||||
and
|
||||
.Fa end ,
|
||||
exclusive,
|
||||
though the actual elements stored in the table should only contain
|
||||
NUL-terminated keys.
|
||||
.Pp
|
||||
.Fn ohash_lookup_memory
|
||||
assumes the key is the memory area starting at
|
||||
.Fa k
|
||||
of size
|
||||
.Fa s .
|
||||
All bytes are significant in key comparison.
|
||||
.Pp
|
||||
.Fn ohash_find
|
||||
retrieves an element from a slot
|
||||
.Fa i
|
||||
returned by the
|
||||
.Fn ohash_lookup*
|
||||
functions.
|
||||
It returns
|
||||
.Dv NULL
|
||||
if the slot is empty.
|
||||
.Pp
|
||||
.Fn ohash_insert
|
||||
inserts a new element
|
||||
.Fa p
|
||||
at slot
|
||||
.Fa i .
|
||||
Slot
|
||||
.Fa i
|
||||
must be empty and element
|
||||
.Fa p
|
||||
must have a key corresponding to the
|
||||
.Fn ohash_lookup*
|
||||
call.
|
||||
.Pp
|
||||
.Fn ohash_remove
|
||||
removes the element at slot
|
||||
.Fa i .
|
||||
It returns the removed element, for user code to dispose of, or
|
||||
.Dv NULL
|
||||
if the slot was empty.
|
||||
.Pp
|
||||
.Fn ohash_first
|
||||
and
|
||||
.Fn ohash_next
|
||||
can be used to access all elements in an ohash table, like this:
|
||||
.Bd -literal -offset indent
|
||||
for (n = ohash_first(h, &i); n != NULL; n = ohash_next(h, &i))
|
||||
do_something_with(n);
|
||||
.Ed
|
||||
.Pp
|
||||
.Fa i
|
||||
points to an auxiliary unsigned integer used to record the current position
|
||||
in the ohash table.
|
||||
Those functions are safe to use even while entries are added to/removed
|
||||
from the table, but in such a case they don't guarantee that new entries
|
||||
will be returned.
|
||||
As a special case, they can safely be used to free elements in the table.
|
||||
.Pp
|
||||
.Fn ohash_entries
|
||||
returns the number of elements in the hash table.
|
||||
.Sh STORAGE HANDLING
|
||||
Only
|
||||
.Fn ohash_init ,
|
||||
.Fn ohash_insert ,
|
||||
.Fn ohash_remove
|
||||
and
|
||||
.Fn ohash_delete
|
||||
may call the user-supplied memory functions.
|
||||
It is the responsibility of the user memory allocation code to verify
|
||||
that those calls did not fail.
|
||||
.Pp
|
||||
If memory allocation fails,
|
||||
.Fn ohash_init
|
||||
returns a useless hash table.
|
||||
.Fn ohash_insert
|
||||
and
|
||||
.Fn ohash_remove
|
||||
still perform the requested operation, but the returned table should be
|
||||
considered read-only.
|
||||
It can still be accessed by
|
||||
.Fn ohash_lookup* ,
|
||||
.Fn ohash_find ,
|
||||
.Fn ohash_first
|
||||
and
|
||||
.Fn ohash_next
|
||||
to dump relevant information to disk before aborting.
|
||||
.Sh THREAD SAFETY
|
||||
The open hashing functions are not thread-safe by design.
|
||||
In particular, in a threaded environment, there is no guarantee that a
|
||||
.Qq slot
|
||||
will not move between a
|
||||
.Fn ohash_lookup*
|
||||
and a
|
||||
.Fn ohash_find ,
|
||||
.Fn ohash_insert
|
||||
or
|
||||
.Fn ohash_remove
|
||||
call.
|
||||
.Pp
|
||||
Multi-threaded applications should explicitly protect ohash table access.
|
||||
.Sh SEE ALSO
|
||||
.Xr ohash_interval 3
|
||||
.Rs
|
||||
.%A Donald E. Knuth
|
||||
.%B The Art of Computer Programming
|
||||
.%V Vol. 3
|
||||
.%P pp 506-550
|
||||
.%D 1973
|
||||
.Re
|
||||
.Sh STANDARDS
|
||||
Those functions are completely non-standard and should be avoided in
|
||||
portable programs.
|
||||
.Sh HISTORY
|
||||
Those functions were designed and written for
|
||||
.Ox
|
||||
.Xr make 1
|
||||
by Marc Espie in 1999.
|
43
usr.bin/m4/lib/ohash_init.c
Normal file
43
usr.bin/m4/lib/ohash_init.c
Normal file
@ -0,0 +1,43 @@
|
||||
/* $OpenBSD: ohash_init.c,v 1.2 2004/06/22 20:00:16 espie Exp $ */
|
||||
/* ex:ts=8 sw=4:
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "ohash_int.h"
|
||||
|
||||
void
|
||||
ohash_init(struct ohash *h, unsigned int size, struct ohash_info *info)
|
||||
{
|
||||
h->size = 1UL << size;
|
||||
if (h->size < MINSIZE)
|
||||
h->size = MINSIZE;
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_CREATION++;
|
||||
STAT_HASH_SIZE += h->size;
|
||||
#endif
|
||||
/* Copy info so that caller may free it. */
|
||||
h->info.key_offset = info->key_offset;
|
||||
h->info.halloc = info->halloc;
|
||||
h->info.hfree = info->hfree;
|
||||
h->info.alloc = info->alloc;
|
||||
h->info.data = info->data;
|
||||
h->t = (h->info.halloc)(sizeof(struct _ohash_record) * h->size,
|
||||
h->info.data);
|
||||
h->total = h->deleted = 0;
|
||||
}
|
25
usr.bin/m4/lib/ohash_int.h
Normal file
25
usr.bin/m4/lib/ohash_int.h
Normal file
@ -0,0 +1,25 @@
|
||||
/* $OpenBSD: ohash_int.h,v 1.3 2006/01/16 15:52:25 espie Exp $ */
|
||||
/* $FreeBSD$ */
|
||||
|
||||
#if HAVE_NBTOOL_CONFIG_H
|
||||
#include "nbtool_config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "ohash.h"
|
||||
|
||||
struct _ohash_record {
|
||||
u_int32_t hv;
|
||||
const char *p;
|
||||
};
|
||||
|
||||
#define DELETED ((const char *)h)
|
||||
#define NONE (h->size)
|
||||
|
||||
/* Don't bother changing the hash table if the change is small enough. */
|
||||
#define MINSIZE (1UL << 4)
|
||||
#define MINDELETED 4
|
92
usr.bin/m4/lib/ohash_interval.3
Normal file
92
usr.bin/m4/lib/ohash_interval.3
Normal file
@ -0,0 +1,92 @@
|
||||
.\" $OpenBSD: ohash_interval.3,v 1.11 2007/05/31 19:19:30 jmc Exp $
|
||||
.\" Copyright (c) 2001 Marc Espie <espie@openbsd.org>
|
||||
.\"
|
||||
.\" Permission to use, copy, modify, and distribute this software for any
|
||||
.\" purpose with or without fee is hereby granted, provided that the above
|
||||
.\" copyright notice and this permission notice appear in all copies.
|
||||
.\"
|
||||
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd $Mdocdate: May 31 2007 $
|
||||
.Dt OPEN_HASH_HELPER 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm ohash_interval ,
|
||||
.Nm ohash_create_entry ,
|
||||
.Nm ohash_qlookup ,
|
||||
.Nm ohash_qlookupi
|
||||
.Nd helper functions for open hashing
|
||||
.Sh SYNOPSIS
|
||||
.Fd #include <stdint.h>
|
||||
.Fd #include <stddef.h>
|
||||
.Fd #include <ohash.h>
|
||||
.Ft u_int32_t
|
||||
.Fn ohash_interval "const char *start" "const char **pend"
|
||||
.Ft "void *"
|
||||
.Fn ohash_create_entry "struct ohash_info *info" "const char *start" "const char **pend"
|
||||
.Ft "unsigned int"
|
||||
.Fn ohash_qlookupi "struct ohash *h" "const char *start" "const char **pend"
|
||||
.Ft "unsigned int"
|
||||
.Fn ohash_qlookup "struct ohash *h" "const char *start"
|
||||
.Sh DESCRIPTION
|
||||
These functions are commonly used to simplify open hashing usage, and use
|
||||
similar conventions.
|
||||
They operate indifferently on NUL-terminated strings
|
||||
.Po
|
||||
by setting
|
||||
.Fa *pend
|
||||
=
|
||||
.Dv NULL
|
||||
.Pc
|
||||
or memory ranges
|
||||
.Po
|
||||
delimited by
|
||||
.Fa start
|
||||
and
|
||||
.Fa *pend
|
||||
.Pc .
|
||||
For NUL-terminated strings, as a side effect, those functions
|
||||
set
|
||||
.Fa *pend
|
||||
to the terminating NUL byte.
|
||||
.Pp
|
||||
.Fn ohash_interval
|
||||
is a simple hashing function that yields good results on common data sets.
|
||||
.Pp
|
||||
.Fn ohash_create_entry
|
||||
can be used to create a new record with a given key.
|
||||
In that case,
|
||||
the alloc field of
|
||||
.Fa info
|
||||
should point to a
|
||||
.Xr malloc 3 Ns -like
|
||||
function to allocate the storage.
|
||||
.Pp
|
||||
.Fn ohash_qlookupi
|
||||
is a wrapper function that simply calls
|
||||
.Fn ohash_interval
|
||||
and
|
||||
.Fn ohash_lookup_interval .
|
||||
.Pp
|
||||
.Fn ohash_qlookup
|
||||
is a variation on
|
||||
.Fn ohash_qlookupi
|
||||
designed for NUL-terminated strings.
|
||||
.Sh SEE ALSO
|
||||
.Xr ohash_init 3
|
||||
.Sh STANDARDS
|
||||
Those functions are completely non-standard and should be avoided in
|
||||
portable programs.
|
||||
.Sh HISTORY
|
||||
Those functions were designed and written for
|
||||
.Ox
|
||||
.Xr make 1
|
||||
by Marc Espie in 1999.
|
38
usr.bin/m4/lib/ohash_interval.c
Normal file
38
usr.bin/m4/lib/ohash_interval.c
Normal file
@ -0,0 +1,38 @@
|
||||
/* $OpenBSD: ohash_interval.c,v 1.3 2006/01/16 15:52:25 espie Exp $ */
|
||||
/* ex:ts=8 sw=4:
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "ohash_int.h"
|
||||
|
||||
uint32_t
|
||||
ohash_interval(const char *s, const char **e)
|
||||
{
|
||||
uint32_t k;
|
||||
|
||||
if (!*e)
|
||||
*e = s + strlen(s);
|
||||
if (s == *e)
|
||||
k = 0;
|
||||
else
|
||||
k = *s++;
|
||||
while (s != *e)
|
||||
k = ((k << 2) | (k >> 30)) ^ *s++;
|
||||
return k;
|
||||
}
|
70
usr.bin/m4/lib/ohash_lookup_interval.c
Normal file
70
usr.bin/m4/lib/ohash_lookup_interval.c
Normal file
@ -0,0 +1,70 @@
|
||||
/* $OpenBSD: ohash_lookup_interval.c,v 1.3 2006/01/16 15:52:25 espie Exp $ */
|
||||
/* ex:ts=8 sw=4:
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "ohash_int.h"
|
||||
|
||||
unsigned int
|
||||
ohash_lookup_interval(struct ohash *h, const char *start, const char *end,
|
||||
uint32_t hv)
|
||||
{
|
||||
unsigned int i, incr;
|
||||
unsigned int empty;
|
||||
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_LOOKUP++;
|
||||
#endif
|
||||
empty = NONE;
|
||||
i = hv % h->size;
|
||||
incr = ((hv % (h->size-2)) & ~1) + 1;
|
||||
while (h->t[i].p != NULL) {
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_LENGTH++;
|
||||
#endif
|
||||
if (h->t[i].p == DELETED) {
|
||||
if (empty == NONE)
|
||||
empty = i;
|
||||
} else if (h->t[i].hv == hv &&
|
||||
strncmp(h->t[i].p+h->info.key_offset, start,
|
||||
end - start) == 0 &&
|
||||
(h->t[i].p+h->info.key_offset)[end-start] == '\0') {
|
||||
if (empty != NONE) {
|
||||
h->t[empty].hv = hv;
|
||||
h->t[empty].p = h->t[i].p;
|
||||
h->t[i].p = DELETED;
|
||||
return empty;
|
||||
} else {
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_POSITIVE++;
|
||||
#endif
|
||||
return i;
|
||||
}
|
||||
}
|
||||
i += incr;
|
||||
if (i >= h->size)
|
||||
i -= h->size;
|
||||
}
|
||||
|
||||
/* Found an empty position. */
|
||||
if (empty != NONE)
|
||||
i = empty;
|
||||
h->t[i].hv = hv;
|
||||
return i;
|
||||
}
|
66
usr.bin/m4/lib/ohash_lookup_memory.c
Normal file
66
usr.bin/m4/lib/ohash_lookup_memory.c
Normal file
@ -0,0 +1,66 @@
|
||||
/* $OpenBSD: ohash_lookup_memory.c,v 1.3 2006/01/16 15:52:25 espie Exp $ */
|
||||
/* ex:ts=8 sw=4:
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "ohash_int.h"
|
||||
|
||||
unsigned int
|
||||
ohash_lookup_memory(struct ohash *h, const char *k, size_t size, uint32_t hv)
|
||||
{
|
||||
unsigned int i, incr;
|
||||
unsigned int empty;
|
||||
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_LOOKUP++;
|
||||
#endif
|
||||
empty = NONE;
|
||||
i = hv % h->size;
|
||||
incr = ((hv % (h->size-2)) & ~1) + 1;
|
||||
while (h->t[i].p != NULL) {
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_LENGTH++;
|
||||
#endif
|
||||
if (h->t[i].p == DELETED) {
|
||||
if (empty == NONE)
|
||||
empty = i;
|
||||
} else if (h->t[i].hv == hv &&
|
||||
memcmp(h->t[i].p+h->info.key_offset, k, size) == 0) {
|
||||
if (empty != NONE) {
|
||||
h->t[empty].hv = hv;
|
||||
h->t[empty].p = h->t[i].p;
|
||||
h->t[i].p = DELETED;
|
||||
return empty;
|
||||
} else {
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_POSITIVE++;
|
||||
#endif
|
||||
} return i;
|
||||
}
|
||||
i += incr;
|
||||
if (i >= h->size)
|
||||
i -= h->size;
|
||||
}
|
||||
|
||||
/* Found an empty position. */
|
||||
if (empty != NONE)
|
||||
i = empty;
|
||||
h->t[i].hv = hv;
|
||||
return i;
|
||||
}
|
29
usr.bin/m4/lib/ohash_qlookup.c
Normal file
29
usr.bin/m4/lib/ohash_qlookup.c
Normal file
@ -0,0 +1,29 @@
|
||||
/* $OpenBSD: ohash_qlookup.c,v 1.2 2004/06/22 20:00:17 espie Exp $ */
|
||||
/* ex:ts=8 sw=4:
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "ohash_int.h"
|
||||
|
||||
unsigned int
|
||||
ohash_qlookup(struct ohash *h, const char *s)
|
||||
{
|
||||
const char *e = NULL;
|
||||
return ohash_qlookupi(h, s, &e);
|
||||
}
|
31
usr.bin/m4/lib/ohash_qlookupi.c
Normal file
31
usr.bin/m4/lib/ohash_qlookupi.c
Normal file
@ -0,0 +1,31 @@
|
||||
/* $OpenBSD: ohash_qlookupi.c,v 1.2 2004/06/22 20:00:17 espie Exp $ */
|
||||
/* ex:ts=8 sw=4:
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "ohash_int.h"
|
||||
|
||||
unsigned int
|
||||
ohash_qlookupi(struct ohash *h, const char *s, const char **e)
|
||||
{
|
||||
u_int32_t hv;
|
||||
|
||||
hv = ohash_interval(s, e);
|
||||
return ohash_lookup_interval(h, s, *e, hv);
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: look.c,v 1.10 2002/04/26 16:15:16 espie Exp $ */
|
||||
/* $OpenBSD: look.c,v 1.22 2010/09/07 19:58:09 marco Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1989, 1993
|
||||
@ -15,7 +15,7 @@
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
@ -31,13 +31,6 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)look.c 8.1 (Berkeley) 6/6/93";
|
||||
#endif /* not lint */
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
@ -50,21 +43,52 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <ohash.h>
|
||||
#include "mdef.h"
|
||||
#include "stdd.h"
|
||||
#include "extern.h"
|
||||
|
||||
static void freent(ndptr);
|
||||
static void *hash_alloc(size_t, void *);
|
||||
static void hash_free(void *, size_t, void *);
|
||||
static void *element_alloc(size_t, void *);
|
||||
static void setup_definition(struct macro_definition *, const char *,
|
||||
const char *);
|
||||
|
||||
unsigned int
|
||||
hash(const char *name)
|
||||
static struct ohash_info macro_info = {
|
||||
offsetof(struct ndblock, name),
|
||||
NULL, hash_alloc, hash_free, element_alloc };
|
||||
|
||||
struct ohash macros;
|
||||
|
||||
/* Support routines for hash tables. */
|
||||
void *
|
||||
hash_alloc(size_t s, __unused void *u)
|
||||
{
|
||||
unsigned int h = 0;
|
||||
while (*name)
|
||||
h = (h << 5) + h + *name++;
|
||||
return (h);
|
||||
void *storage = xalloc(s, "hash alloc");
|
||||
if (storage)
|
||||
memset(storage, 0, s);
|
||||
return storage;
|
||||
}
|
||||
|
||||
void
|
||||
hash_free(void *p, __unused size_t s, __unused void *u)
|
||||
{
|
||||
free(p);
|
||||
}
|
||||
|
||||
void *
|
||||
element_alloc(size_t s, __unused void *u)
|
||||
{
|
||||
return xalloc(s, "element alloc");
|
||||
}
|
||||
|
||||
void
|
||||
init_macros(void)
|
||||
{
|
||||
ohash_init(¯os, 10, ¯o_info);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -73,74 +97,181 @@ hash(const char *name)
|
||||
ndptr
|
||||
lookup(const char *name)
|
||||
{
|
||||
ndptr p;
|
||||
unsigned int h;
|
||||
|
||||
h = hash(name);
|
||||
for (p = hashtab[h % HASHSIZE]; p != nil; p = p->nxtptr)
|
||||
if (h == p->hv && STREQ(name, p->name))
|
||||
break;
|
||||
return (p);
|
||||
return ohash_find(¯os, ohash_qlookup(¯os, name));
|
||||
}
|
||||
|
||||
/*
|
||||
* hash and create an entry in the hash table.
|
||||
* The new entry is added in front of a hash bucket.
|
||||
*/
|
||||
ndptr
|
||||
addent(const char *name)
|
||||
struct macro_definition *
|
||||
lookup_macro_definition(const char *name)
|
||||
{
|
||||
unsigned int h;
|
||||
ndptr p;
|
||||
|
||||
h = hash(name);
|
||||
p = (ndptr) xalloc(sizeof(struct ndblock));
|
||||
p->nxtptr = hashtab[h % HASHSIZE];
|
||||
hashtab[h % HASHSIZE] = p;
|
||||
p->name = xstrdup(name);
|
||||
p->hv = h;
|
||||
return p;
|
||||
p = ohash_find(¯os, ohash_qlookup(¯os, name));
|
||||
if (p)
|
||||
return p->d;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
freent(ndptr p)
|
||||
setup_definition(struct macro_definition *d, const char *defn, const char *name)
|
||||
{
|
||||
free((char *) p->name);
|
||||
if (p->defn != null)
|
||||
free((char *) p->defn);
|
||||
free((char *) p);
|
||||
ndptr p;
|
||||
|
||||
if (strncmp(defn, BUILTIN_MARKER, sizeof(BUILTIN_MARKER)-1) == 0 &&
|
||||
(p = macro_getbuiltin(defn+sizeof(BUILTIN_MARKER)-1)) != NULL) {
|
||||
d->type = macro_builtin_type(p);
|
||||
d->defn = xstrdup(defn+sizeof(BUILTIN_MARKER)-1);
|
||||
} else {
|
||||
if (!*defn)
|
||||
d->defn = __DECONST(char *, null);
|
||||
else
|
||||
d->defn = xstrdup(defn);
|
||||
d->type = MACRTYPE;
|
||||
}
|
||||
if (STREQ(name, defn))
|
||||
d->type |= RECDEF;
|
||||
}
|
||||
|
||||
/*
|
||||
* remove an entry from the hashtable
|
||||
*/
|
||||
void
|
||||
remhash(const char *name, int all)
|
||||
static ndptr
|
||||
create_entry(const char *name)
|
||||
{
|
||||
unsigned int h;
|
||||
ndptr xp, tp, mp;
|
||||
const char *end = NULL;
|
||||
unsigned int i;
|
||||
ndptr n;
|
||||
|
||||
h = hash(name);
|
||||
mp = hashtab[h % HASHSIZE];
|
||||
tp = nil;
|
||||
while (mp != nil) {
|
||||
if (mp->hv == h && STREQ(mp->name, name)) {
|
||||
mp = mp->nxtptr;
|
||||
if (tp == nil) {
|
||||
freent(hashtab[h % HASHSIZE]);
|
||||
hashtab[h % HASHSIZE] = mp;
|
||||
}
|
||||
else {
|
||||
xp = tp->nxtptr;
|
||||
tp->nxtptr = mp;
|
||||
freent(xp);
|
||||
}
|
||||
if (!all)
|
||||
break;
|
||||
i = ohash_qlookupi(¯os, name, &end);
|
||||
n = ohash_find(¯os, i);
|
||||
if (n == NULL) {
|
||||
n = ohash_create_entry(¯o_info, name, &end);
|
||||
ohash_insert(¯os, i, n);
|
||||
n->trace_flags = FLAG_NO_TRACE;
|
||||
n->builtin_type = MACRTYPE;
|
||||
n->d = NULL;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void
|
||||
macro_define(const char *name, const char *defn)
|
||||
{
|
||||
ndptr n = create_entry(name);
|
||||
if (n->d != NULL) {
|
||||
if (n->d->defn != null)
|
||||
free(n->d->defn);
|
||||
} else {
|
||||
n->d = xalloc(sizeof(struct macro_definition), NULL);
|
||||
n->d->next = NULL;
|
||||
}
|
||||
setup_definition(n->d, defn, name);
|
||||
}
|
||||
|
||||
void
|
||||
macro_pushdef(const char *name, const char *defn)
|
||||
{
|
||||
ndptr n;
|
||||
struct macro_definition *d;
|
||||
|
||||
n = create_entry(name);
|
||||
d = xalloc(sizeof(struct macro_definition), NULL);
|
||||
d->next = n->d;
|
||||
n->d = d;
|
||||
setup_definition(n->d, defn, name);
|
||||
}
|
||||
|
||||
void
|
||||
macro_undefine(const char *name)
|
||||
{
|
||||
ndptr n = lookup(name);
|
||||
if (n != NULL) {
|
||||
struct macro_definition *r, *r2;
|
||||
|
||||
for (r = n->d; r != NULL; r = r2) {
|
||||
r2 = r->next;
|
||||
if (r->defn != null)
|
||||
free(r->defn);
|
||||
free(r);
|
||||
}
|
||||
else {
|
||||
tp = mp;
|
||||
mp = mp->nxtptr;
|
||||
n->d = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
macro_popdef(const char *name)
|
||||
{
|
||||
ndptr n = lookup(name);
|
||||
|
||||
if (n != NULL) {
|
||||
struct macro_definition *r = n->d;
|
||||
if (r != NULL) {
|
||||
n->d = r->next;
|
||||
if (r->defn != null)
|
||||
free(r->defn);
|
||||
free(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
macro_for_all(void (*f)(const char *, struct macro_definition *))
|
||||
{
|
||||
ndptr n;
|
||||
unsigned int i;
|
||||
|
||||
for (n = ohash_first(¯os, &i); n != NULL;
|
||||
n = ohash_next(¯os, &i))
|
||||
if (n->d != NULL)
|
||||
f(n->name, n->d);
|
||||
}
|
||||
|
||||
void
|
||||
setup_builtin(const char *name, unsigned int type)
|
||||
{
|
||||
ndptr n;
|
||||
char *name2;
|
||||
|
||||
if (prefix_builtins) {
|
||||
name2 = xalloc(strlen(name)+3+1, NULL);
|
||||
memcpy(name2, "m4_", 3);
|
||||
memcpy(name2 + 3, name, strlen(name)+1);
|
||||
} else
|
||||
name2 = xstrdup(name);
|
||||
|
||||
n = create_entry(name2);
|
||||
n->builtin_type = type;
|
||||
n->d = xalloc(sizeof(struct macro_definition), NULL);
|
||||
n->d->defn = name2;
|
||||
n->d->type = type;
|
||||
n->d->next = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
mark_traced(const char *name, int on)
|
||||
{
|
||||
ndptr p;
|
||||
unsigned int i;
|
||||
|
||||
if (name == NULL) {
|
||||
if (on)
|
||||
trace_flags |= TRACE_ALL;
|
||||
else
|
||||
trace_flags &= ~TRACE_ALL;
|
||||
for (p = ohash_first(¯os, &i); p != NULL;
|
||||
p = ohash_next(¯os, &i))
|
||||
p->trace_flags = FLAG_NO_TRACE;
|
||||
} else {
|
||||
p = create_entry(name);
|
||||
p->trace_flags = on;
|
||||
}
|
||||
}
|
||||
|
||||
ndptr
|
||||
macro_getbuiltin(const char *name)
|
||||
{
|
||||
ndptr p;
|
||||
|
||||
p = lookup(name);
|
||||
if (p == NULL || p->builtin_type == MACRTYPE)
|
||||
return NULL;
|
||||
else
|
||||
return p;
|
||||
}
|
||||
|
498
usr.bin/m4/m4.1
498
usr.bin/m4/m4.1
@ -1,201 +1,266 @@
|
||||
.\" @(#) $OpenBSD: m4.1,v 1.24 2002/04/18 18:57:23 espie Exp $
|
||||
.\" $NetBSD: m4.1,v 1.22 2010/05/14 17:14:28 joerg Exp $
|
||||
.\" @(#) $OpenBSD: m4.1,v 1.56 2009/10/14 17:19:47 sthen Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1989, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" This code is derived from software contributed to Berkeley by
|
||||
.\" Ozan Yigit at York University.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. Neither the name of the University nor the names of its contributors
|
||||
.\" may be used to endorse or promote products derived from this software
|
||||
.\" without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd July 3, 2004
|
||||
.Dd October 14, 2009
|
||||
.Dt M4 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm m4
|
||||
.Nd macro language processor
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Nm m4
|
||||
.Op Fl gPs
|
||||
.Oo
|
||||
.Sm off
|
||||
.Fl D Ar name Op No = Ar value
|
||||
.Sm on
|
||||
.Oc
|
||||
.Op Fl d Ar flags
|
||||
.Op Fl t Ar name
|
||||
.Op Fl gs
|
||||
.Op Fl D Ar name Ns Op = Ns Ar value
|
||||
.Op Fl U Ar name
|
||||
.Op Fl I Ar dirname
|
||||
.Op Fl o Ar filename
|
||||
.Bk -words
|
||||
.Op Fl t Ar macro
|
||||
.Op Fl U Ns Ar name
|
||||
.Op Ar
|
||||
.Ek
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
.Nm m4
|
||||
utility is a macro processor that can be used as a front end to any
|
||||
language (e.g., C, ratfor, fortran, lex, and yacc).
|
||||
The
|
||||
.Nm
|
||||
utility reads from the standard input and writes
|
||||
the processed text to the standard output.
|
||||
If no input files are given,
|
||||
.Nm m4
|
||||
reads from the standard input,
|
||||
otherwise files specified on the command line are
|
||||
processed in the given order.
|
||||
Input files can be regular files, files in the m4 include paths, or a
|
||||
single dash
|
||||
.Pq Sq - ,
|
||||
denoting standard input.
|
||||
.Nm m4
|
||||
writes
|
||||
the processed text to the standard output, unless told otherwise.
|
||||
.Pp
|
||||
Macro calls have the form
|
||||
.Ic name Ns Pq Ar argument1 Ns Op , Ar argument2 , ... , argumentN .
|
||||
Macro calls have the form name(argument1[, argument2, ..., argumentN]).
|
||||
.Pp
|
||||
There cannot be any space following the macro name and the open
|
||||
parenthesis
|
||||
.Pq Ql \&( .
|
||||
.Sq \&( .
|
||||
If the macro name is not followed by an open
|
||||
parenthesis it is processed with no arguments.
|
||||
.Pp
|
||||
Macro names consist of a leading alphabetic or underscore
|
||||
possibly followed by alphanumeric or underscore characters, e.g.,
|
||||
valid macro names match the pattern
|
||||
.Dq Li [a-zA-Z_][a-zA-Z0-9_]* .
|
||||
.Dq [a-zA-Z_][a-zA-Z0-9_]* .
|
||||
.Pp
|
||||
In arguments to macros, leading unquoted space, tab, and newline
|
||||
.Pq Ql \en
|
||||
.Pq Sq \en
|
||||
characters are ignored.
|
||||
To quote strings, use left and right single
|
||||
quotes (e.g.,
|
||||
.Sq "\ this is a string with a leading space" ) .
|
||||
To quote strings, use left and right single quotes
|
||||
.Po e.g.,\ \&
|
||||
.Sq "\ this is a string with a leading space"
|
||||
.Pc .
|
||||
You can change the quote characters with the
|
||||
.Ic changequote
|
||||
built-in macro.
|
||||
.Pp
|
||||
Most built-ins do not make any sense without arguments, and hence are not
|
||||
Most built-ins don't make any sense without arguments, and hence are not
|
||||
recognized as special when not followed by an open parenthesis.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width indent
|
||||
.It Fl s
|
||||
Emit
|
||||
.Ic #line
|
||||
directives for
|
||||
.Xr cpp 1 .
|
||||
.It Fl D Ar name Ns Op = Ns Ar value
|
||||
.Bl -tag -width Ds
|
||||
.It Fl D Ns Ar name Ns Op Pf = Ns Ar value
|
||||
Define the symbol
|
||||
.Ar name
|
||||
to have some value (or
|
||||
.Dv NULL ) .
|
||||
.It Fl U Ar name
|
||||
Undefine the symbol
|
||||
.Ar name .
|
||||
.It Fl I Ar dirname
|
||||
Add directory
|
||||
.Ar dirname
|
||||
to the include path.
|
||||
.It Fl d Ar flags
|
||||
.It Fl d Ar "flags"
|
||||
Set trace flags.
|
||||
The
|
||||
.Ar flags
|
||||
argument may hold the following:
|
||||
.Pp
|
||||
.Bl -tag -width indent -compact
|
||||
.It Cm a
|
||||
print macro arguments
|
||||
.It Cm c
|
||||
print macro expansion over several lines
|
||||
.It Cm e
|
||||
print result of macro expansion
|
||||
.It Cm f
|
||||
print filename location
|
||||
.It Cm l
|
||||
print line number
|
||||
.It Cm q
|
||||
quote arguments and expansion with the current quotes
|
||||
.It Cm t
|
||||
start with all macros traced
|
||||
.It Cm x
|
||||
number macro expansions
|
||||
.It Cm V
|
||||
turn on all options
|
||||
may hold the following:
|
||||
.Bl -tag -width Ds
|
||||
.It Ar a
|
||||
print macro arguments.
|
||||
.It Ar c
|
||||
print macro expansion over several lines.
|
||||
.It Ar e
|
||||
print result of macro expansion.
|
||||
.It Ar f
|
||||
print filename location.
|
||||
.It Ar l
|
||||
print line number.
|
||||
.It Ar q
|
||||
quote arguments and expansion with the current quotes.
|
||||
.It Ar t
|
||||
start with all macros traced.
|
||||
.It Ar x
|
||||
number macro expansions.
|
||||
.It Ar V
|
||||
turn on all options.
|
||||
.El
|
||||
.Pp
|
||||
By default, trace is set to
|
||||
.Cm eq .
|
||||
.Qq eq .
|
||||
.It Fl g
|
||||
Activate GNU-m4 compatibility mode.
|
||||
In this mode, translit handles simple character
|
||||
ranges (e.g., a-z), regular expressions mimic emacs behavior,
|
||||
multiple m4wrap calls are handled as a stack,
|
||||
the number of diversions is unlimited,
|
||||
empty names for macro definitions are allowed,
|
||||
and eval understands
|
||||
.Sq 0rbase:value
|
||||
numbers.
|
||||
.It Fl I Ar "dirname"
|
||||
Add directory
|
||||
.Ar dirname
|
||||
to the include path.
|
||||
.It Fl o Ar filename
|
||||
Send trace output to
|
||||
.Ar filename .
|
||||
.It Fl P
|
||||
Prefix all built-in macros with
|
||||
.Sq m4_ .
|
||||
For example, instead of writing
|
||||
.Ic define ,
|
||||
use
|
||||
.Ic m4_define .
|
||||
.It Fl s
|
||||
Output line synchronization directives, suitable for
|
||||
.Xr cpp 1 .
|
||||
.It Fl t Ar macro
|
||||
Turn tracing on for
|
||||
.Ar macro .
|
||||
.It Fl g
|
||||
Activate GNU-m4 compatibility mode.
|
||||
In this mode,
|
||||
.Ic changequote
|
||||
with two empty parameters deactivates quotes,
|
||||
.Ic translit
|
||||
handles simple character ranges (e.g.,
|
||||
.Li a-z ) ,
|
||||
regular expressions mimic
|
||||
.Xr emacs 1
|
||||
behavior,
|
||||
and the number of diversions is unlimited.
|
||||
.It Fl "U" Ns Ar "name"
|
||||
Undefine the symbol
|
||||
.Ar name .
|
||||
.El
|
||||
.Sh SYNTAX
|
||||
The
|
||||
.Nm
|
||||
utility provides the following built-in macros.
|
||||
.Nm m4
|
||||
provides the following built-in macros.
|
||||
They may be redefined, losing their original meaning.
|
||||
Return values are null unless otherwise stated.
|
||||
.Bl -tag -width ".Ic changequote"
|
||||
.It Ic builtin
|
||||
Calls a built-in by its name, overriding possible redefinitions.
|
||||
.It Ic changecom
|
||||
Changes the start and end comment sequences.
|
||||
The default is the pound sign
|
||||
.Pq Ql #
|
||||
.Bl -tag -width changequote
|
||||
.It Fn builtin name
|
||||
Calls a built-in by its
|
||||
.Fa name ,
|
||||
overriding possible redefinitions.
|
||||
.It Fn changecom startcomment endcomment
|
||||
Changes the start comment and end comment sequences.
|
||||
Comment sequences may be up to five characters long.
|
||||
The default values are the hash sign
|
||||
and the newline character.
|
||||
With no arguments, the comment sequence is reset to the default,
|
||||
in GNU
|
||||
.Nm
|
||||
mode, comments are turned off.
|
||||
The maximum length for a comment marker is five characters.
|
||||
.It Ic changequote
|
||||
Defines the quote symbols to be the first and second arguments.
|
||||
The symbols may be up to five characters long.
|
||||
If no arguments are
|
||||
given it restores the default open and close single quotes.
|
||||
.It Ic decr
|
||||
Decrements the argument by 1.
|
||||
The argument must be a valid numeric string.
|
||||
.It Ic define
|
||||
Define a new macro named by the first argument to have the
|
||||
value of the second argument.
|
||||
.Bd -literal -offset indent
|
||||
# This is a comment
|
||||
.Ed
|
||||
.Pp
|
||||
With no arguments, comments are turned off.
|
||||
With one single argument, the end comment sequence is set
|
||||
to the newline character.
|
||||
.It Fn changequote beginquote endquote
|
||||
Defines the open quote and close quote sequences.
|
||||
Quote sequences may be up to five characters long.
|
||||
The default values are the backquote character and the quote
|
||||
character.
|
||||
.Bd -literal -offset indent
|
||||
`Here is a quoted string'
|
||||
.Ed
|
||||
.Pp
|
||||
With no arguments, the default quotes are restored.
|
||||
With one single argument, the close quote sequence is set
|
||||
to the newline character.
|
||||
.It Fn decr arg
|
||||
Decrements the argument
|
||||
.Fa arg
|
||||
by 1.
|
||||
The argument
|
||||
.Fa arg
|
||||
must be a valid numeric string.
|
||||
.It Fn define name value
|
||||
Define a new macro named by the first argument
|
||||
.Fa name
|
||||
to have the
|
||||
value of the second argument
|
||||
.Fa value .
|
||||
Each occurrence of
|
||||
.Sq Li $ Ns Ar n
|
||||
.Sq $n
|
||||
(where
|
||||
.Ar n
|
||||
is 0 through 9) is replaced by the
|
||||
.Ar n Ns 'th
|
||||
argument.
|
||||
.Ql $0
|
||||
.Sq $0
|
||||
is the name of the calling macro.
|
||||
Undefined arguments are replaced by a null string.
|
||||
.Ql $#
|
||||
.Sq $#
|
||||
is replaced by the number of arguments;
|
||||
.Ql $*
|
||||
.Sq $*
|
||||
is replaced by all arguments comma separated;
|
||||
.Ql $@
|
||||
.Sq $@
|
||||
is the same as
|
||||
.Ql $*
|
||||
.Sq $*
|
||||
but all arguments are quoted against further expansion.
|
||||
.It Ic defn
|
||||
.It Fn defn name ...
|
||||
Returns the quoted definition for each argument.
|
||||
This can be used to rename
|
||||
macro definitions (even for built-in macros).
|
||||
.It Ic divert
|
||||
.It Fn divert num
|
||||
There are 10 output queues (numbered 0-9).
|
||||
At the end of processing
|
||||
.Nm
|
||||
.Nm m4
|
||||
concatenates all the queues in numerical order to produce the
|
||||
final output.
|
||||
Initially the output queue is 0.
|
||||
The
|
||||
.Ic divert
|
||||
The divert
|
||||
macro allows you to select a new output queue (an invalid argument
|
||||
passed to
|
||||
.Ic divert
|
||||
causes output to be discarded).
|
||||
passed to divert causes output to be discarded).
|
||||
.It Ic divnum
|
||||
Returns the current output queue number.
|
||||
.It Ic dnl
|
||||
Discards input characters up to and including the next newline.
|
||||
.It Ic dumpdef
|
||||
Discard input characters up to and including the next newline.
|
||||
.It Fn dumpdef name ...
|
||||
Prints the names and definitions for the named items, or for everything
|
||||
if no arguments are passed.
|
||||
.It Ic errprint
|
||||
.It Fn errprint msg
|
||||
Prints the first argument on the standard error output stream.
|
||||
.It Ic esyscmd
|
||||
.It Fn esyscmd cmd
|
||||
Passes its first argument to a shell and returns the shell's standard output.
|
||||
Note that the shell shares its standard input and standard error with
|
||||
.Nm .
|
||||
.It Ic eval
|
||||
.Nm m4 .
|
||||
.It Fn eval expr
|
||||
Computes the first argument as an arithmetic expression using 32-bit
|
||||
arithmetic.
|
||||
Operators are the standard C ternary, arithmetic, logical,
|
||||
@ -203,30 +268,46 @@ shift, relational, bitwise, and parentheses operators.
|
||||
You can specify
|
||||
octal, decimal, and hexadecimal numbers as in C.
|
||||
The second argument (if any)
|
||||
specifies the radix for the result, and the third argument (if any)
|
||||
specifies the radix for the result and the third argument (if any)
|
||||
specifies the minimum number of digits in the result.
|
||||
.It Ic expr
|
||||
.It Fn expr expr
|
||||
This is an alias for
|
||||
.Ic eval .
|
||||
.It Ic ifdef
|
||||
.It Fn format formatstring arg1 ...
|
||||
Returns
|
||||
.Fa formatstring
|
||||
with escape sequences substituted with
|
||||
.Fa arg1
|
||||
and following arguments, in a way similar to
|
||||
.Xr printf 3 .
|
||||
This built-in is only available in GNU-m4 compatibility mode, and the only
|
||||
parameters implemented are there for autoconf compatibility:
|
||||
left-padding flag, an optional field width, a maximum field width,
|
||||
*-specified field widths, and the %s and %c data type.
|
||||
.It Fn ifdef name yes no
|
||||
If the macro named by the first argument is defined then return the second
|
||||
argument, otherwise the third.
|
||||
If there is no third argument, the value is
|
||||
.Dv NULL .
|
||||
The word
|
||||
.Ic unix
|
||||
.Qq unix
|
||||
is predefined.
|
||||
.It Ic ifelse
|
||||
If the first argument matches the second argument then
|
||||
.Ic ifelse
|
||||
.It Fn ifelse a b yes ...
|
||||
If the first argument
|
||||
.Fa a
|
||||
matches the second argument
|
||||
.Fa b
|
||||
then
|
||||
.Fn ifelse
|
||||
returns
|
||||
the third argument.
|
||||
If the match fails, the three arguments are
|
||||
the third argument
|
||||
.Fa yes .
|
||||
If the match fails the three arguments are
|
||||
discarded and the next three arguments are used until there is
|
||||
zero or one arguments left, either this last argument or
|
||||
.Dv NULL
|
||||
is returned if no other matches were found.
|
||||
.It Ic include
|
||||
.It Fn include name
|
||||
Returns the contents of the file specified in the first argument.
|
||||
If the file is not found as is, look through the include path:
|
||||
first the directories specified with
|
||||
@ -234,114 +315,114 @@ first the directories specified with
|
||||
on the command line, then the environment variable
|
||||
.Ev M4PATH ,
|
||||
as a colon-separated list of directories.
|
||||
Aborts with an error message if the file cannot be included.
|
||||
.It Ic incr
|
||||
Include aborts with an error message if the file cannot be included.
|
||||
.It Fn incr arg
|
||||
Increments the argument by 1.
|
||||
The argument must be a valid numeric string.
|
||||
.It Ic index
|
||||
.It Fn index string substring
|
||||
Returns the index of the second argument in the first argument (e.g.,
|
||||
.Fn index "the quick brown fox jumped" fox
|
||||
.Ic index(the quick brown fox jumped, fox)
|
||||
returns 16).
|
||||
If the second
|
||||
argument is not found,
|
||||
.Ic index
|
||||
returns \-1.
|
||||
.It Ic indir
|
||||
Indirectly calls the macro whose name is passed as the first arguments,
|
||||
with the remaining arguments passed as first, etc.\& arguments.
|
||||
.It Ic len
|
||||
argument is not found index returns \-1.
|
||||
.It Fn indir macro arg1 ...
|
||||
Indirectly calls the macro whose name is passed as the first argument,
|
||||
with the remaining arguments passed as first, ... arguments.
|
||||
.It Fn len arg
|
||||
Returns the number of characters in the first argument.
|
||||
Extra arguments
|
||||
are ignored.
|
||||
.It Ic m4exit
|
||||
.It Fn m4exit code
|
||||
Immediately exits with the return value specified by the first argument,
|
||||
0 if none.
|
||||
.It Ic m4wrap
|
||||
.It Fn m4wrap todo
|
||||
Allows you to define what happens at the final
|
||||
.Dv EOF ,
|
||||
usually for cleanup purposes (e.g.,
|
||||
.Fn m4wrap cleanup(tempfile)
|
||||
causes the macro
|
||||
.Ic cleanup
|
||||
to be
|
||||
.Ic m4wrap("cleanup(tempfile)")
|
||||
causes the macro cleanup to be
|
||||
invoked after all other processing is done).
|
||||
.It Ic maketemp
|
||||
Translates the string
|
||||
.Dq Li XXXXX
|
||||
in the first argument with the current process
|
||||
ID leaving other characters alone.
|
||||
.Pp
|
||||
Multiple calls to
|
||||
.Fn m4wrap
|
||||
get inserted in sequence at the final
|
||||
.Dv EOF .
|
||||
.It Fn maketemp template
|
||||
Invokes
|
||||
.Xr mkstemp 3
|
||||
on the first argument, and returns the modified string.
|
||||
This can be used to create unique
|
||||
temporary file names.
|
||||
.It Ic paste
|
||||
.It Fn paste file
|
||||
Includes the contents of the file specified by the first argument without
|
||||
any macro processing.
|
||||
Aborts with an error message if the file cannot be
|
||||
included.
|
||||
.It Ic patsubst
|
||||
.It Fn patsubst string regexp replacement
|
||||
Substitutes a regular expression in a string with a replacement string.
|
||||
Usual substitution patterns apply: an ampersand
|
||||
.Pq Ql &
|
||||
.Pq Sq \&&
|
||||
is replaced by the string matching the regular expression.
|
||||
The string
|
||||
.Sq \e Ns Ar # ,
|
||||
.Sq \e# ,
|
||||
where
|
||||
.Ar #
|
||||
.Sq #
|
||||
is a digit, is replaced by the corresponding back-reference.
|
||||
.It Ic popdef
|
||||
.It Fn popdef arg ...
|
||||
Restores the
|
||||
.Ic pushdef Ns ed
|
||||
definition for each argument.
|
||||
.It Ic pushdef
|
||||
.It Fn pushdef macro def
|
||||
Takes the same arguments as
|
||||
.Ic define ,
|
||||
but it saves the definition on a
|
||||
stack for later retrieval by
|
||||
.Ic popdef .
|
||||
.It Ic regexp
|
||||
.Fn popdef .
|
||||
.It Fn regexp string regexp replacement
|
||||
Finds a regular expression in a string.
|
||||
If no further arguments are given,
|
||||
it returns the first match position or \-1 if no match.
|
||||
If a third argument
|
||||
is provided, it returns the replacement string, with sub-patterns replaced.
|
||||
.It Ic shift
|
||||
.It Fn shift arg1 ...
|
||||
Returns all but the first argument, the remaining arguments are
|
||||
quoted and pushed back with commas in between.
|
||||
The quoting
|
||||
nullifies the effect of the extra scan that will subsequently be
|
||||
performed.
|
||||
.It Ic sinclude
|
||||
.It Fn sinclude file
|
||||
Similar to
|
||||
.Ic include ,
|
||||
except it ignores any errors.
|
||||
.It Ic spaste
|
||||
.It Fn spaste file
|
||||
Similar to
|
||||
.Ic paste ,
|
||||
.Fn paste ,
|
||||
except it ignores any errors.
|
||||
.It Ic substr
|
||||
.It Fn substr string offset length
|
||||
Returns a substring of the first argument starting at the offset specified
|
||||
by the second argument and the length specified by the third argument.
|
||||
If no third argument is present it returns the rest of the string.
|
||||
.It Ic syscmd
|
||||
.It Fn syscmd cmd
|
||||
Passes the first argument to the shell.
|
||||
Nothing is returned.
|
||||
.It Ic sysval
|
||||
Returns the return value from the last
|
||||
.Ic syscmd .
|
||||
.It Ic traceon
|
||||
.It Fn traceon arg ...
|
||||
Enables tracing of macro expansions for the given arguments, or for all
|
||||
macros if no argument is given.
|
||||
.It Ic traceoff
|
||||
.It Fn traceoff arg ...
|
||||
Disables tracing of macro expansions for the given arguments, or for all
|
||||
macros if no argument is given.
|
||||
.It Ic translit
|
||||
.It Fn translit string mapfrom mapto
|
||||
Transliterate the characters in the first argument from the set
|
||||
given by the second argument to the set given by the third.
|
||||
You cannot use
|
||||
.Xr tr 1
|
||||
style abbreviations.
|
||||
.It Ic undefine
|
||||
.It Fn undefine name1 ...
|
||||
Removes the definition for the macros specified by its arguments.
|
||||
.It Ic undivert
|
||||
.It Fn undivert arg ...
|
||||
Flushes the named output queues (or all queues if no arguments).
|
||||
.It Ic unix
|
||||
A pre-defined macro for testing the OS platform.
|
||||
@ -350,37 +431,20 @@ Returns the current file's line number.
|
||||
.It Ic __file__
|
||||
Returns the current file's name.
|
||||
.El
|
||||
.Sh EXIT STATUS
|
||||
.Ex -std
|
||||
.Pp
|
||||
The
|
||||
.Ic m4exit
|
||||
macro may be used to change the exit status from the input file.
|
||||
.Sh COMPATIBILITY
|
||||
.Sh STANDARDS
|
||||
The
|
||||
.Nm
|
||||
utility follows the
|
||||
.St -susv2 ,
|
||||
along with a few extensions taken from GNU-m4.
|
||||
Flags
|
||||
.Fl I , d ,
|
||||
and
|
||||
.Fl t
|
||||
are non-standard.
|
||||
utility is compliant with the
|
||||
.St -p1003.1-2008
|
||||
specification.
|
||||
.Pp
|
||||
The output format of tracing and of
|
||||
.Ic dumpdef
|
||||
are not specified in any standard,
|
||||
are likely to change and should not be relied upon.
|
||||
The current format of tracing is closely modeled on GNU-m4,
|
||||
to allow
|
||||
.Nm autoconf
|
||||
to work.
|
||||
.Pp
|
||||
For portability, one should not use the macros
|
||||
The flags
|
||||
.Op Fl dgIot
|
||||
and the macros
|
||||
.Ic builtin ,
|
||||
.Ic esyscmd ,
|
||||
.Ic expr ,
|
||||
.Ic format ,
|
||||
.Ic indir ,
|
||||
.Ic paste ,
|
||||
.Ic patsubst ,
|
||||
@ -389,33 +453,43 @@ For portability, one should not use the macros
|
||||
.Ic unix ,
|
||||
.Ic __line__ ,
|
||||
and
|
||||
.Ic __file__ .
|
||||
.Ic __file__
|
||||
are extensions to that specification.
|
||||
.Pp
|
||||
The output format of tracing and of
|
||||
.Ic dumpdef
|
||||
are not specified in any standard,
|
||||
are likely to change and should not be relied upon.
|
||||
The current format of tracing is closely modelled on
|
||||
.Nm gnu-m4 ,
|
||||
to allow
|
||||
.Nm autoconf
|
||||
to work.
|
||||
.Pp
|
||||
The built-ins
|
||||
.Ic pushdef
|
||||
and
|
||||
.Ic popdef
|
||||
handle macro definitions as a stack.
|
||||
However,
|
||||
.Ic define
|
||||
interacts with the stack in an undefined way.
|
||||
In this implementation,
|
||||
.Ic define
|
||||
replaces the top-most definition only.
|
||||
Other implementations may erase all definitions on the stack instead.
|
||||
.Pp
|
||||
All built-ins do expand without arguments in many other
|
||||
.Nm
|
||||
implementations.
|
||||
.Nm m4 .
|
||||
.Pp
|
||||
Many other
|
||||
.Nm
|
||||
implementations have dire size limitations with respect to buffer sizes.
|
||||
.Sh STANDARDS
|
||||
The
|
||||
.Nm
|
||||
utility
|
||||
conforms to
|
||||
.St -p1003.1-2001 .
|
||||
.Sh HISTORY
|
||||
An
|
||||
.Nm
|
||||
command appeared in PWB UNIX.
|
||||
have dire size limitations with respect to buffer sizes.
|
||||
.Sh AUTHORS
|
||||
.An -nosplit
|
||||
.An Ozan Yigit Aq oz@sis.yorku.ca
|
||||
and
|
||||
.An Richard A. O'Keefe Aq ok@goanna.cs.rmit.OZ.AU .
|
||||
.Pp
|
||||
GNU-m4 compatibility extensions by
|
||||
.An Marc Espie Aq espie@cvs.openbsd.org .
|
||||
.Sh BUGS
|
||||
The
|
||||
.Nm
|
||||
utility does not recognize multibyte characters.
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: main.c,v 1.53 2002/04/26 16:15:16 espie Exp $ */
|
||||
/* $OpenBSD: main.c,v 1.80 2011/09/27 07:24:02 espie Exp $ */
|
||||
/* $NetBSD: main.c,v 1.12 1997/02/08 23:54:49 cgd Exp $ */
|
||||
|
||||
/*-
|
||||
@ -16,7 +16,7 @@
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
@ -33,73 +33,59 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char copyright[] =
|
||||
"@(#) Copyright (c) 1989, 1993\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93";
|
||||
#else
|
||||
#if 0
|
||||
static char rcsid[] = "$OpenBSD: main.c,v 1.53 2002/04/26 16:15:16 espie Exp $";
|
||||
#endif
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* main.c
|
||||
* Facility: m4 macro processor
|
||||
* by: oz
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <err.h>
|
||||
#include <locale.h>
|
||||
#include <ohash.h>
|
||||
#include "mdef.h"
|
||||
#include "stdd.h"
|
||||
#include "extern.h"
|
||||
#include "pathnames.h"
|
||||
|
||||
ndptr hashtab[HASHSIZE]; /* hash table for macros etc. */
|
||||
stae *mstack; /* stack of m4 machine */
|
||||
char *sstack; /* shadow stack, for string space extension */
|
||||
stae *mstack; /* stack of m4 machine */
|
||||
char *sstack; /* shadow stack, for string space extension */
|
||||
static size_t STACKMAX; /* current maximum size of stack */
|
||||
int sp; /* current m4 stack pointer */
|
||||
int fp; /* m4 call frame pointer */
|
||||
int sp; /* current m4 stack pointer */
|
||||
int fp; /* m4 call frame pointer */
|
||||
struct input_file infile[MAXINP];/* input file stack (0=stdin) */
|
||||
char *inname[MAXINP]; /* names of these input files */
|
||||
int inlineno[MAXINP]; /* current number in each input file */
|
||||
FILE **outfile; /* diversion array(0=bitbucket)*/
|
||||
int maxout;
|
||||
FILE *active; /* active output file pointer */
|
||||
int ilevel = 0; /* input file stack pointer */
|
||||
int oindex = 0; /* diversion index.. */
|
||||
char null[] = ""; /* as it says.. just a null.. */
|
||||
const char *m4wraps = ""; /* m4wrap string default.. */
|
||||
int ilevel = 0; /* input file stack pointer */
|
||||
int oindex = 0; /* diversion index.. */
|
||||
const char *null = ""; /* as it says.. just a null.. */
|
||||
char **m4wraps = NULL; /* m4wraps array. */
|
||||
int maxwraps = 0; /* size of m4wraps array */
|
||||
int wrapindex = 0; /* current offset in m4wraps */
|
||||
char lquote[MAXCCHARS+1] = {LQUOTE}; /* left quote character (`) */
|
||||
char rquote[MAXCCHARS+1] = {RQUOTE}; /* right quote character (') */
|
||||
char scommt[MAXCCHARS+1] = {SCOMMT}; /* start character for comment */
|
||||
char ecommt[MAXCCHARS+1] = {ECOMMT}; /* end character for comment */
|
||||
int synccpp; /* Line synchronisation for C preprocessor */
|
||||
int synch_lines = 0; /* line synchronisation for C preprocessor */
|
||||
int prefix_builtins = 0; /* -P option to prefix builtin keywords */
|
||||
|
||||
static const struct keyblk keywrds[] = { /* m4 keywords to be installed */
|
||||
struct keyblk {
|
||||
const char *knam; /* keyword name */
|
||||
int ktyp; /* keyword type */
|
||||
};
|
||||
|
||||
struct keyblk keywrds[] = { /* m4 keywords to be installed */
|
||||
{ "include", INCLTYPE },
|
||||
{ "sinclude", SINCTYPE },
|
||||
{ "define", DEFITYPE },
|
||||
@ -120,7 +106,7 @@ static const struct keyblk keywrds[] = { /* m4 keywords to be installed */
|
||||
#ifdef EXTENDED
|
||||
{ "paste", PASTTYPE },
|
||||
{ "spaste", SPASTYPE },
|
||||
/* Newer extensions, needed to handle gnu-m4 scripts */
|
||||
/* Newer extensions, needed to handle gnu-m4 scripts */
|
||||
{ "indir", INDIRTYPE},
|
||||
{ "builtin", BUILTINTYPE},
|
||||
{ "patsubst", PATSTYPE},
|
||||
@ -138,6 +124,7 @@ static const struct keyblk keywrds[] = { /* m4 keywords to be installed */
|
||||
{ "undivert", UNDVTYPE | NOARGS },
|
||||
{ "divnum", DIVNTYPE | NOARGS },
|
||||
{ "maketemp", MKTMTYPE },
|
||||
{ "mkstemp", MKTMTYPE },
|
||||
{ "errprint", ERRPTYPE | NOARGS },
|
||||
{ "m4wrap", M4WRTYPE | NOARGS },
|
||||
{ "m4exit", EXITTYPE | NOARGS },
|
||||
@ -170,43 +157,41 @@ static void macro(void);
|
||||
static void initkwds(void);
|
||||
static ndptr inspect(int, char *);
|
||||
static int do_look_ahead(int, const char *);
|
||||
static void reallyoutputstr(const char *);
|
||||
static void reallyputchar(int);
|
||||
|
||||
static void enlarge_stack(void);
|
||||
|
||||
int main(int, char *[]);
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
int n;
|
||||
int rval;
|
||||
char *p;
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
|
||||
traceout = stderr;
|
||||
|
||||
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
|
||||
signal(SIGINT, onintr);
|
||||
|
||||
initkwds();
|
||||
init_macros();
|
||||
initspaces();
|
||||
STACKMAX = INITSTACKMAX;
|
||||
|
||||
mstack = (stae *)xalloc(sizeof(stae) * STACKMAX);
|
||||
sstack = (char *)xalloc(STACKMAX);
|
||||
mstack = (stae *)xalloc(sizeof(stae) * STACKMAX, NULL);
|
||||
sstack = (char *)xalloc(STACKMAX, NULL);
|
||||
|
||||
maxout = 0;
|
||||
outfile = NULL;
|
||||
resizedivs(MAXOUT);
|
||||
|
||||
while ((c = getopt(argc, argv, "gst:d:D:U:o:I:")) != -1)
|
||||
while ((c = getopt(argc, argv, "gst:d:D:U:o:I:P")) != -1)
|
||||
switch(c) {
|
||||
|
||||
case 'D': /* define something..*/
|
||||
for (p = optarg; *p; p++)
|
||||
if (*p == '=')
|
||||
break;
|
||||
if (p == optarg)
|
||||
errx(1, "null variable cannot be defined");
|
||||
if (*p)
|
||||
*p++ = EOS;
|
||||
dodefine(optarg, p);
|
||||
@ -214,8 +199,11 @@ main(int argc, char *argv[])
|
||||
case 'I':
|
||||
addtoincludepath(optarg);
|
||||
break;
|
||||
case 'P':
|
||||
prefix_builtins = 1;
|
||||
break;
|
||||
case 'U': /* undefine... */
|
||||
remhash(optarg, TOP);
|
||||
macro_popdef(optarg);
|
||||
break;
|
||||
case 'g':
|
||||
mimic_gnu = 1;
|
||||
@ -224,7 +212,7 @@ main(int argc, char *argv[])
|
||||
set_trace_flags(optarg);
|
||||
break;
|
||||
case 's':
|
||||
synccpp = 1;
|
||||
synch_lines = 1;
|
||||
break;
|
||||
case 't':
|
||||
mark_traced(optarg, 1);
|
||||
@ -233,51 +221,55 @@ main(int argc, char *argv[])
|
||||
trace_file(optarg);
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
rval = 0;
|
||||
initkwds();
|
||||
if (mimic_gnu)
|
||||
setup_builtin("format", FORMATTYPE);
|
||||
|
||||
active = stdout; /* default active output */
|
||||
bbase[0] = bufbase;
|
||||
if (!argc) {
|
||||
sp = -1; /* stack pointer initialized */
|
||||
fp = 0; /* frame pointer initialized */
|
||||
sp = -1; /* stack pointer initialized */
|
||||
fp = 0; /* frame pointer initialized */
|
||||
set_input(infile+0, stdin, "stdin");
|
||||
/* default input (naturally) */
|
||||
if ((inname[0] = strdup("-")) == NULL)
|
||||
err(1, NULL);
|
||||
inlineno[0] = 1;
|
||||
emitline();
|
||||
macro();
|
||||
} else
|
||||
for (; argc--; ++argv) {
|
||||
p = *argv;
|
||||
if (p[0] == '-' && p[1] == EOS)
|
||||
set_input(infile, stdin, "stdin");
|
||||
else if (fopen_trypath(infile, p) == NULL) {
|
||||
warn("%s", p);
|
||||
rval = 1;
|
||||
continue;
|
||||
}
|
||||
else if (fopen_trypath(infile, p) == NULL)
|
||||
err(1, "%s", p);
|
||||
sp = -1;
|
||||
fp = 0;
|
||||
if ((inname[0] = strdup(p)) == NULL)
|
||||
err(1, NULL);
|
||||
inlineno[0] = 1;
|
||||
emitline();
|
||||
macro();
|
||||
release_input(infile);
|
||||
release_input(infile);
|
||||
}
|
||||
|
||||
if (*m4wraps) { /* anything for rundown ?? */
|
||||
if (wrapindex) {
|
||||
int i;
|
||||
|
||||
ilevel = 0; /* in case m4wrap includes.. */
|
||||
bufbase = bp = buf; /* use the entire buffer */
|
||||
pbstr(m4wraps); /* user-defined wrapup act */
|
||||
macro(); /* last will and testament */
|
||||
if (mimic_gnu) {
|
||||
while (wrapindex != 0) {
|
||||
for (i = 0; i < wrapindex; i++)
|
||||
pbstr(m4wraps[i]);
|
||||
wrapindex =0;
|
||||
macro();
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < wrapindex; i++) {
|
||||
pbstr(m4wraps[i]);
|
||||
macro();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (active != stdout)
|
||||
@ -290,7 +282,7 @@ main(int argc, char *argv[])
|
||||
(void) fclose(outfile[0]);
|
||||
}
|
||||
|
||||
exit(rval);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -310,17 +302,17 @@ do_look_ahead(int t, const char *token)
|
||||
for (i = 1; *++token; i++) {
|
||||
t = gpbc();
|
||||
if (t == EOF || (unsigned char)t != (unsigned char)*token) {
|
||||
putback(t);
|
||||
pushback(t);
|
||||
while (--i)
|
||||
putback(*--token);
|
||||
pushback(*--token);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define LOOK_AHEAD(t, token) (t != EOF && \
|
||||
(unsigned char)(t)==(unsigned char)(token)[0] && \
|
||||
#define LOOK_AHEAD(t, token) (t != EOF && \
|
||||
(unsigned char)(t)==(unsigned char)(token)[0] && \
|
||||
do_look_ahead(t,token))
|
||||
|
||||
/*
|
||||
@ -336,61 +328,8 @@ macro(void)
|
||||
|
||||
cycle {
|
||||
t = gpbc();
|
||||
if (t == '_' || isalpha(t)) {
|
||||
p = inspect(t, token);
|
||||
if (p != nil)
|
||||
putback(l = gpbc());
|
||||
if (p == nil || (l != LPAREN &&
|
||||
(p->type & NEEDARGS) != 0))
|
||||
outputstr(token);
|
||||
else {
|
||||
/*
|
||||
* real thing.. First build a call frame:
|
||||
*/
|
||||
pushf(fp); /* previous call frm */
|
||||
pushf(p->type); /* type of the call */
|
||||
pushf(0); /* parenthesis level */
|
||||
fp = sp; /* new frame pointer */
|
||||
/*
|
||||
* now push the string arguments:
|
||||
*/
|
||||
pushs1(p->defn); /* defn string */
|
||||
pushs1(p->name); /* macro name */
|
||||
pushs(ep); /* start next..*/
|
||||
|
||||
if (l != LPAREN && PARLEV == 0) {
|
||||
/* no bracks */
|
||||
chrsave(EOS);
|
||||
|
||||
if ((uintptr_t)sp == STACKMAX)
|
||||
errx(1, "internal stack overflow");
|
||||
eval((const char **) mstack+fp+1, 2,
|
||||
CALTYP);
|
||||
|
||||
ep = PREVEP; /* flush strspace */
|
||||
sp = PREVSP; /* previous sp.. */
|
||||
fp = PREVFP; /* rewind stack...*/
|
||||
}
|
||||
}
|
||||
} else if (t == EOF) {
|
||||
if (sp > -1) {
|
||||
warnx( "unexpected end of input, unclosed parenthesis:");
|
||||
dump_stack(paren, PARLEV);
|
||||
exit(1);
|
||||
}
|
||||
if (ilevel <= 0)
|
||||
break; /* all done thanks.. */
|
||||
release_input(infile+ilevel--);
|
||||
free(inname[ilevel+1]);
|
||||
bufbase = bbase[ilevel];
|
||||
emitline();
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* non-alpha token possibly seen..
|
||||
* [the order of else if .. stmts is important.]
|
||||
*/
|
||||
else if (LOOK_AHEAD(t,lquote)) { /* strip quotes */
|
||||
if (LOOK_AHEAD(t,lquote)) { /* strip quotes */
|
||||
nlpar = 0;
|
||||
record(quotes, nlpar++);
|
||||
/*
|
||||
@ -416,32 +355,77 @@ macro(void)
|
||||
} else {
|
||||
if (nlpar > 0) {
|
||||
if (sp < 0)
|
||||
putc(l, active);
|
||||
reallyputchar(l);
|
||||
else
|
||||
CHRSAVE(l);
|
||||
}
|
||||
}
|
||||
}
|
||||
while (nlpar != 0);
|
||||
}
|
||||
|
||||
else if (sp < 0 && LOOK_AHEAD(t, scommt)) {
|
||||
fputs(scommt, active);
|
||||
} else if (sp < 0 && LOOK_AHEAD(t, scommt)) {
|
||||
reallyoutputstr(scommt);
|
||||
|
||||
for(;;) {
|
||||
t = gpbc();
|
||||
if (LOOK_AHEAD(t, ecommt)) {
|
||||
fputs(ecommt, active);
|
||||
reallyoutputstr(ecommt);
|
||||
break;
|
||||
}
|
||||
if (t == EOF)
|
||||
break;
|
||||
putc(t, active);
|
||||
reallyputchar(t);
|
||||
}
|
||||
}
|
||||
} else if (t == '_' || isalpha(t)) {
|
||||
p = inspect(t, token);
|
||||
if (p != NULL)
|
||||
pushback(l = gpbc());
|
||||
if (p == NULL || (l != LPAREN &&
|
||||
(macro_getdef(p)->type & NEEDARGS) != 0))
|
||||
outputstr(token);
|
||||
else {
|
||||
/*
|
||||
* real thing.. First build a call frame:
|
||||
*/
|
||||
pushf(fp); /* previous call frm */
|
||||
pushf(macro_getdef(p)->type); /* type of the call */
|
||||
pushf(is_traced(p));
|
||||
pushf(0); /* parenthesis level */
|
||||
fp = sp; /* new frame pointer */
|
||||
/*
|
||||
* now push the string arguments:
|
||||
*/
|
||||
pushs1(macro_getdef(p)->defn); /* defn string */
|
||||
pushs1((char *)macro_name(p)); /* macro name */
|
||||
pushs(ep); /* start next..*/
|
||||
|
||||
else if (sp < 0) { /* not in a macro at all */
|
||||
putc(t, active); /* output directly.. */
|
||||
if (l != LPAREN && PARLEV == 0) {
|
||||
/* no bracks */
|
||||
chrsave(EOS);
|
||||
|
||||
if (sp == (int)STACKMAX)
|
||||
errx(1, "internal stack overflow");
|
||||
eval((const char **) mstack+fp+1, 2,
|
||||
CALTYP, TRACESTATUS);
|
||||
|
||||
ep = PREVEP; /* flush strspace */
|
||||
sp = PREVSP; /* previous sp.. */
|
||||
fp = PREVFP; /* rewind stack...*/
|
||||
}
|
||||
}
|
||||
} else if (t == EOF) {
|
||||
if (sp > -1 && ilevel <= 0) {
|
||||
warnx( "unexpected end of input, unclosed parenthesis:");
|
||||
dump_stack(paren, PARLEV);
|
||||
exit(1);
|
||||
}
|
||||
if (ilevel <= 0)
|
||||
break; /* all done thanks.. */
|
||||
release_input(infile+ilevel--);
|
||||
emit_synchline();
|
||||
bufbase = bbase[ilevel];
|
||||
continue;
|
||||
} else if (sp < 0) { /* not in a macro at all */
|
||||
reallyputchar(t); /* output directly.. */
|
||||
}
|
||||
|
||||
else switch(t) {
|
||||
@ -449,9 +433,10 @@ macro(void)
|
||||
case LPAREN:
|
||||
if (PARLEV > 0)
|
||||
chrsave(t);
|
||||
while (isspace(l = gpbc()))
|
||||
; /* skip blank, tab, nl.. */
|
||||
putback(l);
|
||||
while (isspace(l = gpbc())) /* skip blank, tab, nl.. */
|
||||
if (PARLEV > 0)
|
||||
chrsave(l);
|
||||
pushback(l);
|
||||
record(paren, PARLEV++);
|
||||
break;
|
||||
|
||||
@ -461,11 +446,11 @@ macro(void)
|
||||
else { /* end of argument list */
|
||||
chrsave(EOS);
|
||||
|
||||
if ((uintptr_t)sp == STACKMAX)
|
||||
if (sp == (int)STACKMAX)
|
||||
errx(1, "internal stack overflow");
|
||||
|
||||
eval((const char **) mstack+fp+1, sp-fp,
|
||||
CALTYP);
|
||||
CALTYP, TRACESTATUS);
|
||||
|
||||
ep = PREVEP; /* flush strspace */
|
||||
sp = PREVSP; /* previous sp.. */
|
||||
@ -478,7 +463,7 @@ macro(void)
|
||||
chrsave(EOS); /* new argument */
|
||||
while (isspace(l = gpbc()))
|
||||
;
|
||||
putback(l);
|
||||
pushback(l);
|
||||
pushs(ep);
|
||||
} else
|
||||
chrsave(t);
|
||||
@ -486,14 +471,14 @@ macro(void)
|
||||
|
||||
default:
|
||||
if (LOOK_AHEAD(t, scommt)) {
|
||||
char *pc;
|
||||
for (pc = scommt; *pc; pc++)
|
||||
chrsave(*pc);
|
||||
char *cp;
|
||||
for (cp = scommt; *cp; cp++)
|
||||
chrsave(*cp);
|
||||
for(;;) {
|
||||
t = gpbc();
|
||||
if (LOOK_AHEAD(t, ecommt)) {
|
||||
for (pc = ecommt; *pc; pc++)
|
||||
chrsave(*pc);
|
||||
for (cp = ecommt; *cp; cp++)
|
||||
chrsave(*cp);
|
||||
break;
|
||||
}
|
||||
if (t == EOF)
|
||||
@ -514,17 +499,43 @@ void
|
||||
outputstr(const char *s)
|
||||
{
|
||||
if (sp < 0)
|
||||
while (*s)
|
||||
putc(*s++, active);
|
||||
reallyoutputstr(s);
|
||||
else
|
||||
while (*s)
|
||||
CHRSAVE(*s++);
|
||||
}
|
||||
|
||||
void
|
||||
reallyoutputstr(const char *s)
|
||||
{
|
||||
if (synch_lines) {
|
||||
while (*s) {
|
||||
fputc(*s, active);
|
||||
if (*s++ == '\n') {
|
||||
infile[ilevel].synch_lineno++;
|
||||
if (infile[ilevel].synch_lineno !=
|
||||
infile[ilevel].lineno)
|
||||
do_emit_synchline();
|
||||
}
|
||||
}
|
||||
} else
|
||||
fputs(s, active);
|
||||
}
|
||||
|
||||
void
|
||||
reallyputchar(int c)
|
||||
{
|
||||
putc(c, active);
|
||||
if (synch_lines && c == '\n') {
|
||||
infile[ilevel].synch_lineno++;
|
||||
if (infile[ilevel].synch_lineno != infile[ilevel].lineno)
|
||||
do_emit_synchline();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* build an input token..
|
||||
* consider only those starting with _ or A-Za-z. This is a
|
||||
* combo with lookup to speed things up.
|
||||
* consider only those starting with _ or A-Za-z.
|
||||
*/
|
||||
static ndptr
|
||||
inspect(int c, char *tp)
|
||||
@ -532,14 +543,13 @@ inspect(int c, char *tp)
|
||||
char *name = tp;
|
||||
char *etp = tp+MAXTOK;
|
||||
ndptr p;
|
||||
unsigned int h;
|
||||
|
||||
h = *tp++ = c;
|
||||
*tp++ = c;
|
||||
|
||||
while ((isalnum(c = gpbc()) || c == '_') && tp < etp)
|
||||
h = (h << 5) + h + (*tp++ = c);
|
||||
*tp++ = c;
|
||||
if (c != EOF)
|
||||
PUTBACK(c);
|
||||
PUSHBACK(c);
|
||||
*tp = EOS;
|
||||
/* token is too long, it won't match anything, but it can still
|
||||
* be output. */
|
||||
@ -547,17 +557,19 @@ inspect(int c, char *tp)
|
||||
outputstr(name);
|
||||
while (isalnum(c = gpbc()) || c == '_') {
|
||||
if (sp < 0)
|
||||
putc(c, active);
|
||||
reallyputchar(c);
|
||||
else
|
||||
CHRSAVE(c);
|
||||
}
|
||||
*name = EOS;
|
||||
return nil;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (p = hashtab[h % HASHSIZE]; p != nil; p = p->nxtptr)
|
||||
if (h == p->hv && STREQ(name, p->name))
|
||||
break;
|
||||
p = ohash_find(¯os, ohash_qlookupi(¯os, name, (const char **)&tp));
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
if (macro_getdef(p) == NULL)
|
||||
return NULL;
|
||||
return p;
|
||||
}
|
||||
|
||||
@ -571,47 +583,17 @@ inspect(int c, char *tp)
|
||||
static void
|
||||
initkwds(void)
|
||||
{
|
||||
size_t i;
|
||||
unsigned int h;
|
||||
ndptr p;
|
||||
unsigned int type;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAXKEYS; i++) {
|
||||
h = hash(keywrds[i].knam);
|
||||
p = (ndptr) xalloc(sizeof(struct ndblock));
|
||||
p->nxtptr = hashtab[h % HASHSIZE];
|
||||
hashtab[h % HASHSIZE] = p;
|
||||
p->name = xstrdup(keywrds[i].knam);
|
||||
p->defn = null;
|
||||
p->hv = h;
|
||||
p->type = keywrds[i].ktyp & TYPEMASK;
|
||||
for (i = 0; i < (int)MAXKEYS; i++) {
|
||||
type = keywrds[i].ktyp & TYPEMASK;
|
||||
if ((keywrds[i].ktyp & NOARGS) == 0)
|
||||
p->type |= NEEDARGS;
|
||||
type |= NEEDARGS;
|
||||
setup_builtin(keywrds[i].knam, type);
|
||||
}
|
||||
}
|
||||
|
||||
/* Look up a builtin type, even if overridden by the user */
|
||||
int
|
||||
builtin_type(const char *key)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i != MAXKEYS; i++)
|
||||
if (STREQ(keywrds[i].knam, key))
|
||||
return keywrds[i].ktyp;
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *
|
||||
builtin_realname(int n)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i != MAXKEYS; i++)
|
||||
if (((keywrds[i].ktyp ^ n) & TYPEMASK) == 0)
|
||||
return keywrds[i].knam;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
record(struct position *t, int lev)
|
||||
{
|
||||
@ -640,20 +622,11 @@ dump_stack(struct position *t, int lev)
|
||||
static void
|
||||
enlarge_stack(void)
|
||||
{
|
||||
STACKMAX *= 2;
|
||||
mstack = realloc(mstack, sizeof(stae) * STACKMAX);
|
||||
sstack = realloc(sstack, STACKMAX);
|
||||
if (mstack == NULL || sstack == NULL)
|
||||
errx(1, "Evaluation stack overflow (%lu)",
|
||||
(unsigned long)STACKMAX);
|
||||
}
|
||||
|
||||
/* Emit preprocessor #line directive if -s option used. */
|
||||
void
|
||||
emitline(void)
|
||||
{
|
||||
|
||||
if (synccpp)
|
||||
fprintf(active, "#line %d \"%s\"\n", inlineno[ilevel],
|
||||
inname[ilevel]);
|
||||
STACKMAX += STACKMAX/2;
|
||||
mstack = xrealloc(mstack, sizeof(stae) * STACKMAX,
|
||||
"Evaluation stack overflow (%lu)",
|
||||
(unsigned long)STACKMAX);
|
||||
sstack = xrealloc(sstack, STACKMAX,
|
||||
"Evaluation stack overflow (%lu)",
|
||||
(unsigned long)STACKMAX);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: mdef.h,v 1.21 2001/09/27 11:40:33 espie Exp $ */
|
||||
/* $OpenBSD: mdef.h,v 1.31 2011/09/27 07:24:02 espie Exp $ */
|
||||
/* $NetBSD: mdef.h,v 1.7 1996/01/13 23:25:27 pk Exp $ */
|
||||
|
||||
/*
|
||||
@ -16,7 +16,7 @@
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
@ -36,6 +36,12 @@
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define UNUSED __attribute__((__unused__))
|
||||
#else
|
||||
# define UNUSED
|
||||
#endif
|
||||
|
||||
#define MACRTYPE 1
|
||||
#define DEFITYPE 2
|
||||
#define EXPRTYPE 3
|
||||
@ -79,7 +85,9 @@
|
||||
#define ESYSCMDTYPE 41
|
||||
#define TRACEONTYPE 42
|
||||
#define TRACEOFFTYPE 43
|
||||
#define FORMATTYPE 44
|
||||
|
||||
#define BUILTIN_MARKER "__builtin_"
|
||||
|
||||
#define TYPEMASK 63 /* Keep bits really corresponding to a type. */
|
||||
#define RECDEF 256 /* Pure recursive def, don't expand it */
|
||||
@ -108,13 +116,12 @@
|
||||
*/
|
||||
|
||||
#define EOS '\0'
|
||||
#define MAXINP 10 /* maximum include files */
|
||||
#define MAXOUT 10 /* maximum # of diversions */
|
||||
#define MAXINP 10 /* maximum include files */
|
||||
#define MAXOUT 10 /* maximum # of diversions */
|
||||
#define BUFSIZE 4096 /* starting size of pushback buffer */
|
||||
#define INITSTACKMAX 4096 /* starting size of call stack */
|
||||
#define INITSTACKMAX 4096 /* starting size of call stack */
|
||||
#define STRSPMAX 4096 /* starting size of string space */
|
||||
#define MAXTOK 512 /* maximum chars in a tokn */
|
||||
#define HASHSIZE 199 /* maximum size of hashtab */
|
||||
#define MAXTOK 512 /* maximum chars in a tokn */
|
||||
#define MAXCCHARS 5 /* max size of comment/quote delim */
|
||||
|
||||
#define ALL 1
|
||||
@ -130,31 +137,31 @@
|
||||
|
||||
typedef struct ndblock *ndptr;
|
||||
|
||||
struct ndblock { /* hastable structure */
|
||||
char *name; /* entry name.. */
|
||||
struct macro_definition {
|
||||
struct macro_definition *next;
|
||||
char *defn; /* definition.. */
|
||||
unsigned int type; /* type of the entry.. */
|
||||
unsigned int hv; /* hash function value.. */
|
||||
ndptr nxtptr; /* link to next entry.. */
|
||||
};
|
||||
|
||||
#define nil ((ndptr) 0)
|
||||
|
||||
struct keyblk {
|
||||
const char *knam; /* keyword name */
|
||||
int ktyp; /* keyword type */
|
||||
struct ndblock { /* hashtable structure */
|
||||
unsigned int builtin_type;
|
||||
unsigned int trace_flags;
|
||||
struct macro_definition *d;
|
||||
char name[1]; /* entry name.. */
|
||||
};
|
||||
|
||||
typedef union { /* stack structure */
|
||||
int sfra; /* frame entry */
|
||||
char *sstr; /* string entry */
|
||||
char *sstr; /* string entry */
|
||||
} stae;
|
||||
|
||||
struct input_file {
|
||||
FILE *file;
|
||||
char *name;
|
||||
unsigned long lineno;
|
||||
int c;
|
||||
FILE *file;
|
||||
char *name;
|
||||
unsigned long lineno;
|
||||
unsigned long synch_lineno; /* used for -s */
|
||||
int c;
|
||||
};
|
||||
|
||||
#define CURRENT_NAME (infile[ilevel].name)
|
||||
@ -162,31 +169,33 @@ struct input_file {
|
||||
/*
|
||||
* macros for readibility and/or speed
|
||||
*
|
||||
* gpbc() - get a possibly pushed-back character
|
||||
* pushf() - push a call frame entry onto stack
|
||||
* pushs() - push a string pointer onto stack
|
||||
*/
|
||||
#define pushf(x) \
|
||||
do { \
|
||||
if ((uintptr_t)++sp == STACKMAX) \
|
||||
enlarge_stack(); \
|
||||
mstack[sp].sfra = (x); \
|
||||
sstack[sp] = 0; \
|
||||
#define gpbc() (bp > bufbase) ? *--bp : obtain_char(infile+ilevel)
|
||||
#define pushf(x) \
|
||||
do { \
|
||||
if (++sp == (int)STACKMAX) \
|
||||
enlarge_stack();\
|
||||
mstack[sp].sfra = (x); \
|
||||
sstack[sp] = 0; \
|
||||
} while (0)
|
||||
|
||||
#define pushs(x) \
|
||||
do { \
|
||||
if ((uintptr_t)++sp == STACKMAX) \
|
||||
enlarge_stack(); \
|
||||
mstack[sp].sstr = (x); \
|
||||
sstack[sp] = 1; \
|
||||
#define pushs(x) \
|
||||
do { \
|
||||
if (++sp == (int)STACKMAX) \
|
||||
enlarge_stack();\
|
||||
mstack[sp].sstr = (x); \
|
||||
sstack[sp] = 1; \
|
||||
} while (0)
|
||||
|
||||
#define pushs1(x) \
|
||||
do { \
|
||||
if ((uintptr_t)++sp == STACKMAX) \
|
||||
enlarge_stack(); \
|
||||
mstack[sp].sstr = (x); \
|
||||
sstack[sp] = 0; \
|
||||
#define pushs1(x) \
|
||||
do { \
|
||||
if (++sp == (int)STACKMAX) \
|
||||
enlarge_stack();\
|
||||
mstack[sp].sstr = (x); \
|
||||
sstack[sp] = 0; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
@ -195,25 +204,26 @@ struct input_file {
|
||||
* +-------+ +-----+
|
||||
* | arg 3 ----------------------->| str |
|
||||
* +-------+ | . |
|
||||
* | arg 2 ---PREVEP-----+ .
|
||||
* | arg 2 ---PREVEP-----+ .
|
||||
* +-------+ |
|
||||
* . | | |
|
||||
* +-------+ | +-----+
|
||||
* +-------+ | +-----+
|
||||
* | plev | PARLEV +-------->| str |
|
||||
* +-------+ | . |
|
||||
* | type | CALTYP .
|
||||
* +-------+
|
||||
* | prcf ---PREVFP--+
|
||||
* +-------+ |
|
||||
* +-------+ |
|
||||
* | . | PREVSP |
|
||||
* . |
|
||||
* . |
|
||||
* +-------+ |
|
||||
* | <----------+
|
||||
* +-------+
|
||||
*
|
||||
*/
|
||||
#define PARLEV (mstack[fp].sfra)
|
||||
#define CALTYP (mstack[fp-1].sfra)
|
||||
#define CALTYP (mstack[fp-2].sfra)
|
||||
#define TRACESTATUS (mstack[fp-1].sfra)
|
||||
#define PREVEP (mstack[fp+3].sstr)
|
||||
#define PREVSP (fp-3)
|
||||
#define PREVFP (mstack[fp-2].sfra)
|
||||
#define PREVSP (fp-4)
|
||||
#define PREVFP (mstack[fp-3].sfra)
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: misc.c,v 1.27 2002/04/26 16:15:16 espie Exp $ */
|
||||
/* $OpenBSD: misc.c,v 1.42 2010/09/07 19:58:09 marco Exp $ */
|
||||
/* $NetBSD: misc.c,v 1.6 1995/09/28 05:37:41 tls Exp $ */
|
||||
|
||||
/*
|
||||
@ -16,7 +16,7 @@
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
@ -32,23 +32,13 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)misc.c 8.1 (Berkeley) 6/6/93";
|
||||
#else
|
||||
#if 0
|
||||
static char rcsid[] = "$OpenBSD: misc.c,v 1.27 2002/04/26 16:15:16 espie Exp $";
|
||||
#endif
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@ -66,11 +56,11 @@ char *endest; /* end of string space */
|
||||
static size_t strsize = STRSPMAX;
|
||||
static size_t bufsize = BUFSIZE;
|
||||
|
||||
char *buf; /* push-back buffer */
|
||||
char *bufbase; /* the base for current ilevel */
|
||||
char *bbase[MAXINP]; /* the base for each ilevel */
|
||||
char *bp; /* first available character */
|
||||
char *endpbb; /* end of push-back buffer */
|
||||
unsigned char *buf; /* push-back buffer */
|
||||
unsigned char *bufbase; /* the base for current ilevel */
|
||||
unsigned char *bbase[MAXINP]; /* the base for each ilevel */
|
||||
unsigned char *bp; /* first available character */
|
||||
unsigned char *endpbb; /* end of push-back buffer */
|
||||
|
||||
|
||||
/*
|
||||
@ -88,10 +78,10 @@ indx(const char *s1, const char *s2)
|
||||
return (t - s1);
|
||||
}
|
||||
/*
|
||||
* putback - push character back onto input
|
||||
* pushback - push character back onto input
|
||||
*/
|
||||
void
|
||||
putback(int c)
|
||||
pushback(int c)
|
||||
{
|
||||
if (c == EOF)
|
||||
return;
|
||||
@ -102,7 +92,7 @@ putback(int c)
|
||||
|
||||
/*
|
||||
* pbstr - push string back onto input
|
||||
* putback is replicated to improve
|
||||
* pushback is replicated to improve
|
||||
* performance.
|
||||
*/
|
||||
void
|
||||
@ -111,7 +101,7 @@ pbstr(const char *s)
|
||||
size_t n;
|
||||
|
||||
n = strlen(s);
|
||||
while ((size_t)(endpbb - bp) <= n)
|
||||
while (endpbb - bp <= (long)n)
|
||||
enlarge_bufspace();
|
||||
while (n > 0)
|
||||
*bp++ = s[--n];
|
||||
@ -123,16 +113,36 @@ pbstr(const char *s)
|
||||
void
|
||||
pbnum(int n)
|
||||
{
|
||||
pbnumbase(n, 10, 0);
|
||||
}
|
||||
|
||||
void
|
||||
pbnumbase(int n, int base, int d)
|
||||
{
|
||||
static char digits[36] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
int num;
|
||||
int printed = 0;
|
||||
|
||||
if (base > 36)
|
||||
m4errx(1, "base %d > 36: not supported.", base);
|
||||
|
||||
if (base < 2)
|
||||
m4errx(1, "bad base %d for conversion.", base);
|
||||
|
||||
num = (n < 0) ? -n : n;
|
||||
do {
|
||||
putback(num % 10 + '0');
|
||||
pushback(digits[num % base]);
|
||||
printed++;
|
||||
}
|
||||
while ((num /= 10) > 0);
|
||||
while ((num /= base) > 0);
|
||||
|
||||
if (n < 0)
|
||||
putback('-');
|
||||
printed++;
|
||||
while (printed++ < d)
|
||||
pushback('0');
|
||||
|
||||
if (n < 0)
|
||||
pushback('-');
|
||||
}
|
||||
|
||||
/*
|
||||
@ -142,7 +152,7 @@ void
|
||||
pbunsigned(unsigned long n)
|
||||
{
|
||||
do {
|
||||
putback(n % 10 + '0');
|
||||
pushback(n % 10 + '0');
|
||||
}
|
||||
while ((n /= 10) > 0);
|
||||
}
|
||||
@ -152,10 +162,10 @@ initspaces(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
strspace = xalloc(strsize+1);
|
||||
strspace = xalloc(strsize+1, NULL);
|
||||
ep = strspace;
|
||||
endest = strspace+strsize;
|
||||
buf = (char *)xalloc(bufsize);
|
||||
buf = (unsigned char *)xalloc(bufsize, NULL);
|
||||
bufbase = buf;
|
||||
bp = buf;
|
||||
endpbb = buf + bufsize;
|
||||
@ -187,13 +197,11 @@ enlarge_strspace(void)
|
||||
void
|
||||
enlarge_bufspace(void)
|
||||
{
|
||||
char *newbuf;
|
||||
unsigned char *newbuf;
|
||||
int i;
|
||||
|
||||
bufsize *= 2;
|
||||
newbuf = realloc(buf, bufsize);
|
||||
if (!newbuf)
|
||||
errx(1, "too many characters pushed back");
|
||||
bufsize += bufsize/2;
|
||||
newbuf = xrealloc(buf, bufsize, "too many characters pushed back");
|
||||
for (i = 0; i < MAXINP; i++)
|
||||
bbase[i] = (bbase[i]-buf)+newbuf;
|
||||
bp = (bp-buf)+newbuf;
|
||||
@ -222,7 +230,7 @@ getdiv(int n)
|
||||
int c;
|
||||
|
||||
if (active == outfile[n])
|
||||
errx(1, "undivert: diversion still active");
|
||||
m4errx(1, "undivert: diversion still active.");
|
||||
rewind(outfile[n]);
|
||||
while ((c = getc(outfile[n])) != EOF)
|
||||
putc(c, active);
|
||||
@ -231,7 +239,7 @@ getdiv(int n)
|
||||
}
|
||||
|
||||
void
|
||||
onintr(int signo __unused)
|
||||
onintr(__unused int signo)
|
||||
{
|
||||
#define intrmessage "m4: interrupted.\n"
|
||||
write(STDERR_FILENO, intrmessage, sizeof(intrmessage)-1);
|
||||
@ -252,6 +260,24 @@ killdiv(void)
|
||||
}
|
||||
}
|
||||
|
||||
extern char *__progname;
|
||||
|
||||
void
|
||||
m4errx(int evaluation, const char *fmt, ...)
|
||||
{
|
||||
fprintf(stderr, "%s: ", __progname);
|
||||
fprintf(stderr, "%s at line %lu: ", CURRENT_NAME, CURRENT_LINE);
|
||||
if (fmt != NULL) {
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
exit(evaluation);
|
||||
}
|
||||
|
||||
/*
|
||||
* resizedivs: allocate more diversion files */
|
||||
void
|
||||
@ -259,21 +285,49 @@ resizedivs(int n)
|
||||
{
|
||||
int i;
|
||||
|
||||
outfile = (FILE **)realloc(outfile, sizeof(FILE *) * n);
|
||||
if (outfile == NULL)
|
||||
errx(1, "too many diverts %d", n);
|
||||
outfile = (FILE **)xrealloc(outfile, sizeof(FILE *) * n,
|
||||
"too many diverts %d", n);
|
||||
for (i = maxout; i < n; i++)
|
||||
outfile[i] = NULL;
|
||||
maxout = n;
|
||||
}
|
||||
|
||||
void *
|
||||
xalloc(size_t n)
|
||||
xalloc(size_t n, const char *fmt, ...)
|
||||
{
|
||||
char *p = malloc(n);
|
||||
void *p = malloc(n);
|
||||
|
||||
if (p == NULL)
|
||||
err(1, "malloc");
|
||||
if (p == NULL) {
|
||||
if (fmt == NULL)
|
||||
err(1, "malloc");
|
||||
else {
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
verr(1, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void *
|
||||
xrealloc(void *old, size_t n, const char *fmt, ...)
|
||||
{
|
||||
char *p = realloc(old, n);
|
||||
|
||||
if (p == NULL) {
|
||||
free(old);
|
||||
if (fmt == NULL)
|
||||
err(1, "realloc");
|
||||
else {
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
verr(1, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
@ -289,9 +343,9 @@ xstrdup(const char *s)
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"usage: m4 [-d flags] [-t name] [-gs] [-D name[=value]]...\n"
|
||||
" [-U name]... [-I dirname]... file...\n");
|
||||
fprintf(stderr, "usage: m4 [-gPs] [-Dname[=value]] [-d flags] "
|
||||
"[-I dirname] [-o filename]\n"
|
||||
"\t[-t macro] [-Uname] [file ...]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -300,10 +354,11 @@ obtain_char(struct input_file *f)
|
||||
{
|
||||
if (f->c == EOF)
|
||||
return EOF;
|
||||
else if (f->c == '\n')
|
||||
f->lineno++;
|
||||
|
||||
f->c = fgetc(f->file);
|
||||
if (f->c == '\n')
|
||||
f->lineno++;
|
||||
|
||||
return f->c;
|
||||
}
|
||||
|
||||
@ -314,6 +369,15 @@ set_input(struct input_file *f, FILE *real, const char *name)
|
||||
f->lineno = 1;
|
||||
f->c = 0;
|
||||
f->name = xstrdup(name);
|
||||
emit_synchline();
|
||||
}
|
||||
|
||||
void
|
||||
do_emit_synchline(void)
|
||||
{
|
||||
fprintf(active, "#line %lu \"%s\"\n",
|
||||
infile[ilevel].lineno, infile[ilevel].name);
|
||||
infile[ilevel].synch_lineno = infile[ilevel].lineno;
|
||||
}
|
||||
|
||||
void
|
||||
@ -356,8 +420,8 @@ buffer_mark(void)
|
||||
void
|
||||
dump_buffer(FILE *f, size_t m)
|
||||
{
|
||||
char *s;
|
||||
unsigned char *s;
|
||||
|
||||
for (s = bp; s - buf > (int)m;)
|
||||
for (s = bp; s-buf > (long)m;)
|
||||
fputc(*--s, f);
|
||||
}
|
||||
|
83
usr.bin/m4/parser.y
Normal file
83
usr.bin/m4/parser.y
Normal file
@ -0,0 +1,83 @@
|
||||
%{
|
||||
/* $OpenBSD: parser.y,v 1.6 2008/08/21 21:00:14 espie Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2004 Marc Espie <espie@cvs.openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#define YYSTYPE int32_t
|
||||
extern int32_t end_result;
|
||||
extern int yylex(void);
|
||||
extern int yyerror(const char *);
|
||||
extern int yyparse(void);
|
||||
%}
|
||||
%token NUMBER
|
||||
%token ERROR
|
||||
%left LOR
|
||||
%left LAND
|
||||
%left '|'
|
||||
%left '^'
|
||||
%left '&'
|
||||
%left EQ NE
|
||||
%left '<' LE '>' GE
|
||||
%left LSHIFT RSHIFT
|
||||
%left '+' '-'
|
||||
%left '*' '/' '%'
|
||||
%right UMINUS UPLUS '!' '~'
|
||||
|
||||
%%
|
||||
|
||||
top : expr { end_result = $1; }
|
||||
;
|
||||
expr : expr '+' expr { $$ = $1 + $3; }
|
||||
| expr '-' expr { $$ = $1 - $3; }
|
||||
| expr '*' expr { $$ = $1 * $3; }
|
||||
| expr '/' expr {
|
||||
if ($3 == 0) {
|
||||
yyerror("division by zero");
|
||||
exit(1);
|
||||
}
|
||||
$$ = $1 / $3;
|
||||
}
|
||||
| expr '%' expr {
|
||||
if ($3 == 0) {
|
||||
yyerror("modulo zero");
|
||||
exit(1);
|
||||
}
|
||||
$$ = $1 % $3;
|
||||
}
|
||||
| expr LSHIFT expr { $$ = $1 << $3; }
|
||||
| expr RSHIFT expr { $$ = $1 >> $3; }
|
||||
| expr '<' expr { $$ = $1 < $3; }
|
||||
| expr '>' expr { $$ = $1 > $3; }
|
||||
| expr LE expr { $$ = $1 <= $3; }
|
||||
| expr GE expr { $$ = $1 >= $3; }
|
||||
| expr EQ expr { $$ = $1 == $3; }
|
||||
| expr NE expr { $$ = $1 != $3; }
|
||||
| expr '&' expr { $$ = $1 & $3; }
|
||||
| expr '^' expr { $$ = $1 ^ $3; }
|
||||
| expr '|' expr { $$ = $1 | $3; }
|
||||
| expr LAND expr { $$ = $1 && $3; }
|
||||
| expr LOR expr { $$ = $1 || $3; }
|
||||
| '(' expr ')' { $$ = $2; }
|
||||
| '-' expr %prec UMINUS { $$ = -$2; }
|
||||
| '+' expr %prec UPLUS { $$ = $2; }
|
||||
| '!' expr { $$ = !$2; }
|
||||
| '~' expr { $$ = ~$2; }
|
||||
| NUMBER
|
||||
;
|
||||
%%
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: pathnames.h,v 1.4 1997/04/04 18:41:29 deraadt Exp $ */
|
||||
/* $OpenBSD: pathnames.h,v 1.5 2003/06/03 02:56:10 millert Exp $ */
|
||||
/* $NetBSD: pathnames.h,v 1.6 1995/09/29 00:27:55 cgd Exp $ */
|
||||
|
||||
/*
|
||||
@ -16,7 +16,7 @@
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
@ -46,8 +46,7 @@
|
||||
#define UNIQUE 3 /* unique char location */
|
||||
#endif
|
||||
|
||||
#if defined(unix) || defined(__FreeBSD__) || defined(__NetBSD__) || \
|
||||
defined(__OpenBSD__)
|
||||
#if defined(unix) || defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
#define _PATH_DIVNAME "/tmp/m4.0XXXXXXXXXX" /* unix diversion files */
|
||||
#define UNIQUE 8 /* unique char location */
|
||||
#endif
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: stdd.h,v 1.4 1999/11/09 18:16:18 deraadt Exp $ */
|
||||
/* $OpenBSD: stdd.h,v 1.6 2010/09/07 19:58:09 marco Exp $ */
|
||||
/* $NetBSD: stdd.h,v 1.2 1995/09/28 05:37:50 tls Exp $ */
|
||||
|
||||
/*-
|
||||
@ -16,7 +16,7 @@
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
|
111
usr.bin/m4/tokenizer.l
Normal file
111
usr.bin/m4/tokenizer.l
Normal file
@ -0,0 +1,111 @@
|
||||
%option nounput noinput
|
||||
%{
|
||||
/* $OpenBSD: tokenizer.l,v 1.7 2010/03/22 20:40:44 espie Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2004 Marc Espie <espie@cvs.openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#include "parser.h"
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
|
||||
extern int mimic_gnu;
|
||||
extern int32_t yylval;
|
||||
|
||||
int32_t number(void);
|
||||
int32_t parse_radix(void);
|
||||
extern int yylex(void);
|
||||
%}
|
||||
|
||||
delim [ \t\n]
|
||||
ws {delim}+
|
||||
hex 0[xX][0-9a-fA-F]+
|
||||
oct 0[0-7]*
|
||||
dec [1-9][0-9]*
|
||||
radix 0[rR][0-9]+:[0-9a-zA-Z]+
|
||||
|
||||
%%
|
||||
{ws} {/* just skip it */}
|
||||
{hex}|{oct}|{dec} { yylval = number(); return(NUMBER); }
|
||||
{radix} { if (mimic_gnu) {
|
||||
yylval = parse_radix(); return(NUMBER);
|
||||
} else {
|
||||
return(ERROR);
|
||||
}
|
||||
}
|
||||
"<=" { return(LE); }
|
||||
">=" { return(GE); }
|
||||
"<<" { return(LSHIFT); }
|
||||
">>" { return(RSHIFT); }
|
||||
"==" { return(EQ); }
|
||||
"!=" { return(NE); }
|
||||
"&&" { return(LAND); }
|
||||
"||" { return(LOR); }
|
||||
. { return yytext[0]; }
|
||||
%%
|
||||
|
||||
int32_t
|
||||
number(void)
|
||||
{
|
||||
long l;
|
||||
|
||||
errno = 0;
|
||||
l = strtol(yytext, NULL, 0);
|
||||
if (((l == LONG_MAX || l == LONG_MIN) && errno == ERANGE) ||
|
||||
l > INT32_MAX || l < INT32_MIN) {
|
||||
fprintf(stderr, "m4: numeric overflow in expr: %s\n", yytext);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
int32_t
|
||||
parse_radix(void)
|
||||
{
|
||||
long base;
|
||||
char *next;
|
||||
long l;
|
||||
int d;
|
||||
|
||||
l = 0;
|
||||
base = strtol(yytext+2, &next, 0);
|
||||
if (base > 36 || next == NULL) {
|
||||
fprintf(stderr, "m4: error in number %s\n", yytext);
|
||||
} else {
|
||||
next++;
|
||||
while (*next != 0) {
|
||||
if (*next >= '0' && *next <= '9')
|
||||
d = *next - '0';
|
||||
else if (*next >= 'a' && *next <= 'z')
|
||||
d = *next - 'a' + 10;
|
||||
else {
|
||||
assert(*next >= 'A' && *next <= 'Z');
|
||||
d = *next - 'A' + 10;
|
||||
}
|
||||
if (d >= base) {
|
||||
fprintf(stderr,
|
||||
"m4: error in number %s\n", yytext);
|
||||
return 0;
|
||||
}
|
||||
l = base * l + d;
|
||||
next++;
|
||||
}
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: trace.c,v 1.6 2002/04/26 16:15:16 espie Exp $ */
|
||||
/* $OpenBSD: trace.c,v 1.16 2010/09/07 19:58:09 marco Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2001 Marc Espie.
|
||||
*
|
||||
@ -23,25 +23,21 @@
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <err.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "mdef.h"
|
||||
#include "stdd.h"
|
||||
#include "extern.h"
|
||||
|
||||
FILE *traceout;
|
||||
|
||||
int traced_macros = 0;
|
||||
|
||||
#define TRACE_ARGS 1
|
||||
#define TRACE_ARGS 1
|
||||
#define TRACE_EXPANSION 2
|
||||
#define TRACE_QUOTE 4
|
||||
#define TRACE_FILENAME 8
|
||||
@ -50,81 +46,19 @@ int traced_macros = 0;
|
||||
#define TRACE_ID 64
|
||||
#define TRACE_NEWFILE 128 /* not implemented yet */
|
||||
#define TRACE_INPUT 256 /* not implemented yet */
|
||||
#define TRACE_ALL 512
|
||||
|
||||
static struct t {
|
||||
struct t *next;
|
||||
char *name;
|
||||
int on;
|
||||
} *l;
|
||||
|
||||
static unsigned int letter_to_flag(int);
|
||||
static void print_header(struct input_file *);
|
||||
static struct t *find_trace_entry(const char *);
|
||||
static int frame_level(void);
|
||||
|
||||
static unsigned int flags = TRACE_QUOTE | TRACE_EXPANSION;
|
||||
|
||||
static struct t *
|
||||
find_trace_entry(const char *name)
|
||||
{
|
||||
struct t *n;
|
||||
|
||||
for (n = l; n != NULL; n = n->next)
|
||||
if (STREQ(n->name, name))
|
||||
return n;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
mark_traced(const char *name, int on)
|
||||
{
|
||||
struct t *n, *n2;
|
||||
|
||||
traced_macros = 1;
|
||||
|
||||
if (name == NULL) {
|
||||
if (on)
|
||||
flags |= TRACE_ALL;
|
||||
else {
|
||||
flags &= ~TRACE_ALL;
|
||||
traced_macros = 0;
|
||||
}
|
||||
for (n = l; n != NULL; n = n2) {
|
||||
n2 = n->next;
|
||||
free(n->name);
|
||||
free(n);
|
||||
}
|
||||
l = NULL;
|
||||
} else {
|
||||
n = find_trace_entry(name);
|
||||
if (n == NULL) {
|
||||
n = xalloc(sizeof(struct t));
|
||||
n->name = xstrdup(name);
|
||||
n->next = l;
|
||||
l = n;
|
||||
}
|
||||
n->on = on;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
is_traced(const char *name)
|
||||
{
|
||||
struct t *n;
|
||||
|
||||
for (n = l; n != NULL; n = n->next)
|
||||
if (STREQ(n->name, name))
|
||||
return n->on;
|
||||
return (flags & TRACE_ALL) ? 1 : 0;
|
||||
}
|
||||
unsigned int trace_flags = TRACE_QUOTE | TRACE_EXPANSION;
|
||||
|
||||
void
|
||||
trace_file(const char *name)
|
||||
{
|
||||
|
||||
if (traceout != stderr)
|
||||
if (traceout && traceout != stderr)
|
||||
fclose(traceout);
|
||||
traceout = fopen(name, "w");
|
||||
if (!traceout)
|
||||
@ -168,21 +102,19 @@ set_trace_flags(const char *s)
|
||||
char mode = 0;
|
||||
unsigned int f = 0;
|
||||
|
||||
traced_macros = 1;
|
||||
|
||||
if (*s == '+' || *s == '-')
|
||||
mode = *s++;
|
||||
while (*s)
|
||||
f |= letter_to_flag(*s++);
|
||||
switch(mode) {
|
||||
case 0:
|
||||
flags = f;
|
||||
trace_flags = f;
|
||||
break;
|
||||
case '+':
|
||||
flags |= f;
|
||||
trace_flags |= f;
|
||||
break;
|
||||
case '-':
|
||||
flags &= ~f;
|
||||
trace_flags &= ~f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -194,7 +126,7 @@ frame_level(void)
|
||||
int framep;
|
||||
|
||||
for (framep = fp, level = 0; framep != 0;
|
||||
level++,framep = mstack[framep-2].sfra)
|
||||
level++,framep = mstack[framep-3].sfra)
|
||||
;
|
||||
return level;
|
||||
}
|
||||
@ -203,25 +135,27 @@ static void
|
||||
print_header(struct input_file *inp)
|
||||
{
|
||||
fprintf(traceout, "m4trace:");
|
||||
if (flags & TRACE_FILENAME)
|
||||
if (trace_flags & TRACE_FILENAME)
|
||||
fprintf(traceout, "%s:", inp->name);
|
||||
if (flags & TRACE_LINENO)
|
||||
if (trace_flags & TRACE_LINENO)
|
||||
fprintf(traceout, "%lu:", inp->lineno);
|
||||
fprintf(traceout, " -%d- ", frame_level());
|
||||
if (flags & TRACE_ID)
|
||||
if (trace_flags & TRACE_ID)
|
||||
fprintf(traceout, "id %lu: ", expansion_id);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
size_t
|
||||
trace(const char *argv[], int argc, struct input_file *inp)
|
||||
{
|
||||
if (!traceout)
|
||||
traceout = stderr;
|
||||
print_header(inp);
|
||||
if (flags & TRACE_CONT) {
|
||||
if (trace_flags & TRACE_CONT) {
|
||||
fprintf(traceout, "%s ...\n", argv[1]);
|
||||
print_header(inp);
|
||||
}
|
||||
fprintf(traceout, "%s", argv[1]);
|
||||
if ((flags & TRACE_ARGS) && argc > 2) {
|
||||
if ((trace_flags & TRACE_ARGS) && argc > 2) {
|
||||
char delim[3];
|
||||
int i;
|
||||
|
||||
@ -229,25 +163,25 @@ trace(const char *argv[], int argc, struct input_file *inp)
|
||||
delim[1] = EOS;
|
||||
for (i = 2; i < argc; i++) {
|
||||
fprintf(traceout, "%s%s%s%s", delim,
|
||||
(flags & TRACE_QUOTE) ? lquote : "",
|
||||
(trace_flags & TRACE_QUOTE) ? lquote : "",
|
||||
argv[i],
|
||||
(flags & TRACE_QUOTE) ? rquote : "");
|
||||
(trace_flags & TRACE_QUOTE) ? rquote : "");
|
||||
delim[0] = COMMA;
|
||||
delim[1] = ' ';
|
||||
delim[2] = EOS;
|
||||
}
|
||||
fprintf(traceout, "%c", RPAREN);
|
||||
}
|
||||
if (flags & TRACE_CONT) {
|
||||
if (trace_flags & TRACE_CONT) {
|
||||
fprintf(traceout, " -> ???\n");
|
||||
print_header(inp);
|
||||
fprintf(traceout, argc > 2 ? "%s(...)" : "%s", argv[1]);
|
||||
}
|
||||
if (flags & TRACE_EXPANSION)
|
||||
if (trace_flags & TRACE_EXPANSION)
|
||||
return buffer_mark();
|
||||
else {
|
||||
fprintf(traceout, "\n");
|
||||
return -1;
|
||||
return SIZE_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
@ -255,10 +189,10 @@ void
|
||||
finish_trace(size_t mark)
|
||||
{
|
||||
fprintf(traceout, " -> ");
|
||||
if (flags & TRACE_QUOTE)
|
||||
if (trace_flags & TRACE_QUOTE)
|
||||
fprintf(traceout, "%s", lquote);
|
||||
dump_buffer(traceout, mark);
|
||||
if (flags & TRACE_QUOTE)
|
||||
if (trace_flags & TRACE_QUOTE)
|
||||
fprintf(traceout, "%s", rquote);
|
||||
fprintf(traceout, "\n");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user