Replace m4 with NetBSD version
-Create usr.bin hierarchy -Update minix-port.patch to include m4
This commit is contained in:
7
usr.bin/Makefile
Normal file
7
usr.bin/Makefile
Normal file
@@ -0,0 +1,7 @@
|
||||
# Makefile for usr.bin
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
SUBDIR= m4
|
||||
|
||||
.include <bsd.subdir.mk>
|
||||
7
usr.bin/Makefile.inc
Normal file
7
usr.bin/Makefile.inc
Normal file
@@ -0,0 +1,7 @@
|
||||
# Require clang and NBSD_LIBC
|
||||
NBSD_LIBC:= yes
|
||||
CC:= clang
|
||||
COMPILER_TYPE:= gnu
|
||||
|
||||
BINDIR?=/usr/bin
|
||||
|
||||
27
usr.bin/m4/Makefile
Normal file
27
usr.bin/m4/Makefile
Normal file
@@ -0,0 +1,27 @@
|
||||
# $NetBSD: Makefile,v 1.15 2009/10/26 21:11:28 christos Exp $
|
||||
#
|
||||
# @(#)Makefile 8.1 (Berkeley) 6/6/93
|
||||
|
||||
# -DEXTENDED
|
||||
# if you want the paste & spaste macros.
|
||||
.include <bsd.own.mk>
|
||||
|
||||
PROG= m4
|
||||
CPPFLAGS+= -DEXTENDED -I${.CURDIR}/lib
|
||||
SRCS= parser.y tokenizer.l eval.c expr.c look.c main.c misc.c gnum4.c trace.c
|
||||
.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 strtonum.c
|
||||
YHEADER=1
|
||||
.if (${HOSTPROG:U} == "")
|
||||
DPADD+= ${LIBUTIL} ${LIBL}
|
||||
LDADD+= -lutil -ll
|
||||
.endif
|
||||
|
||||
tokenizer.o: parser.h
|
||||
|
||||
CLEANFILES+=parser.c parser.h tokenizer.o
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
64
usr.bin/m4/NOTES
Normal file
64
usr.bin/m4/NOTES
Normal file
@@ -0,0 +1,64 @@
|
||||
m4 - macro processor
|
||||
|
||||
PD m4 is based on the macro tool distributed with the software
|
||||
tools (VOS) package, and described in the "SOFTWARE TOOLS" and
|
||||
"SOFTWARE TOOLS IN PASCAL" books. It has been expanded to include
|
||||
most of the command set of SysV m4, the standard UN*X macro processor.
|
||||
|
||||
Since both PD m4 and UN*X m4 are based on SOFTWARE TOOLS macro,
|
||||
there may be certain implementation similarities between
|
||||
the two. The PD m4 was produced without ANY references to m4
|
||||
sources.
|
||||
|
||||
written by: Ozan S. Yigit
|
||||
|
||||
References:
|
||||
|
||||
Software Tools distribution: macro
|
||||
|
||||
Kernighan, Brian W. and P. J. Plauger, SOFTWARE
|
||||
TOOLS IN PASCAL, Addison-Wesley, Mass. 1981
|
||||
|
||||
Kernighan, Brian W. and P. J. Plauger, SOFTWARE
|
||||
TOOLS, Addison-Wesley, Mass. 1976
|
||||
|
||||
Kernighan, Brian W. and Dennis M. Ritchie,
|
||||
THE M4 MACRO PROCESSOR, Unix Programmer's Manual,
|
||||
Seventh Edition, Vol. 2, Bell Telephone Labs, 1979
|
||||
|
||||
System V man page for M4
|
||||
|
||||
|
||||
Implementation Notes:
|
||||
|
||||
[1] PD m4 uses a different (and simpler) stack mechanism than the one
|
||||
described in Software Tools and Software Tools in Pascal books.
|
||||
The triple stack thing is replaced with a single stack containing
|
||||
the call frames and the arguments. Each frame is back-linked to a
|
||||
previous stack frame, which enables us to rewind the stack after
|
||||
each nested call is completed. Each argument is a character pointer
|
||||
to the beginning of the argument string within the string space.
|
||||
The only exceptions to this are (*) arg 0 and arg 1, which are
|
||||
the macro definition and macro name strings, stored dynamically
|
||||
for the hash table.
|
||||
|
||||
. .
|
||||
| . | <-- sp | . |
|
||||
+-------+ +-----+
|
||||
| arg 3 ------------------------------->| str |
|
||||
+-------+ | . |
|
||||
| arg 2 --------------+ .
|
||||
+-------+ |
|
||||
* | | |
|
||||
+-------+ | +-----+
|
||||
| plev | <-- fp +---------------->| str |
|
||||
+-------+ | . |
|
||||
| type | .
|
||||
+-------+
|
||||
| prcf -----------+ plev: paren level
|
||||
+-------+ | type: call type
|
||||
| . | | prcf: prev. call frame
|
||||
. |
|
||||
+-------+ |
|
||||
| <----------+
|
||||
+-------+
|
||||
12
usr.bin/m4/PSD.doc/Makefile
Normal file
12
usr.bin/m4/PSD.doc/Makefile
Normal file
@@ -0,0 +1,12 @@
|
||||
# $NetBSD: Makefile,v 1.3 2003/07/10 10:34:44 lukem Exp $
|
||||
#
|
||||
# @(#)Makefile 8.1 (Berkeley) 6/8/93
|
||||
|
||||
DIR= psd/17.m4
|
||||
SRCS= m4.ms
|
||||
MACROS= -msU
|
||||
|
||||
paper.ps: ${SRCS}
|
||||
${TOOL_ROFF_PS} ${SRCS} > ${.TARGET}
|
||||
|
||||
.include <bsd.doc.mk>
|
||||
41
usr.bin/m4/TEST/ack.m4
Normal file
41
usr.bin/m4/TEST/ack.m4
Normal file
@@ -0,0 +1,41 @@
|
||||
# $NetBSD: ack.m4,v 1.4 1995/09/28 05:37:54 tls 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.
|
||||
#
|
||||
# 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. All advertising materials mentioning features or use of this software
|
||||
# must display the following acknowledgement:
|
||||
# This product includes software developed by the University of
|
||||
# California, Berkeley and its contributors.
|
||||
# 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.
|
||||
#
|
||||
# @(#)ack.m4 8.1 (Berkeley) 6/6/93
|
||||
#
|
||||
|
||||
define(ack, `ifelse($1,0,incr($2),$2,0,`ack(DECR($1),1)',
|
||||
`ack(DECR($1), ack($1,DECR($2)))')')
|
||||
46
usr.bin/m4/TEST/hanoi.m4
Normal file
46
usr.bin/m4/TEST/hanoi.m4
Normal file
@@ -0,0 +1,46 @@
|
||||
# $NetBSD: hanoi.m4,v 1.4 1995/09/28 05:37:56 tls 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.
|
||||
#
|
||||
# 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. All advertising materials mentioning features or use of this software
|
||||
# must display the following acknowledgement:
|
||||
# This product includes software developed by the University of
|
||||
# California, Berkeley and its contributors.
|
||||
# 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.
|
||||
#
|
||||
# @(#)hanoi.m4 8.1 (Berkeley) 6/6/93
|
||||
#
|
||||
|
||||
define(hanoi, `trans(A, B, C, $1)')
|
||||
|
||||
define(moved,`move disk from $1 to $2
|
||||
')
|
||||
|
||||
define(trans, `ifelse($4,1,`moved($1,$2)',
|
||||
`trans($1,$3,$2,DECR($4))moved($1,$2)trans($3,$2,$1,DECR($4))')')
|
||||
56
usr.bin/m4/TEST/hash.m4
Normal file
56
usr.bin/m4/TEST/hash.m4
Normal file
@@ -0,0 +1,56 @@
|
||||
# $NetBSD: hash.m4,v 1.4 1995/09/28 05:37:58 tls 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.
|
||||
#
|
||||
# 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. All advertising materials mentioning features or use of this software
|
||||
# must display the following acknowledgement:
|
||||
# This product includes software developed by the University of
|
||||
# California, Berkeley and its contributors.
|
||||
# 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.
|
||||
#
|
||||
# @(#)hash.m4 8.1 (Berkeley) 6/6/93
|
||||
#
|
||||
|
||||
dnl This probably will not run on any m4 that cannot
|
||||
dnl handle char constants in eval.
|
||||
dnl
|
||||
changequote(<,>) define(HASHVAL,99) dnl
|
||||
define(hash,<eval(str(substr($1,1),0)%HASHVAL)>) dnl
|
||||
define(str,
|
||||
<ifelse($1,",$2,
|
||||
<str(substr(<$1>,1),<eval($2+'substr($1,0,1)')>)>)
|
||||
>) dnl
|
||||
define(KEYWORD,<$1,hash($1),>) dnl
|
||||
define(TSTART,
|
||||
<struct prehash {
|
||||
char *keyword;
|
||||
int hashval;
|
||||
} keytab[] = {>) dnl
|
||||
define(TEND,< "",0
|
||||
};>) dnl
|
||||
182
usr.bin/m4/TEST/math.m4
Normal file
182
usr.bin/m4/TEST/math.m4
Normal file
@@ -0,0 +1,182 @@
|
||||
dnl $NetBSD: math.m4,v 1.2 2005/10/06 17:38:09 drochner Exp $
|
||||
dnl FreeBSD: /repoman/r/ncvs/src/usr.bin/m4/TEST/math.m4,v 1.1 2004/05/01 03:27:05 smkelly Exp
|
||||
dnl A regression test for m4 C operators (ksb,petef)
|
||||
dnl If you think you have a short-circuiting m4, run us m4 -DSHORCIRCUIT=yes
|
||||
dnl
|
||||
dnl first level of precedence
|
||||
ifelse(eval(-7),-7,,`failed -
|
||||
')dnl
|
||||
ifelse(eval(- -2),2,,`failed -
|
||||
')dnl
|
||||
ifelse(eval(!0),1,,`failed !
|
||||
')dnl
|
||||
ifelse(eval(!7),0,,`failed !
|
||||
')dnl
|
||||
ifelse(eval(~-1),0,,`failed ~
|
||||
')dnl
|
||||
dnl next level of precedence
|
||||
ifelse(eval(3*5),15,,`failed *
|
||||
')dnl
|
||||
ifelse(eval(3*0),0,,`failed *
|
||||
')dnl
|
||||
ifelse(eval(11/2),5,,`failed /
|
||||
')dnl
|
||||
ifelse(eval(1/700),0,,`failed /
|
||||
')dnl
|
||||
ifelse(eval(10%5),0,,`failed %
|
||||
')dnl
|
||||
ifelse(eval(2%5),2,,`failed %
|
||||
')dnl
|
||||
ifelse(eval(2%-1),0,,`failed %
|
||||
')dnl
|
||||
dnl next level of precedence
|
||||
ifelse(eval(2+2),4,,`failed +
|
||||
')dnl
|
||||
ifelse(eval(2+-2),0,,`failed +
|
||||
')dnl
|
||||
ifelse(eval(2- -2),4,,`failed -
|
||||
')dnl
|
||||
ifelse(eval(2-2),0,,`failed -
|
||||
')dnl
|
||||
dnl next level of precedence
|
||||
ifelse(eval(1<<4),16,,`failed <<
|
||||
')dnl
|
||||
ifelse(eval(16>>4),1,,`failed >>
|
||||
')dnl
|
||||
dnl next level of precedence
|
||||
ifelse(eval(4<4),0,,`failed <
|
||||
')dnl
|
||||
ifelse(eval(4<5),1,,`failed <
|
||||
')dnl
|
||||
ifelse(eval(4<3),0,,`failed <
|
||||
')dnl
|
||||
ifelse(eval(4>4),0,,`failed >
|
||||
')dnl
|
||||
ifelse(eval(4>5),0,,`failed >
|
||||
')dnl
|
||||
ifelse(eval(4>3),1,,`failed >
|
||||
')dnl
|
||||
ifelse(eval(4<=4),1,,`failed <=
|
||||
')dnl
|
||||
ifelse(eval(4<=5),1,,`failed <=
|
||||
')dnl
|
||||
ifelse(eval(4<=3),0,,`failed <=
|
||||
')dnl
|
||||
ifelse(eval(4>=4),1,,`failed >=
|
||||
')dnl
|
||||
ifelse(eval(4>=5),0,,`failed >=
|
||||
')dnl
|
||||
ifelse(eval(4>=3),1,,`failed >=
|
||||
')dnl
|
||||
dnl next level of precedence
|
||||
ifelse(eval(1==1),1,,`failed ==
|
||||
')dnl
|
||||
ifelse(eval(1==-1),0,,`failed ==
|
||||
')dnl
|
||||
ifelse(eval(1!=1),0,,`failed !=
|
||||
')dnl
|
||||
ifelse(eval(1!=2),1,,`failed !=
|
||||
')dnl
|
||||
dnl next level of precedence
|
||||
ifelse(eval(3&5),1,,`failed &
|
||||
')dnl
|
||||
ifelse(eval(8&7),0,,`failed &
|
||||
')dnl
|
||||
dnl next level of precedence
|
||||
ifelse(eval(1^1),0,,`failed ^
|
||||
')dnl
|
||||
ifelse(eval(21^5),16,,`failed ^
|
||||
')dnl
|
||||
dnl next level of precedence
|
||||
ifelse(eval(1|1),1,,`failed |
|
||||
')dnl
|
||||
ifelse(eval(21|5),21,,`failed |
|
||||
')dnl
|
||||
ifelse(eval(100|1),101,,`failed |
|
||||
')dnl
|
||||
dnl next level of precedence
|
||||
ifelse(eval(1&&1),1,,`failed &&
|
||||
')dnl
|
||||
ifelse(eval(0&&1),0,,`failed &&
|
||||
')dnl
|
||||
ifelse(eval(1&&0),0,,`failed &&
|
||||
')dnl
|
||||
ifelse(SHORTCIRCUIT,`yes',`ifelse(eval(0&&10/0),0,,`failed && shortcircuit
|
||||
')')dnl
|
||||
dnl next level of precedence
|
||||
ifelse(eval(1||1),1,,`failed ||
|
||||
')dnl
|
||||
ifelse(eval(1||0),1,,`failed ||
|
||||
')dnl
|
||||
ifelse(eval(0||0),0,,`failed ||
|
||||
')dnl
|
||||
ifelse(SHORTCIRCUIT,`yes',`ifelse(eval(1||10/0),1,,`failed || shortcircuit
|
||||
')')dnl
|
||||
dnl next level of precedence
|
||||
ifelse(eval(0 ? 2 : 5),5,,`failed ?:
|
||||
')dnl
|
||||
ifelse(eval(1 ? 2 : 5),2,,`failed ?:
|
||||
')dnl
|
||||
ifelse(SHORTCIRCUIT,`yes',`ifelse(eval(0 ? 10/0 : 7),7,,`failed ?: shortcircuit
|
||||
')')dnl
|
||||
ifelse(SHORTCIRCUIT,`yes',`ifelse(eval(1 ? 7 : 10/0),7,,`failed ?: shortcircuit
|
||||
')')dnl
|
||||
dnl operator precedence
|
||||
ifelse(eval(!0*-2),-2,,`precedence wrong, ! *
|
||||
')dnl
|
||||
ifelse(eval(~8/~2),3,,`precedence wrong ~ /
|
||||
')dnl
|
||||
ifelse(eval(~-20%7),5,,`precedence wrong ~ %
|
||||
')dnl
|
||||
ifelse(eval(3*2+100),106,,`precedence wrong * +
|
||||
')dnl
|
||||
ifelse(eval(3+2*100),203,,`precedence wrong + *
|
||||
')dnl
|
||||
ifelse(eval(2%5-6/3),0,,`precedence wrong % -
|
||||
')dnl
|
||||
ifelse(eval(2/5-5%3),-2,,`precedence wrong / -
|
||||
')dnl
|
||||
ifelse(eval(2+5%5+1),3,,`precedence wrong % +
|
||||
')dnl
|
||||
ifelse(eval(7+9<<1),32,,`precedence wrong + <<
|
||||
')dnl
|
||||
ifelse(eval(35-3>>2),8,,`precedence wrong - >>
|
||||
')dnl
|
||||
ifelse(eval(9<10<<5),1,,`precedence wrong << <
|
||||
')dnl
|
||||
ifelse(eval(9>10<<5),0,,`precedence wrong << >
|
||||
')dnl
|
||||
ifelse(eval(32>>2<32),1,,`precedence wrong >> <
|
||||
')dnl
|
||||
ifelse(eval(9<=10<<5),1,,`precedence wrong << <
|
||||
')dnl
|
||||
ifelse(eval(5<<1<=20>>1),1,,`precedence wrong << <=
|
||||
')dnl
|
||||
ifelse(eval(5<<1>=20>>1),1,,`precedence wrong << >=
|
||||
')dnl
|
||||
ifelse(eval(0<7==5>=5),1,,`precedence wrong < ==
|
||||
')dnl
|
||||
ifelse(eval(0<7!=5>=5),0,,`precedence wrong < !=
|
||||
')dnl
|
||||
ifelse(eval(0>7==5>=5),0,,`precedence wrong > ==
|
||||
')dnl
|
||||
ifelse(eval(0>7!=5>=5),1,,`precedence wrong > !=
|
||||
')dnl
|
||||
ifelse(eval(1&7==7),1,,`precedence wrong & ==
|
||||
')dnl
|
||||
ifelse(eval(0&7!=6),0,,`precedence wrong & !=
|
||||
')dnl
|
||||
ifelse(eval(9&1|5),5,,`precedence wrong & |
|
||||
')dnl
|
||||
ifelse(eval(9&1^5),4,,`precedence wrong & ^
|
||||
')dnl
|
||||
ifelse(eval(9^1|5),13,,`precedence wrong ^ |
|
||||
')dnl
|
||||
ifelse(eval(5|0&&1),1,,`precedence wrong | &&
|
||||
')dnl
|
||||
ifelse(eval(5&&0||0&&5||5),1,,`precedence wrong && ||
|
||||
')dnl
|
||||
ifelse(eval(0 || 1 ? 0 : 1),0,,`precedence wrong || ?:
|
||||
')dnl
|
||||
ifelse(eval(5&&(0||0)&&(5||5)),0,,`precedence wrong || parens
|
||||
')dnl
|
||||
46
usr.bin/m4/TEST/sqroot.m4
Normal file
46
usr.bin/m4/TEST/sqroot.m4
Normal file
@@ -0,0 +1,46 @@
|
||||
# $NetBSD: sqroot.m4,v 1.4 1995/09/28 05:38:01 tls 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.
|
||||
#
|
||||
# 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. All advertising materials mentioning features or use of this software
|
||||
# must display the following acknowledgement:
|
||||
# This product includes software developed by the University of
|
||||
# California, Berkeley and its contributors.
|
||||
# 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.
|
||||
#
|
||||
# @(#)sqroot.m4 8.1 (Berkeley) 6/6/93
|
||||
#
|
||||
|
||||
define(square_root,
|
||||
`ifelse(eval($1<0),1,negative-square-root,
|
||||
`square_root_aux($1, 1, eval(($1+1)/2))')')
|
||||
define(square_root_aux,
|
||||
`ifelse($3, $2, $3,
|
||||
$3, eval($1/$2), $3,
|
||||
`square_root_aux($1, $3, eval(($3+($1/$3))/2))')')
|
||||
46
usr.bin/m4/TEST/string.m4
Normal file
46
usr.bin/m4/TEST/string.m4
Normal file
@@ -0,0 +1,46 @@
|
||||
# $NetBSD: string.m4,v 1.4 1995/09/28 05:38:03 tls 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.
|
||||
#
|
||||
# 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. All advertising materials mentioning features or use of this software
|
||||
# must display the following acknowledgement:
|
||||
# This product includes software developed by the University of
|
||||
# California, Berkeley and its contributors.
|
||||
# 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.
|
||||
#
|
||||
# @(#)string.m4 8.1 (Berkeley) 6/6/93
|
||||
#
|
||||
|
||||
define(string,`integer $1(len(substr($2,1)))
|
||||
str($1,substr($2,1),0)
|
||||
data $1(len(substr($2,1)))/EOS/
|
||||
')
|
||||
|
||||
define(str,`ifelse($2,",,data $1(incr($3))/`LET'substr($2,0,1)/
|
||||
`str($1,substr($2,1),incr($3))')')
|
||||
244
usr.bin/m4/TEST/test.m4
Normal file
244
usr.bin/m4/TEST/test.m4
Normal file
@@ -0,0 +1,244 @@
|
||||
# $NetBSD: test.m4,v 1.4 1995/09/28 05:38:05 tls 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.
|
||||
#
|
||||
# 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. All advertising materials mentioning features or use of this software
|
||||
# must display the following acknowledgement:
|
||||
# This product includes software developed by the University of
|
||||
# California, Berkeley and its contributors.
|
||||
# 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.
|
||||
#
|
||||
# @(#)test.m4 8.1 (Berkeley) 6/6/93
|
||||
#
|
||||
|
||||
# test file for mp (not comprehensive)
|
||||
#
|
||||
# v7 m4 does not have `decr'.
|
||||
#
|
||||
define(DECR,`eval($1-1)')
|
||||
#
|
||||
# include string macros
|
||||
#
|
||||
include(string.m4)
|
||||
#
|
||||
# create some fortrash strings for an even uglier language
|
||||
#
|
||||
string(TEXT, "text")
|
||||
string(DATA, "data")
|
||||
string(BEGIN, "begin")
|
||||
string(END, "end")
|
||||
string(IF, "if")
|
||||
string(THEN, "then")
|
||||
string(ELSE, "else")
|
||||
string(CASE, "case")
|
||||
string(REPEAT, "repeat")
|
||||
string(WHILE, "while")
|
||||
string(DEFAULT, "default")
|
||||
string(UNTIL, "until")
|
||||
string(FUNCTION, "function")
|
||||
string(PROCEDURE, "procedure")
|
||||
string(EXTERNAL, "external")
|
||||
string(FORWARD, "forward")
|
||||
string(TYPE, "type")
|
||||
string(VAR, "var")
|
||||
string(CONST, "const")
|
||||
string(PROGRAM, "program")
|
||||
string(INPUT, "input")
|
||||
string(OUTPUT, "output")
|
||||
#
|
||||
divert(2)
|
||||
diversion #1
|
||||
divert(3)
|
||||
diversion #2
|
||||
divert(4)
|
||||
diversion #3
|
||||
divert(5)
|
||||
diversion #4
|
||||
divert(0)
|
||||
define(abc,xxx)
|
||||
ifdef(`abc',defined,undefined)
|
||||
#
|
||||
# v7 m4 does this wrong. The right output is
|
||||
# this is A vEry lon sEntEnCE
|
||||
# see m4 documentation for translit.
|
||||
#
|
||||
translit(`this is a very long sentence', abcdefg, ABCDEF)
|
||||
#
|
||||
# include towers-of-hanoi
|
||||
#
|
||||
include(hanoi.m4)
|
||||
#
|
||||
# some reasonable set of disks
|
||||
#
|
||||
hanoi(6)
|
||||
#
|
||||
# include ackermann's function
|
||||
#
|
||||
include(ack.m4)
|
||||
#
|
||||
# something like (3,3) will blow away un*x m4.
|
||||
#
|
||||
ack(2,3)
|
||||
#
|
||||
# include a square_root function for fixed nums
|
||||
#
|
||||
include(sqroot.m4)
|
||||
#
|
||||
# some square roots.
|
||||
#
|
||||
square_root(15)
|
||||
square_root(100)
|
||||
square_root(-4)
|
||||
square_root(21372)
|
||||
#
|
||||
# some textual material for enjoyment.
|
||||
#
|
||||
[taken from the 'Clemson University Computer Newsletter',
|
||||
September 1981, pp. 6-7]
|
||||
|
||||
I am a wizard in the magical Kingdom of Transformation and I
|
||||
slay dragons for a living. Actually, I am a systems programmer.
|
||||
One of the problems with systems programming is explaining to
|
||||
non-computer enthusiasts what that is. All of the terms I use to
|
||||
describe my job are totally meaningless to them. Usually my response
|
||||
to questions about my work is to say as little as possible. For
|
||||
instance, if someone asks what happened at work this week, I say
|
||||
"Nothing much" and then I change the subject.
|
||||
|
||||
With the assistance of my brother, a mechanical engineer, I have devised
|
||||
an analogy that everyone can understand. The analogy describes the
|
||||
"Kingdom of Transformation" where travelers wander and are magically
|
||||
transformed. This kingdom is the computer and the travelers are information.
|
||||
The purpose of the computer is to change information to a more meaningful
|
||||
forma. The law of conservation applies here: The computer never creates
|
||||
and never intentionally destroys data. With no further ado, let us travel
|
||||
to the Kingdom of Transformation:
|
||||
|
||||
In a land far, far away, there is a magical kingdom called the Kingdom of
|
||||
Transformation. A king rules over this land and employs a Council of
|
||||
Wizardry. The main purpose of this kingdom is to provide a way for
|
||||
neighboring kingdoms to transform citizens into more useful citizens. This
|
||||
is done by allowing the citizens to enter the kingdom at one of its ports
|
||||
and to travel any of the many routes in the kingdom. They are magically
|
||||
transformed along the way. The income of the Kingdom of Transformation
|
||||
comes from the many toll roads within its boundaries.
|
||||
|
||||
The Kingdom of Transformation was created when several kingdoms got
|
||||
together and discovered a mutual need for new talents and abilities for
|
||||
citizens. They employed CTK, Inc. (Creators of Transformation, Inc.) to
|
||||
create this kingdom. CTK designed the country, its transportation routes,
|
||||
and its laws of transformation, and created the major highway system.
|
||||
|
||||
Hazards
|
||||
=======
|
||||
|
||||
Because magic is not truly controllable, CTK invariably, but unknowingly,
|
||||
creates dragons. Dragons are huge fire-breathing beasts which sometimes
|
||||
injure or kill travelers. Fortunately, they do not travel, but always
|
||||
remain near their den.
|
||||
|
||||
Other hazards also exist which are potentially harmful. As the roads
|
||||
become older and more weatherbeaten, pot-holes will develop, trees will
|
||||
fall on travelers, etc. CTK maintenance men are called to fix these
|
||||
problems.
|
||||
|
||||
Wizards
|
||||
=======
|
||||
|
||||
The wizards play a major role in creating and maintaining the kingdom but
|
||||
get little credit for their work because it is performed secretly. The
|
||||
wizards do not wan the workers or travelers to learn their incantations
|
||||
because many laws would be broken and chaos would result.
|
||||
|
||||
CTK's grand design is always general enough to be applicable in many
|
||||
different situations. As a result, it is often difficult to use. The
|
||||
first duty of the wizards is to tailor the transformation laws so as to be
|
||||
more beneficial and easier to use in their particular environment.
|
||||
|
||||
After creation of the kingdom, a major duty of the wizards is to search for
|
||||
and kill dragons. If travelers do not return on time or if they return
|
||||
injured, the ruler of the country contacts the wizards. If the wizards
|
||||
determine that the injury or death occurred due to the traveler's
|
||||
negligence, they provide the traveler's country with additional warnings.
|
||||
If not, they must determine if the cause was a road hazard or a dragon. If
|
||||
the suspect a road hazard, they call in a CTK maintenance man to locate the
|
||||
hazard and to eliminate it, as in repairing the pothole in the road. If
|
||||
they think that cause was a dragon, then they must find and slay it.
|
||||
|
||||
The most difficult part of eliminating a dragon is finding it. Sometimes
|
||||
the wizard magically knows where the dragon's lair it, but often the wizard
|
||||
must send another traveler along the same route and watch to see where he
|
||||
disappears. This sounds like a failsafe method for finding dragons (and a
|
||||
suicide mission for thr traveler) but the second traveler does not always
|
||||
disappear. Some dragons eat any traveler who comes too close; others are
|
||||
very picky.
|
||||
|
||||
The wizards may call in CTK who designed the highway system and
|
||||
transformation laws to help devise a way to locate the dragon. CTK also
|
||||
helps provide the right spell or incantation to slay the dragon. (There is
|
||||
no general spell to slay dragons; each dragon must be eliminated with a
|
||||
different spell.)
|
||||
|
||||
Because neither CTK nor wizards are perfect, spells to not always work
|
||||
correctly. At best, nothing happens when the wrong spell is uttered. At
|
||||
worst, the dragon becomes a much larger dragon or multiplies into several
|
||||
smaller ones. In either case, new spells must be found.
|
||||
|
||||
If all existing dragons are quiet (i.e. have eaten sufficiently), wizards
|
||||
have time to do other things. They hide in castles and practice spells and
|
||||
incatations. They also devise shortcuts for travelers and new laws of
|
||||
transformation.
|
||||
|
||||
Changes in the Kingdom
|
||||
======================
|
||||
|
||||
As new transformation kingdoms are created and old ones are maintained,
|
||||
CTK, Inc. is constantly learning new things. It learns ways to avoid
|
||||
creating some of the dragons that they have previously created. It also
|
||||
discovers new and better laws of transformation. As a result, CTK will
|
||||
periodically create a new grand design which is far better than the old.
|
||||
The wizards determine when is a good time to implement this new design.
|
||||
This is when the tourist season is slow or when no important travelers
|
||||
(VIPs) are to arrive. The kingdom must be closed for the actual
|
||||
implementation and is leter reopened as a new and better place to go.
|
||||
|
||||
A final question you might ask is what happens when the number of tourists
|
||||
becomes too great for the kingdom to handle in a reasonable period of time
|
||||
(i.e., the tourist lines at the ports are too long). The Kingdom of
|
||||
Transformation has three options: (1) shorten the paths that a tourist must
|
||||
travel, or (2) convince CTK to develop a faster breed of horses so that the
|
||||
travelers can finish sooner, or (3) annex more territories so that the
|
||||
kingdom can handle more travelers.
|
||||
|
||||
Thus ends the story of the Kingdom of Transformation. I hope this has
|
||||
explained my job to you: I slay dragons for a living.
|
||||
|
||||
#
|
||||
#should do an automatic undivert..
|
||||
#
|
||||
1016
usr.bin/m4/eval.c
Normal file
1016
usr.bin/m4/eval.c
Normal file
File diff suppressed because it is too large
Load Diff
50
usr.bin/m4/expr.c
Normal file
50
usr.bin/m4/expr.c
Normal file
@@ -0,0 +1,50 @@
|
||||
/* $NetBSD: expr.c,v 1.19 2009/10/26 21:11:28 christos Exp $ */
|
||||
/* $OpenBSD: expr.c,v 1.17 2006/01/20 23:10:19 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.
|
||||
*/
|
||||
#if HAVE_NBTOOL_CONFIG_H
|
||||
#include "nbtool_config.h"
|
||||
#endif
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: expr.c,v 1.19 2009/10/26 21:11:28 christos Exp $");
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include "mdef.h"
|
||||
#include "extern.h"
|
||||
|
||||
int32_t end_result;
|
||||
const char *copy_toeval;
|
||||
|
||||
extern void yy_scan_string(const char *);
|
||||
extern int yyparse(void);
|
||||
extern int yyerror(const char *);
|
||||
|
||||
int
|
||||
yyerror(const char *msg)
|
||||
{
|
||||
fprintf(stderr, "m4: %s in expr %s\n", msg, copy_toeval);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int
|
||||
expr(const char *toeval)
|
||||
{
|
||||
copy_toeval = toeval;
|
||||
yy_scan_string(toeval);
|
||||
yyparse();
|
||||
return end_result;
|
||||
}
|
||||
178
usr.bin/m4/extern.h
Normal file
178
usr.bin/m4/extern.h
Normal file
@@ -0,0 +1,178 @@
|
||||
/* $OpenBSD: extern.h,v 1.49 2009/10/14 17:19:47 sthen Exp $ */
|
||||
/* $NetBSD: extern.h,v 1.14 2009/10/26 21:12:47 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 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.
|
||||
*
|
||||
* @(#)extern.h 8.1 (Berkeley) 6/6/93
|
||||
*/
|
||||
|
||||
/* eval.c */
|
||||
extern void eval(const char *[], int, int, int);
|
||||
extern void dodefine(const char *, const char *);
|
||||
extern unsigned long expansion_id;
|
||||
|
||||
/* expr.c */
|
||||
extern int expr(const char *);
|
||||
|
||||
/* gnum4.c */
|
||||
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);
|
||||
extern void dopatsubst(const char *[], int);
|
||||
extern void doregexp(const char *[], int);
|
||||
|
||||
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 */
|
||||
|
||||
#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 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 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 void getdiv(int);
|
||||
extern ptrdiff_t indx(const char *, const char *);
|
||||
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 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 __dead m4errx(int, const char *, ...);
|
||||
|
||||
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/pushback */
|
||||
#define PUSHBACK(c) \
|
||||
do { \
|
||||
if (bp >= endpbb) \
|
||||
enlarge_bufspace(); \
|
||||
*bp++ = (c); \
|
||||
} while(0)
|
||||
|
||||
#define CHRSAVE(c) \
|
||||
do { \
|
||||
if (ep >= endest) \
|
||||
enlarge_strspace(); \
|
||||
*ep++ = (c); \
|
||||
} while(0)
|
||||
|
||||
/* and corresponding exposure for local symbols */
|
||||
extern void enlarge_bufspace(void);
|
||||
extern void enlarge_strspace(void);
|
||||
extern unsigned char *endpbb;
|
||||
extern char *endest;
|
||||
|
||||
/* trace.c */
|
||||
extern unsigned int trace_flags;
|
||||
#define TRACE_ALL 512
|
||||
extern void trace_file(const char *);
|
||||
extern size_t trace(const char **, int, struct input_file *);
|
||||
extern void finish_trace(size_t);
|
||||
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 FILE **outfile; /* diversion array(0=bitbucket) */
|
||||
extern int maxout; /* maximum number of diversions */
|
||||
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 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 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 synch_lines; /* line synchronisation directives */
|
||||
|
||||
extern int mimic_gnu; /* behaves like gnu-m4 */
|
||||
extern int prefix_builtins; /* prefix builtin macros with m4_ */
|
||||
|
||||
extern long long strtonum(const char *, long long, long long, const char **);
|
||||
669
usr.bin/m4/gnum4.c
Normal file
669
usr.bin/m4/gnum4.c
Normal file
@@ -0,0 +1,669 @@
|
||||
/* $NetBSD: gnum4.c,v 1.7 2009/10/26 21:16:49 christos Exp $ */
|
||||
/* $OpenBSD: gnum4.c,v 1.39 2008/08/21 21:01:04 espie Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1999 Marc Espie
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* functions needed to support gnu-m4 extensions, including a fake freezing
|
||||
*/
|
||||
#if HAVE_NBTOOL_CONFIG_H
|
||||
#include "nbtool_config.h"
|
||||
#endif
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: gnum4.c,v 1.7 2009/10/26 21:16:49 christos Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#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 <errno.h>
|
||||
#include <unistd.h>
|
||||
#include "mdef.h"
|
||||
#include "stdd.h"
|
||||
#include "extern.h"
|
||||
|
||||
|
||||
int mimic_gnu = 0;
|
||||
#ifndef SIZE_T_MAX
|
||||
#define SIZE_T_MAX (size_t)~0ull
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Support for include path search
|
||||
* First search in the current directory.
|
||||
* If not found, and the path is not absolute, include path kicks in.
|
||||
* First, -I options, in the order found on the command line.
|
||||
* Then M4PATH env variable
|
||||
*/
|
||||
|
||||
struct path_entry {
|
||||
char *name;
|
||||
struct path_entry *next;
|
||||
} *first, *last;
|
||||
|
||||
static struct path_entry *new_path_entry(const char *);
|
||||
static void ensure_m4path(void);
|
||||
static struct input_file *dopath(struct input_file *, const char *);
|
||||
|
||||
static struct path_entry *
|
||||
new_path_entry(const char *dirname)
|
||||
{
|
||||
struct path_entry *n;
|
||||
|
||||
n = malloc(sizeof(struct path_entry));
|
||||
if (!n)
|
||||
errx(1, "out of memory");
|
||||
n->name = strdup(dirname);
|
||||
if (!n->name)
|
||||
errx(1, "out of memory");
|
||||
n->next = 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
void
|
||||
addtoincludepath(const char *dirname)
|
||||
{
|
||||
struct path_entry *n;
|
||||
|
||||
n = new_path_entry(dirname);
|
||||
|
||||
if (last) {
|
||||
last->next = n;
|
||||
last = n;
|
||||
}
|
||||
else
|
||||
last = first = n;
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_m4path()
|
||||
{
|
||||
static int envpathdone = 0;
|
||||
char *envpath;
|
||||
char *sweep;
|
||||
char *path;
|
||||
|
||||
if (envpathdone)
|
||||
return;
|
||||
envpathdone = TRUE;
|
||||
envpath = getenv("M4PATH");
|
||||
if (!envpath)
|
||||
return;
|
||||
/* for portability: getenv result is read-only */
|
||||
envpath = strdup(envpath);
|
||||
if (!envpath)
|
||||
errx(1, "out of memory");
|
||||
for (sweep = envpath;
|
||||
(path = strsep(&sweep, ":")) != NULL;)
|
||||
addtoincludepath(path);
|
||||
free(envpath);
|
||||
}
|
||||
|
||||
static
|
||||
struct input_file *
|
||||
dopath(struct input_file *i, const char *filename)
|
||||
{
|
||||
char path[MAXPATHLEN];
|
||||
struct path_entry *pe;
|
||||
FILE *f;
|
||||
|
||||
for (pe = first; pe; pe = pe->next) {
|
||||
snprintf(path, sizeof(path), "%s/%s", pe->name, filename);
|
||||
if ((f = fopen(path, "r")) != 0) {
|
||||
set_input(i, f, path);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct input_file *
|
||||
fopen_trypath(struct input_file *i, const char *filename)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
f = fopen(filename, "r");
|
||||
if (f != NULL) {
|
||||
set_input(i, f, filename);
|
||||
return i;
|
||||
}
|
||||
if (filename[0] == '/')
|
||||
return NULL;
|
||||
|
||||
ensure_m4path();
|
||||
|
||||
return dopath(i, filename);
|
||||
}
|
||||
|
||||
void
|
||||
doindir(const char *argv[], int argc)
|
||||
{
|
||||
ndptr n;
|
||||
struct macro_definition *p;
|
||||
|
||||
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, is_traced(n));
|
||||
}
|
||||
|
||||
void
|
||||
dobuiltin(const char *argv[], int argc)
|
||||
{
|
||||
ndptr p;
|
||||
|
||||
argv[1] = NULL;
|
||||
p = macro_getbuiltin(argv[2]);
|
||||
if (p != NULL)
|
||||
eval(argv+1, argc-1, macro_builtin_type(p), is_traced(p));
|
||||
else
|
||||
m4errx(1, "unknown builtin %s.", argv[2]);
|
||||
}
|
||||
|
||||
|
||||
/* We need some temporary buffer space, as pb pushes BACK and substitution
|
||||
* proceeds forward... */
|
||||
static char *buffer;
|
||||
static size_t bufsize = 0;
|
||||
static size_t current = 0;
|
||||
|
||||
static void addchars(const char *, size_t);
|
||||
static void addchar(int);
|
||||
static char *twiddle(const char *);
|
||||
static char *getstring(void);
|
||||
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_replace(const char *, regex_t *, const char *, regmatch_t *);
|
||||
#define addconstantstring(s) addchars((s), sizeof(s)-1)
|
||||
|
||||
static void
|
||||
addchars(const char *c, size_t n)
|
||||
{
|
||||
if (n == 0)
|
||||
return;
|
||||
while (current + n > bufsize) {
|
||||
if (bufsize == 0)
|
||||
bufsize = 1024;
|
||||
else
|
||||
bufsize *= 2;
|
||||
buffer = xrealloc(buffer, bufsize, NULL);
|
||||
}
|
||||
memcpy(buffer+current, c, n);
|
||||
current += n;
|
||||
}
|
||||
|
||||
static void
|
||||
addchar(int c)
|
||||
{
|
||||
if (current +1 > bufsize) {
|
||||
if (bufsize == 0)
|
||||
bufsize = 1024;
|
||||
else
|
||||
bufsize *= 2;
|
||||
buffer = xrealloc(buffer, bufsize, NULL);
|
||||
}
|
||||
buffer[current++] = c;
|
||||
}
|
||||
|
||||
static char *
|
||||
getstring()
|
||||
{
|
||||
addchar('\0');
|
||||
current = 0;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
exit_regerror(int er, regex_t *re)
|
||||
{
|
||||
size_t errlen;
|
||||
char *errbuf;
|
||||
|
||||
errlen = regerror(er, re, NULL, 0);
|
||||
errbuf = xalloc(errlen,
|
||||
"malloc in regerror: %lu", (unsigned long)errlen);
|
||||
regerror(er, re, errbuf, errlen);
|
||||
m4errx(1, "regular expression error: %s.", errbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
add_sub(size_t n, const char *string, regex_t *re, regmatch_t *pm)
|
||||
{
|
||||
if (n > re->re_nsub)
|
||||
warnx("No subexpression %zu", n);
|
||||
/* Subexpressions that did not match are
|
||||
* not an error. */
|
||||
else if (pm[n].rm_so != -1 &&
|
||||
pm[n].rm_eo != -1) {
|
||||
addchars(string + pm[n].rm_so,
|
||||
pm[n].rm_eo - pm[n].rm_so);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add replacement string to the output buffer, recognizing special
|
||||
* constructs and replacing them with substrings of the original string.
|
||||
*/
|
||||
static void
|
||||
add_replace(const char *string, regex_t *re, const char *replace, regmatch_t *pm)
|
||||
{
|
||||
const char *p;
|
||||
|
||||
for (p = replace; *p != '\0'; p++) {
|
||||
if (*p == '&' && !mimic_gnu) {
|
||||
add_sub(0, string, re, pm);
|
||||
continue;
|
||||
}
|
||||
if (*p == '\\') {
|
||||
if (p[1] == '\\') {
|
||||
addchar(p[1]);
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
if (p[1] == '&') {
|
||||
if (mimic_gnu)
|
||||
add_sub(0, string, re, pm);
|
||||
else
|
||||
addchar(p[1]);
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
if (isdigit((unsigned char)p[1])) {
|
||||
add_sub(*(++p) - '0', string, re, pm);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
addchar(*p);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
do_subst(const char *string, regex_t *re, const char *replace, regmatch_t *pm)
|
||||
{
|
||||
int error;
|
||||
int flags = 0;
|
||||
const char *last_match = NULL;
|
||||
|
||||
while ((error = regexec(re, string, re->re_nsub+1, pm, flags)) == 0) {
|
||||
if (pm[0].rm_eo != 0) {
|
||||
if (string[pm[0].rm_eo-1] == '\n')
|
||||
flags = 0;
|
||||
else
|
||||
flags = REG_NOTBOL;
|
||||
}
|
||||
|
||||
/* NULL length matches are special... We use the `vi-mode'
|
||||
* rule: don't allow a NULL-match at the last match
|
||||
* position.
|
||||
*/
|
||||
if (pm[0].rm_so == pm[0].rm_eo &&
|
||||
string + pm[0].rm_so == last_match) {
|
||||
if (*string == '\0')
|
||||
return;
|
||||
addchar(*string);
|
||||
if (*string++ == '\n')
|
||||
flags = 0;
|
||||
else
|
||||
flags = REG_NOTBOL;
|
||||
continue;
|
||||
}
|
||||
last_match = string + pm[0].rm_so;
|
||||
addchars(string, pm[0].rm_so);
|
||||
add_replace(string, re, replace, pm);
|
||||
string += pm[0].rm_eo;
|
||||
}
|
||||
if (error != REG_NOMATCH)
|
||||
exit_regerror(error, re);
|
||||
pbstr(string);
|
||||
}
|
||||
|
||||
static void
|
||||
do_regexp(const char *string, regex_t *re, const char *replace, regmatch_t *pm)
|
||||
{
|
||||
int error;
|
||||
|
||||
switch(error = regexec(re, string, re->re_nsub+1, pm, 0)) {
|
||||
case 0:
|
||||
add_replace(string, re, replace, pm);
|
||||
pbstr(getstring());
|
||||
break;
|
||||
case REG_NOMATCH:
|
||||
break;
|
||||
default:
|
||||
exit_regerror(error, re);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
do_regexpindex(const char *string, regex_t *re, regmatch_t *pm)
|
||||
{
|
||||
int error;
|
||||
|
||||
switch(error = regexec(re, string, re->re_nsub+1, pm, 0)) {
|
||||
case 0:
|
||||
pbunsigned(pm[0].rm_so);
|
||||
break;
|
||||
case REG_NOMATCH:
|
||||
pbnum(-1);
|
||||
break;
|
||||
default:
|
||||
exit_regerror(error, re);
|
||||
}
|
||||
}
|
||||
|
||||
/* In Gnu m4 mode, parentheses for backmatch don't work like POSIX 1003.2
|
||||
* says. So we twiddle with the regexp before passing it to regcomp.
|
||||
*/
|
||||
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 == '\\') {
|
||||
switch(p[1]) {
|
||||
case '(':
|
||||
case ')':
|
||||
case '|':
|
||||
addchar(p[1]);
|
||||
break;
|
||||
case 'w':
|
||||
addconstantstring("[_a-zA-Z0-9]");
|
||||
break;
|
||||
case 'W':
|
||||
addconstantstring("[^_a-zA-Z0-9]");
|
||||
break;
|
||||
case '<':
|
||||
addconstantstring("[[:<:]]");
|
||||
break;
|
||||
case '>':
|
||||
addconstantstring("[[:>:]]");
|
||||
break;
|
||||
default:
|
||||
addchars(p, 2);
|
||||
break;
|
||||
}
|
||||
p+=2;
|
||||
continue;
|
||||
}
|
||||
if (*p == '(' || *p == ')' || *p == '|')
|
||||
addchar('\\');
|
||||
|
||||
addchar(*p);
|
||||
p++;
|
||||
}
|
||||
return getstring();
|
||||
}
|
||||
|
||||
/* patsubst(string, regexp, opt replacement) */
|
||||
/* argv[2]: string
|
||||
* argv[3]: regexp
|
||||
* argv[4]: opt rep
|
||||
*/
|
||||
void
|
||||
dopatsubst(const char *argv[], int argc)
|
||||
{
|
||||
if (argc <= 3) {
|
||||
warnx("Too few arguments to patsubst");
|
||||
return;
|
||||
}
|
||||
/* special case: empty regexp */
|
||||
if (argv[3][0] == '\0') {
|
||||
const char *s;
|
||||
size_t len;
|
||||
if (argv[4] && argc > 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]);
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
void
|
||||
doregexp(const char *argv[], int argc)
|
||||
{
|
||||
int error;
|
||||
regex_t re;
|
||||
regmatch_t *pmatch;
|
||||
|
||||
if (argc <= 3) {
|
||||
warnx("Too few arguments to regexp");
|
||||
return;
|
||||
}
|
||||
error = regcomp(&re, mimic_gnu ? twiddle(argv[3]) : argv[3],
|
||||
REG_EXTENDED);
|
||||
if (error != 0)
|
||||
exit_regerror(error, &re);
|
||||
|
||||
pmatch = xalloc(sizeof(regmatch_t) * (re.re_nsub+1), NULL);
|
||||
if (argv[4] == NULL || argc == 4)
|
||||
do_regexpindex(argv[2], &re, pmatch);
|
||||
else
|
||||
do_regexp(argv[2], &re, argv[4], pmatch);
|
||||
free(pmatch);
|
||||
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;
|
||||
char temp[2];
|
||||
size_t 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 {
|
||||
char *eformat;
|
||||
width = strtol(format, &eformat, 10);
|
||||
format = eformat;
|
||||
}
|
||||
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 {
|
||||
char *eformat;
|
||||
extra = strtol(format, &eformat, 10);
|
||||
format = eformat;
|
||||
}
|
||||
} else {
|
||||
extra = SIZE_T_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 (l > extra)
|
||||
l = extra;
|
||||
if (!left_padded) {
|
||||
while (l < (size_t)width--)
|
||||
addchar(' ');
|
||||
}
|
||||
addchars(thisarg, l);
|
||||
if (left_padded) {
|
||||
while (l < (size_t)width--)
|
||||
addchar(' ');
|
||||
}
|
||||
}
|
||||
pbstr(getstring());
|
||||
}
|
||||
|
||||
void
|
||||
doesyscmd(const char *cmd)
|
||||
{
|
||||
int p[2];
|
||||
pid_t pid, cpid;
|
||||
const char *argv[4];
|
||||
int cc;
|
||||
int status;
|
||||
|
||||
/* Follow gnu m4 documentation: first flush buffers. */
|
||||
fflush(NULL);
|
||||
|
||||
argv[0] = "sh";
|
||||
argv[1] = "-c";
|
||||
argv[2] = cmd;
|
||||
argv[3] = NULL;
|
||||
|
||||
/* Just set up standard output, share stderr and stdin with m4 */
|
||||
if (pipe(p) == -1)
|
||||
err(1, "bad pipe");
|
||||
switch(cpid = fork()) {
|
||||
case -1:
|
||||
err(1, "bad fork");
|
||||
/* NOTREACHED */
|
||||
case 0:
|
||||
(void) close(p[0]);
|
||||
(void) dup2(p[1], 1);
|
||||
(void) close(p[1]);
|
||||
execv(_PATH_BSHELL, __UNCONST(argv));
|
||||
exit(1);
|
||||
default:
|
||||
/* Read result in two stages, since m4's buffer is
|
||||
* pushback-only. */
|
||||
(void) close(p[1]);
|
||||
do {
|
||||
char result[BUFSIZE];
|
||||
cc = read(p[0], result, sizeof result);
|
||||
if (cc > 0)
|
||||
addchars(result, cc);
|
||||
} while (cc > 0 || (cc == -1 && errno == EINTR));
|
||||
|
||||
(void) close(p[0]);
|
||||
while ((pid = wait(&status)) != cpid && pid >= 0)
|
||||
continue;
|
||||
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);
|
||||
}
|
||||
73
usr.bin/m4/lib/ohash.h
Normal file
73
usr.bin/m4/lib/ohash.h
Normal file
@@ -0,0 +1,73 @@
|
||||
#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.
|
||||
*/
|
||||
|
||||
/* 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
|
||||
|
||||
38
usr.bin/m4/lib/ohash_create_entry.c
Normal file
38
usr.bin/m4/lib/ohash_create_entry.c
Normal file
@@ -0,0 +1,38 @@
|
||||
/* $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 "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;
|
||||
}
|
||||
31
usr.bin/m4/lib/ohash_delete.c
Normal file
31
usr.bin/m4/lib/ohash_delete.c
Normal file
@@ -0,0 +1,31 @@
|
||||
/* $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 "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
|
||||
}
|
||||
111
usr.bin/m4/lib/ohash_do.c
Normal file
111
usr.bin/m4/lib/ohash_do.c
Normal file
@@ -0,0 +1,111 @@
|
||||
/* $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 "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 = __UNCONST(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 __UNCONST(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;
|
||||
}
|
||||
26
usr.bin/m4/lib/ohash_entries.c
Normal file
26
usr.bin/m4/lib/ohash_entries.c
Normal file
@@ -0,0 +1,26 @@
|
||||
/* $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 "ohash_int.h"
|
||||
|
||||
unsigned int
|
||||
ohash_entries(struct ohash *h)
|
||||
{
|
||||
return h->total - h->deleted;
|
||||
}
|
||||
36
usr.bin/m4/lib/ohash_enum.c
Normal file
36
usr.bin/m4/lib/ohash_enum.c
Normal file
@@ -0,0 +1,36 @@
|
||||
/* $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 "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 __UNCONST(h->t[(*pos)++].p);
|
||||
return NULL;
|
||||
}
|
||||
229
usr.bin/m4/lib/ohash_init.3
Normal file
229
usr.bin/m4/lib/ohash_init.3
Normal file
@@ -0,0 +1,229 @@
|
||||
.\" $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.
|
||||
.\"
|
||||
.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.
|
||||
41
usr.bin/m4/lib/ohash_init.c
Normal file
41
usr.bin/m4/lib/ohash_init.c
Normal file
@@ -0,0 +1,41 @@
|
||||
/* $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 "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;
|
||||
}
|
||||
23
usr.bin/m4/lib/ohash_int.h
Normal file
23
usr.bin/m4/lib/ohash_int.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/* $OpenBSD: ohash_int.h,v 1.3 2006/01/16 15:52:25 espie Exp $ */
|
||||
|
||||
#if HAVE_NBTOOL_CONFIG_H
|
||||
#include "nbtool_config.h"
|
||||
#endif
|
||||
|
||||
#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
|
||||
90
usr.bin/m4/lib/ohash_interval.3
Normal file
90
usr.bin/m4/lib/ohash_interval.3
Normal file
@@ -0,0 +1,90 @@
|
||||
.\" $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.
|
||||
.\"
|
||||
.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.
|
||||
36
usr.bin/m4/lib/ohash_interval.c
Normal file
36
usr.bin/m4/lib/ohash_interval.c
Normal file
@@ -0,0 +1,36 @@
|
||||
/* $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 "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;
|
||||
}
|
||||
68
usr.bin/m4/lib/ohash_lookup_interval.c
Normal file
68
usr.bin/m4/lib/ohash_lookup_interval.c
Normal file
@@ -0,0 +1,68 @@
|
||||
/* $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 "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;
|
||||
}
|
||||
64
usr.bin/m4/lib/ohash_lookup_memory.c
Normal file
64
usr.bin/m4/lib/ohash_lookup_memory.c
Normal file
@@ -0,0 +1,64 @@
|
||||
/* $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 "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;
|
||||
}
|
||||
27
usr.bin/m4/lib/ohash_qlookup.c
Normal file
27
usr.bin/m4/lib/ohash_qlookup.c
Normal file
@@ -0,0 +1,27 @@
|
||||
/* $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 "ohash_int.h"
|
||||
|
||||
unsigned int
|
||||
ohash_qlookup(struct ohash *h, const char *s)
|
||||
{
|
||||
const char *e = NULL;
|
||||
return ohash_qlookupi(h, s, &e);
|
||||
}
|
||||
29
usr.bin/m4/lib/ohash_qlookupi.c
Normal file
29
usr.bin/m4/lib/ohash_qlookupi.c
Normal file
@@ -0,0 +1,29 @@
|
||||
/* $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 "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);
|
||||
}
|
||||
73
usr.bin/m4/lib/strtonum.c
Normal file
73
usr.bin/m4/lib/strtonum.c
Normal file
@@ -0,0 +1,73 @@
|
||||
/* $OpenBSD: strtonum.c,v 1.6 2004/08/03 19:38:01 millert Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2004 Ted Unangst and Todd Miller
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#if HAVE_NBTOOL_CONFIG_H
|
||||
#include "nbtool_config.h"
|
||||
#endif
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: strtonum.c,v 1.2 2009/10/26 21:14:18 christos Exp $");
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define INVALID 1
|
||||
#define TOOSMALL 2
|
||||
#define TOOLARGE 3
|
||||
|
||||
long long
|
||||
strtonum(const char *numstr, long long minval, long long maxval,
|
||||
const char **errstrp);
|
||||
long long
|
||||
strtonum(const char *numstr, long long minval, long long maxval,
|
||||
const char **errstrp)
|
||||
{
|
||||
long long ll = 0;
|
||||
char *ep;
|
||||
int error = 0;
|
||||
struct errval {
|
||||
const char *errstr;
|
||||
int err;
|
||||
} ev[4] = {
|
||||
{ NULL, 0 },
|
||||
{ "invalid", EINVAL },
|
||||
{ "too small", ERANGE },
|
||||
{ "too large", ERANGE },
|
||||
};
|
||||
|
||||
ev[0].err = errno;
|
||||
errno = 0;
|
||||
if (minval > maxval)
|
||||
error = INVALID;
|
||||
else {
|
||||
ll = strtoll(numstr, &ep, 10);
|
||||
if (numstr == ep || *ep != '\0')
|
||||
error = INVALID;
|
||||
else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
|
||||
error = TOOSMALL;
|
||||
else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
|
||||
error = TOOLARGE;
|
||||
}
|
||||
if (errstrp != NULL)
|
||||
*errstrp = ev[error].errstr;
|
||||
errno = ev[error].err;
|
||||
if (error)
|
||||
ll = 0;
|
||||
|
||||
return (ll);
|
||||
}
|
||||
|
||||
287
usr.bin/m4/look.c
Normal file
287
usr.bin/m4/look.c
Normal file
@@ -0,0 +1,287 @@
|
||||
/* $NetBSD: look.c,v 1.11 2009/10/26 21:11:28 christos Exp $ */
|
||||
/* $OpenBSD: look.c,v 1.21 2009/10/14 17:23:17 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* look.c
|
||||
* Facility: m4 macro processor
|
||||
* by: oz
|
||||
*/
|
||||
#if HAVE_NBTOOL_CONFIG_H
|
||||
#include "nbtool_config.h"
|
||||
#endif
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: look.c,v 1.11 2009/10/26 21:11:28 christos Exp $");
|
||||
#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 *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 *);
|
||||
|
||||
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(s, u)
|
||||
size_t s;
|
||||
void *u UNUSED;
|
||||
{
|
||||
void *storage = xalloc(s, "hash alloc");
|
||||
if (storage)
|
||||
memset(storage, 0, s);
|
||||
return storage;
|
||||
}
|
||||
|
||||
void
|
||||
hash_free(p, s, u)
|
||||
void *p;
|
||||
size_t s UNUSED;
|
||||
void *u UNUSED;
|
||||
{
|
||||
free(p);
|
||||
}
|
||||
|
||||
void *
|
||||
element_alloc(s, u)
|
||||
size_t s;
|
||||
void *u UNUSED;
|
||||
{
|
||||
return xalloc(s, "element alloc");
|
||||
}
|
||||
|
||||
void
|
||||
init_macros()
|
||||
{
|
||||
ohash_init(¯os, 10, ¯o_info);
|
||||
}
|
||||
|
||||
/*
|
||||
* find name in the hash table
|
||||
*/
|
||||
ndptr
|
||||
lookup(const char *name)
|
||||
{
|
||||
return ohash_find(¯os, ohash_qlookup(¯os, name));
|
||||
}
|
||||
|
||||
struct macro_definition *
|
||||
lookup_macro_definition(const char *name)
|
||||
{
|
||||
ndptr p;
|
||||
|
||||
p = ohash_find(¯os, ohash_qlookup(¯os, name));
|
||||
if (p)
|
||||
return p->d;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
setup_definition(struct macro_definition *d, const char *defn, const char *name)
|
||||
{
|
||||
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 = xstrdup(null);
|
||||
else
|
||||
d->defn = xstrdup(defn);
|
||||
d->type = MACRTYPE;
|
||||
}
|
||||
if (STREQ(name, defn))
|
||||
d->type |= RECDEF;
|
||||
}
|
||||
|
||||
static ndptr
|
||||
create_entry(const char *name)
|
||||
{
|
||||
const char *end = NULL;
|
||||
unsigned int i;
|
||||
ndptr n;
|
||||
|
||||
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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
493
usr.bin/m4/m4.1
Normal file
493
usr.bin/m4/m4.1
Normal file
@@ -0,0 +1,493 @@
|
||||
.\" $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.
|
||||
.\"
|
||||
.Dd October 14, 2009
|
||||
.Dt M4 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm m4
|
||||
.Nd macro language processor
|
||||
.Sh SYNOPSIS
|
||||
.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 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 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).
|
||||
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 name(argument1[, argument2, ..., argumentN]).
|
||||
.Pp
|
||||
There cannot be any space following the macro name and the open
|
||||
parenthesis
|
||||
.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 [a-zA-Z_][a-zA-Z0-9_]* .
|
||||
.Pp
|
||||
In arguments to macros, leading unquoted space, tab, and newline
|
||||
.Pq Sq \en
|
||||
characters are ignored.
|
||||
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 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 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 d Ar "flags"
|
||||
Set trace flags.
|
||||
.Ar flags
|
||||
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
|
||||
.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 "U" Ns Ar "name"
|
||||
Undefine the symbol
|
||||
.Ar name .
|
||||
.El
|
||||
.Sh SYNTAX
|
||||
.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 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.
|
||||
.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 $n
|
||||
(where
|
||||
.Ar n
|
||||
is 0 through 9) is replaced by the
|
||||
.Ar n Ns 'th
|
||||
argument.
|
||||
.Sq $0
|
||||
is the name of the calling macro.
|
||||
Undefined arguments are replaced by a null string.
|
||||
.Sq $#
|
||||
is replaced by the number of arguments;
|
||||
.Sq $*
|
||||
is replaced by all arguments comma separated;
|
||||
.Sq $@
|
||||
is the same as
|
||||
.Sq $*
|
||||
but all arguments are quoted against further expansion.
|
||||
.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 Fn divert num
|
||||
There are 10 output queues (numbered 0-9).
|
||||
At the end of processing
|
||||
.Nm m4
|
||||
concatenates all the queues in numerical order to produce the
|
||||
final output.
|
||||
Initially the output queue is 0.
|
||||
The divert
|
||||
macro allows you to select a new output queue (an invalid argument
|
||||
passed to divert causes output to be discarded).
|
||||
.It Ic divnum
|
||||
Returns the current output queue number.
|
||||
.It Ic dnl
|
||||
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 Fn errprint msg
|
||||
Prints the first argument on the standard error output stream.
|
||||
.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 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,
|
||||
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 minimum number of digits in the result.
|
||||
.It Fn expr expr
|
||||
This is an alias for
|
||||
.Ic eval .
|
||||
.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
|
||||
.Qq unix
|
||||
is predefined.
|
||||
.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
|
||||
.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 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
|
||||
.Fl I
|
||||
on the command line, then the environment variable
|
||||
.Ev M4PATH ,
|
||||
as a colon-separated list of directories.
|
||||
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 Fn index string substring
|
||||
Returns the index of the second argument in the first argument (e.g.,
|
||||
.Ic index(the quick brown fox jumped, fox)
|
||||
returns 16).
|
||||
If the second
|
||||
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 Fn m4exit code
|
||||
Immediately exits with the return value specified by the first argument,
|
||||
0 if none.
|
||||
.It Fn m4wrap todo
|
||||
Allows you to define what happens at the final
|
||||
.Dv EOF ,
|
||||
usually for cleanup purposes (e.g.,
|
||||
.Ic m4wrap("cleanup(tempfile)")
|
||||
causes the macro cleanup to be
|
||||
invoked after all other processing is done).
|
||||
.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 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 Fn patsubst string regexp replacement
|
||||
Substitutes a regular expression in a string with a replacement string.
|
||||
Usual substitution patterns apply: an ampersand
|
||||
.Pq Sq \&&
|
||||
is replaced by the string matching the regular expression.
|
||||
The string
|
||||
.Sq \e# ,
|
||||
where
|
||||
.Sq #
|
||||
is a digit, is replaced by the corresponding back-reference.
|
||||
.It Fn popdef arg ...
|
||||
Restores the
|
||||
.Ic pushdef Ns ed
|
||||
definition for each argument.
|
||||
.It Fn pushdef macro def
|
||||
Takes the same arguments as
|
||||
.Ic define ,
|
||||
but it saves the definition on a
|
||||
stack for later retrieval by
|
||||
.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 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 Fn sinclude file
|
||||
Similar to
|
||||
.Ic include ,
|
||||
except it ignores any errors.
|
||||
.It Fn spaste file
|
||||
Similar to
|
||||
.Fn paste ,
|
||||
except it ignores any errors.
|
||||
.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 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 Fn traceon arg ...
|
||||
Enables tracing of macro expansions for the given arguments, or for all
|
||||
macros if no argument is given.
|
||||
.It Fn traceoff arg ...
|
||||
Disables tracing of macro expansions for the given arguments, or for all
|
||||
macros if no argument is given.
|
||||
.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 Fn undefine name1 ...
|
||||
Removes the definition for the macros specified by its arguments.
|
||||
.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.
|
||||
.It Ic __line__
|
||||
Returns the current file's line number.
|
||||
.It Ic __file__
|
||||
Returns the current file's name.
|
||||
.El
|
||||
.Sh STANDARDS
|
||||
The
|
||||
.Nm
|
||||
utility is compliant with the
|
||||
.St -p1003.1-2008
|
||||
specification.
|
||||
.Pp
|
||||
The flags
|
||||
.Op Fl dgIot
|
||||
and the macros
|
||||
.Ic builtin ,
|
||||
.Ic esyscmd ,
|
||||
.Ic expr ,
|
||||
.Ic format ,
|
||||
.Ic indir ,
|
||||
.Ic paste ,
|
||||
.Ic patsubst ,
|
||||
.Ic regexp ,
|
||||
.Ic spaste ,
|
||||
.Ic unix ,
|
||||
.Ic __line__ ,
|
||||
and
|
||||
.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 m4 .
|
||||
.Pp
|
||||
Many other
|
||||
.Nm
|
||||
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 .
|
||||
639
usr.bin/m4/main.c
Normal file
639
usr.bin/m4/main.c
Normal file
@@ -0,0 +1,639 @@
|
||||
/* $OpenBSD: main.c,v 1.77 2009/10/14 17:19:47 sthen Exp $ */
|
||||
/* $NetBSD: main.c,v 1.39 2009/11/06 15:13:27 joerg 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* main.c
|
||||
* Facility: m4 macro processor
|
||||
* by: oz
|
||||
*/
|
||||
#if HAVE_NBTOOL_CONFIG_H
|
||||
#include "nbtool_config.h"
|
||||
#endif
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: main.c,v 1.39 2009/11/06 15:13:27 joerg Exp $");
|
||||
#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 <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 */
|
||||
static size_t STACKMAX; /* current maximum size of stack */
|
||||
int sp; /* current m4 stack pointer */
|
||||
int fp; /* m4 call frame pointer */
|
||||
struct input_file infile[MAXINP];/* input file stack (0=stdin) */
|
||||
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.. */
|
||||
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 synch_lines = 0; /* line synchronisation for C preprocessor */
|
||||
int prefix_builtins = 0; /* -P option to prefix builtin keywords */
|
||||
|
||||
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 },
|
||||
{ "defn", DEFNTYPE },
|
||||
{ "divert", DIVRTYPE | NOARGS },
|
||||
{ "expr", EXPRTYPE },
|
||||
{ "eval", EXPRTYPE },
|
||||
{ "substr", SUBSTYPE },
|
||||
{ "ifelse", IFELTYPE },
|
||||
{ "ifdef", IFDFTYPE },
|
||||
{ "len", LENGTYPE },
|
||||
{ "incr", INCRTYPE },
|
||||
{ "decr", DECRTYPE },
|
||||
{ "dnl", DNLNTYPE | NOARGS },
|
||||
{ "changequote", CHNQTYPE | NOARGS },
|
||||
{ "changecom", CHNCTYPE | NOARGS },
|
||||
{ "index", INDXTYPE },
|
||||
#ifdef EXTENDED
|
||||
{ "paste", PASTTYPE },
|
||||
{ "spaste", SPASTYPE },
|
||||
/* Newer extensions, needed to handle gnu-m4 scripts */
|
||||
{ "indir", INDIRTYPE},
|
||||
{ "builtin", BUILTINTYPE},
|
||||
{ "patsubst", PATSTYPE},
|
||||
{ "regexp", REGEXPTYPE},
|
||||
{ "esyscmd", ESYSCMDTYPE},
|
||||
{ "__file__", FILENAMETYPE | NOARGS},
|
||||
{ "__line__", LINETYPE | NOARGS},
|
||||
#endif
|
||||
{ "popdef", POPDTYPE },
|
||||
{ "pushdef", PUSDTYPE },
|
||||
{ "dumpdef", DUMPTYPE | NOARGS },
|
||||
{ "shift", SHIFTYPE | NOARGS },
|
||||
{ "translit", TRNLTYPE },
|
||||
{ "undefine", UNDFTYPE },
|
||||
{ "undivert", UNDVTYPE | NOARGS },
|
||||
{ "divnum", DIVNTYPE | NOARGS },
|
||||
{ "maketemp", MKTMTYPE },
|
||||
{ "errprint", ERRPTYPE | NOARGS },
|
||||
{ "m4wrap", M4WRTYPE | NOARGS },
|
||||
{ "m4exit", EXITTYPE | NOARGS },
|
||||
{ "syscmd", SYSCTYPE },
|
||||
{ "sysval", SYSVTYPE | NOARGS },
|
||||
{ "traceon", TRACEONTYPE | NOARGS },
|
||||
{ "traceoff", TRACEOFFTYPE | NOARGS },
|
||||
|
||||
#if defined(unix) || defined(__unix__)
|
||||
{ "unix", SELFTYPE | NOARGS },
|
||||
#else
|
||||
#ifdef vms
|
||||
{ "vms", SELFTYPE | NOARGS },
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
#define MAXKEYS (sizeof(keywrds)/sizeof(struct keyblk))
|
||||
|
||||
extern int optind;
|
||||
extern char *optarg;
|
||||
|
||||
#define MAXRECORD 50
|
||||
static struct position {
|
||||
char *name;
|
||||
unsigned long line;
|
||||
} quotes[MAXRECORD], paren[MAXRECORD];
|
||||
|
||||
static void record(struct position *, int);
|
||||
static void dump_stack(struct position *, int);
|
||||
|
||||
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;
|
||||
char *p;
|
||||
|
||||
setprogname(argv[0]);
|
||||
|
||||
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
|
||||
signal(SIGINT, onintr);
|
||||
|
||||
init_macros();
|
||||
initspaces();
|
||||
STACKMAX = INITSTACKMAX;
|
||||
|
||||
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:P")) != -1)
|
||||
switch(c) {
|
||||
|
||||
case 'D': /* define something..*/
|
||||
for (p = optarg; *p; p++)
|
||||
if (*p == '=')
|
||||
break;
|
||||
if (*p)
|
||||
*p++ = EOS;
|
||||
dodefine(optarg, p);
|
||||
break;
|
||||
case 'I':
|
||||
addtoincludepath(optarg);
|
||||
break;
|
||||
case 'P':
|
||||
prefix_builtins = 1;
|
||||
break;
|
||||
case 'U': /* undefine... */
|
||||
macro_popdef(optarg);
|
||||
break;
|
||||
case 'g':
|
||||
mimic_gnu = 1;
|
||||
break;
|
||||
case 'd':
|
||||
set_trace_flags(optarg);
|
||||
break;
|
||||
case 's':
|
||||
synch_lines = 1;
|
||||
break;
|
||||
case 't':
|
||||
mark_traced(optarg, 1);
|
||||
break;
|
||||
case 'o':
|
||||
trace_file(optarg);
|
||||
break;
|
||||
case '?':
|
||||
usage();
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
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 */
|
||||
set_input(infile+0, stdin, "stdin");
|
||||
/* default input (naturally) */
|
||||
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)
|
||||
err(1, "%s", p);
|
||||
sp = -1;
|
||||
fp = 0;
|
||||
macro();
|
||||
release_input(infile);
|
||||
}
|
||||
|
||||
if (wrapindex) {
|
||||
int i;
|
||||
|
||||
ilevel = 0; /* in case m4wrap includes.. */
|
||||
bufbase = bp = buf; /* use the entire buffer */
|
||||
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)
|
||||
active = stdout; /* reset output just in case */
|
||||
for (n = 1; n < maxout; n++) /* default wrap-up: undivert */
|
||||
if (outfile[n] != NULL)
|
||||
getdiv(n);
|
||||
/* remove bitbucket if used */
|
||||
if (outfile[0] != NULL) {
|
||||
(void) fclose(outfile[0]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look ahead for `token'.
|
||||
* (on input `t == token[0]')
|
||||
* Used for comment and quoting delimiters.
|
||||
* Returns 1 if `token' present; copied to output.
|
||||
* 0 if `token' not found; all characters pushed back
|
||||
*/
|
||||
static int
|
||||
do_look_ahead(int t, const char *token)
|
||||
{
|
||||
int i;
|
||||
|
||||
assert((unsigned char)t == (unsigned char)token[0]);
|
||||
|
||||
for (i = 1; *++token; i++) {
|
||||
t = gpbc();
|
||||
if (t == EOF || (unsigned char)t != (unsigned char)*token) {
|
||||
pushback(t);
|
||||
while (--i)
|
||||
pushback(*--token);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define LOOK_AHEAD(t, token) (t != EOF && \
|
||||
(unsigned char)(t)==(unsigned char)(token)[0] && \
|
||||
do_look_ahead(t,token))
|
||||
|
||||
/*
|
||||
* macro - the work horse..
|
||||
*/
|
||||
static void
|
||||
macro(void)
|
||||
{
|
||||
char token[MAXTOK+1];
|
||||
int t, l;
|
||||
ndptr p;
|
||||
int nlpar;
|
||||
|
||||
cycle {
|
||||
t = gpbc();
|
||||
|
||||
if (LOOK_AHEAD(t,lquote)) { /* strip quotes */
|
||||
nlpar = 0;
|
||||
record(quotes, nlpar++);
|
||||
/*
|
||||
* Opening quote: scan forward until matching
|
||||
* closing quote has been found.
|
||||
*/
|
||||
do {
|
||||
|
||||
l = gpbc();
|
||||
if (LOOK_AHEAD(l,rquote)) {
|
||||
if (--nlpar > 0)
|
||||
outputstr(rquote);
|
||||
} else if (LOOK_AHEAD(l,lquote)) {
|
||||
record(quotes, nlpar++);
|
||||
outputstr(lquote);
|
||||
} else if (l == EOF) {
|
||||
if (nlpar == 1)
|
||||
warnx("unclosed quote:");
|
||||
else
|
||||
warnx("%d unclosed quotes:", nlpar);
|
||||
dump_stack(quotes, nlpar);
|
||||
exit(1);
|
||||
} else {
|
||||
if (nlpar > 0) {
|
||||
if (sp < 0)
|
||||
reallyputchar(l);
|
||||
else
|
||||
CHRSAVE(l);
|
||||
}
|
||||
}
|
||||
}
|
||||
while (nlpar != 0);
|
||||
} else if (sp < 0 && LOOK_AHEAD(t, scommt)) {
|
||||
reallyoutputstr(scommt);
|
||||
|
||||
for(;;) {
|
||||
t = gpbc();
|
||||
if (LOOK_AHEAD(t, ecommt)) {
|
||||
reallyoutputstr(ecommt);
|
||||
break;
|
||||
}
|
||||
if (t == EOF)
|
||||
break;
|
||||
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..*/
|
||||
|
||||
if (l != LPAREN && PARLEV == 0) {
|
||||
/* no bracks */
|
||||
chrsave(EOS);
|
||||
|
||||
if ((size_t)sp == 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) {
|
||||
|
||||
case LPAREN:
|
||||
if (PARLEV > 0)
|
||||
chrsave(t);
|
||||
while (isspace(l = gpbc())) /* skip blank, tab, nl.. */
|
||||
if (PARLEV > 0)
|
||||
chrsave(l);
|
||||
pushback(l);
|
||||
record(paren, PARLEV++);
|
||||
break;
|
||||
|
||||
case RPAREN:
|
||||
if (--PARLEV > 0)
|
||||
chrsave(t);
|
||||
else { /* end of argument list */
|
||||
chrsave(EOS);
|
||||
|
||||
if ((size_t)sp == STACKMAX)
|
||||
errx(1, "internal stack overflow");
|
||||
|
||||
eval((const char **) mstack+fp+1, sp-fp,
|
||||
CALTYP, TRACESTATUS);
|
||||
|
||||
ep = PREVEP; /* flush strspace */
|
||||
sp = PREVSP; /* previous sp.. */
|
||||
fp = PREVFP; /* rewind stack...*/
|
||||
}
|
||||
break;
|
||||
|
||||
case COMMA:
|
||||
if (PARLEV == 1) {
|
||||
chrsave(EOS); /* new argument */
|
||||
while (isspace(l = gpbc()))
|
||||
;
|
||||
pushback(l);
|
||||
pushs(ep);
|
||||
} else
|
||||
chrsave(t);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (LOOK_AHEAD(t, scommt)) {
|
||||
char *q;
|
||||
for (q = scommt; *q; p++)
|
||||
chrsave(*q);
|
||||
for(;;) {
|
||||
t = gpbc();
|
||||
if (LOOK_AHEAD(t, ecommt)) {
|
||||
for (q = ecommt; *q; q++)
|
||||
chrsave(*q);
|
||||
break;
|
||||
}
|
||||
if (t == EOF)
|
||||
break;
|
||||
CHRSAVE(t);
|
||||
}
|
||||
} else
|
||||
CHRSAVE(t); /* stack the char */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* output string directly, without pushing it for reparses.
|
||||
*/
|
||||
void
|
||||
outputstr(const char *s)
|
||||
{
|
||||
if (sp < 0)
|
||||
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.
|
||||
*/
|
||||
static ndptr
|
||||
inspect(int c, char *tp)
|
||||
{
|
||||
char *name = tp;
|
||||
char *etp = tp+MAXTOK;
|
||||
ndptr p;
|
||||
|
||||
*tp++ = c;
|
||||
|
||||
while ((isalnum(c = gpbc()) || c == '_') && tp < etp)
|
||||
*tp++ = c;
|
||||
if (c != EOF)
|
||||
PUSHBACK(c);
|
||||
*tp = EOS;
|
||||
/* token is too long, it won't match anything, but it can still
|
||||
* be output. */
|
||||
if (tp == ep) {
|
||||
outputstr(name);
|
||||
while (isalnum(c = gpbc()) || c == '_') {
|
||||
if (sp < 0)
|
||||
reallyputchar(c);
|
||||
else
|
||||
CHRSAVE(c);
|
||||
}
|
||||
*name = EOS;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* initkwds - initialise m4 keywords as fast as possible.
|
||||
* This very similar to install, but without certain overheads,
|
||||
* such as calling lookup. Malloc is not used for storing the
|
||||
* keyword strings, since we simply use the static pointers
|
||||
* within keywrds block.
|
||||
*/
|
||||
static void
|
||||
initkwds(void)
|
||||
{
|
||||
unsigned int type;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < MAXKEYS; i++) {
|
||||
type = keywrds[i].ktyp & TYPEMASK;
|
||||
if ((keywrds[i].ktyp & NOARGS) == 0)
|
||||
type |= NEEDARGS;
|
||||
setup_builtin(keywrds[i].knam, type);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
record(struct position *t, int lev)
|
||||
{
|
||||
if (lev < MAXRECORD) {
|
||||
t[lev].name = CURRENT_NAME;
|
||||
t[lev].line = CURRENT_LINE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dump_stack(struct position *t, int lev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < lev; i++) {
|
||||
if (i == MAXRECORD) {
|
||||
fprintf(stderr, " ...\n");
|
||||
break;
|
||||
}
|
||||
fprintf(stderr, " %s at line %lu\n",
|
||||
t[i].name, t[i].line);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
enlarge_stack(void)
|
||||
{
|
||||
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);
|
||||
}
|
||||
229
usr.bin/m4/mdef.h
Normal file
229
usr.bin/m4/mdef.h
Normal file
@@ -0,0 +1,229 @@
|
||||
/* $OpenBSD: mdef.h,v 1.29 2006/03/20 20:27:45 espie Exp $ */
|
||||
/* $NetBSD: mdef.h,v 1.13 2009/10/26 21:11:28 christos 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.
|
||||
*
|
||||
* @(#)mdef.h 8.1 (Berkeley) 6/6/93
|
||||
*/
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define UNUSED __attribute__((__unused__))
|
||||
#else
|
||||
# define UNUSED
|
||||
#endif
|
||||
|
||||
#define MACRTYPE 1
|
||||
#define DEFITYPE 2
|
||||
#define EXPRTYPE 3
|
||||
#define SUBSTYPE 4
|
||||
#define IFELTYPE 5
|
||||
#define LENGTYPE 6
|
||||
#define CHNQTYPE 7
|
||||
#define SYSCTYPE 8
|
||||
#define UNDFTYPE 9
|
||||
#define INCLTYPE 10
|
||||
#define SINCTYPE 11
|
||||
#define PASTTYPE 12
|
||||
#define SPASTYPE 13
|
||||
#define INCRTYPE 14
|
||||
#define IFDFTYPE 15
|
||||
#define PUSDTYPE 16
|
||||
#define POPDTYPE 17
|
||||
#define SHIFTYPE 18
|
||||
#define DECRTYPE 19
|
||||
#define DIVRTYPE 20
|
||||
#define UNDVTYPE 21
|
||||
#define DIVNTYPE 22
|
||||
#define MKTMTYPE 23
|
||||
#define ERRPTYPE 24
|
||||
#define M4WRTYPE 25
|
||||
#define TRNLTYPE 26
|
||||
#define DNLNTYPE 27
|
||||
#define DUMPTYPE 28
|
||||
#define CHNCTYPE 29
|
||||
#define INDXTYPE 30
|
||||
#define SYSVTYPE 31
|
||||
#define EXITTYPE 32
|
||||
#define DEFNTYPE 33
|
||||
#define SELFTYPE 34
|
||||
#define INDIRTYPE 35
|
||||
#define BUILTINTYPE 36
|
||||
#define PATSTYPE 37
|
||||
#define FILENAMETYPE 38
|
||||
#define LINETYPE 39
|
||||
#define REGEXPTYPE 40
|
||||
#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 */
|
||||
#define NOARGS 512 /* builtin needs no args */
|
||||
#define NEEDARGS 1024 /* mark builtin that need args with this */
|
||||
|
||||
/*
|
||||
* m4 special characters
|
||||
*/
|
||||
|
||||
#define ARGFLAG '$'
|
||||
#define LPAREN '('
|
||||
#define RPAREN ')'
|
||||
#define LQUOTE '`'
|
||||
#define RQUOTE '\''
|
||||
#define COMMA ','
|
||||
#define SCOMMT '#'
|
||||
#define ECOMMT '\n'
|
||||
|
||||
#ifdef msdos
|
||||
#define system(str) (-1)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* other important constants
|
||||
*/
|
||||
|
||||
#define EOS '\0'
|
||||
#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 STRSPMAX 4096 /* starting size of string space */
|
||||
#define MAXTOK 512 /* maximum chars in a tokn */
|
||||
#define HASHSIZE 199 /* maximum size of hashtab */
|
||||
#define MAXCCHARS 5 /* max size of comment/quote delim */
|
||||
|
||||
#define ALL 1
|
||||
#define TOP 0
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#define cycle for(;;)
|
||||
|
||||
/*
|
||||
* m4 data structures
|
||||
*/
|
||||
|
||||
typedef struct ndblock *ndptr;
|
||||
|
||||
struct macro_definition {
|
||||
struct macro_definition *next;
|
||||
char *defn; /* definition.. */
|
||||
unsigned int type; /* type of the entry.. */
|
||||
};
|
||||
|
||||
|
||||
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 */
|
||||
} stae;
|
||||
|
||||
struct input_file {
|
||||
FILE *file;
|
||||
char *name;
|
||||
unsigned long lineno;
|
||||
unsigned long synch_lineno; /* used for -s */
|
||||
int c;
|
||||
};
|
||||
|
||||
#define CURRENT_NAME (infile[ilevel].name)
|
||||
#define CURRENT_LINE (infile[ilevel].lineno)
|
||||
/*
|
||||
* 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 gpbc() (bp > bufbase) ? *--bp : obtain_char(infile+ilevel)
|
||||
#define pushf(x) \
|
||||
do { \
|
||||
if ((size_t)++sp == STACKMAX) \
|
||||
enlarge_stack();\
|
||||
mstack[sp].sfra = (x); \
|
||||
sstack[sp] = 0; \
|
||||
} while (0)
|
||||
|
||||
#define pushs(x) \
|
||||
do { \
|
||||
if ((size_t)++sp == STACKMAX) \
|
||||
enlarge_stack();\
|
||||
mstack[sp].sstr = (x); \
|
||||
sstack[sp] = 1; \
|
||||
} while (0)
|
||||
|
||||
#define pushs1(x) \
|
||||
do { \
|
||||
if ((size_t)++sp == STACKMAX) \
|
||||
enlarge_stack();\
|
||||
mstack[sp].sstr = (x); \
|
||||
sstack[sp] = 0; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* . .
|
||||
* | . | <-- sp | . |
|
||||
* +-------+ +-----+
|
||||
* | arg 3 ----------------------->| str |
|
||||
* +-------+ | . |
|
||||
* | arg 2 ---PREVEP-----+ .
|
||||
* +-------+ |
|
||||
* . | | |
|
||||
* +-------+ | +-----+
|
||||
* | plev | PARLEV +-------->| str |
|
||||
* +-------+ | . |
|
||||
* | type | CALTYP .
|
||||
* +-------+
|
||||
* | prcf ---PREVFP--+
|
||||
* +-------+ |
|
||||
* | . | PREVSP |
|
||||
* . |
|
||||
* +-------+ |
|
||||
* | <----------+
|
||||
* +-------+
|
||||
*
|
||||
*/
|
||||
#define PARLEV (mstack[fp].sfra)
|
||||
#define CALTYP (mstack[fp-2].sfra)
|
||||
#define TRACESTATUS (mstack[fp-1].sfra)
|
||||
#define PREVEP (mstack[fp+3].sstr)
|
||||
#define PREVSP (fp-4)
|
||||
#define PREVFP (mstack[fp-3].sfra)
|
||||
427
usr.bin/m4/misc.c
Normal file
427
usr.bin/m4/misc.c
Normal file
@@ -0,0 +1,427 @@
|
||||
/* $OpenBSD: misc.c,v 1.41 2009/10/14 17:19:47 sthen Exp $ */
|
||||
/* $NetBSD: misc.c,v 1.20 2009/11/06 15:13:27 joerg 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.
|
||||
*/
|
||||
#if HAVE_NBTOOL_CONFIG_H
|
||||
#include "nbtool_config.h"
|
||||
#endif
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: misc.c,v 1.20 2009/11/06 15:13:27 joerg Exp $");
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <err.h>
|
||||
#include "mdef.h"
|
||||
#include "stdd.h"
|
||||
#include "extern.h"
|
||||
#include "pathnames.h"
|
||||
|
||||
|
||||
char *ep; /* first free char in strspace */
|
||||
static char *strspace; /* string space for evaluation */
|
||||
char *endest; /* end of string space */
|
||||
static size_t strsize = STRSPMAX;
|
||||
static size_t bufsize = BUFSIZE;
|
||||
|
||||
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 */
|
||||
|
||||
|
||||
/*
|
||||
* find the index of second str in the first str.
|
||||
*/
|
||||
ptrdiff_t
|
||||
indx(const char *s1, const char *s2)
|
||||
{
|
||||
char *t;
|
||||
|
||||
t = strstr(s1, s2);
|
||||
if (t == NULL)
|
||||
return (-1);
|
||||
else
|
||||
return (t - s1);
|
||||
}
|
||||
/*
|
||||
* pushback - push character back onto input
|
||||
*/
|
||||
void
|
||||
pushback(int c)
|
||||
{
|
||||
if (c == EOF)
|
||||
return;
|
||||
if (bp >= endpbb)
|
||||
enlarge_bufspace();
|
||||
*bp++ = c;
|
||||
}
|
||||
|
||||
/*
|
||||
* pbstr - push string back onto input
|
||||
* pushback is replicated to improve
|
||||
* performance.
|
||||
*/
|
||||
void
|
||||
pbstr(const char *s)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
n = strlen(s);
|
||||
while ((size_t)(endpbb - bp) <= n)
|
||||
enlarge_bufspace();
|
||||
while (n > 0)
|
||||
*bp++ = s[--n];
|
||||
}
|
||||
|
||||
/*
|
||||
* pbnum - convert number to string, push back on input.
|
||||
*/
|
||||
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 {
|
||||
pushback(digits[num % base]);
|
||||
printed++;
|
||||
}
|
||||
while ((num /= base) > 0);
|
||||
|
||||
if (n < 0)
|
||||
printed++;
|
||||
while (printed++ < d)
|
||||
pushback('0');
|
||||
|
||||
if (n < 0)
|
||||
pushback('-');
|
||||
}
|
||||
|
||||
/*
|
||||
* pbunsigned - convert unsigned long to string, push back on input.
|
||||
*/
|
||||
void
|
||||
pbunsigned(unsigned long n)
|
||||
{
|
||||
do {
|
||||
pushback(n % 10 + '0');
|
||||
}
|
||||
while ((n /= 10) > 0);
|
||||
}
|
||||
|
||||
void
|
||||
initspaces()
|
||||
{
|
||||
int i;
|
||||
|
||||
strspace = xalloc(strsize+1, NULL);
|
||||
ep = strspace;
|
||||
endest = strspace+strsize;
|
||||
buf = (unsigned char *)xalloc(bufsize, NULL);
|
||||
bufbase = buf;
|
||||
bp = buf;
|
||||
endpbb = buf + bufsize;
|
||||
for (i = 0; i < MAXINP; i++)
|
||||
bbase[i] = buf;
|
||||
}
|
||||
|
||||
void
|
||||
enlarge_strspace()
|
||||
{
|
||||
char *newstrspace;
|
||||
int i;
|
||||
|
||||
strsize *= 2;
|
||||
newstrspace = malloc(strsize + 1);
|
||||
if (!newstrspace)
|
||||
errx(1, "string space overflow");
|
||||
memcpy(newstrspace, strspace, strsize/2);
|
||||
for (i = 0; i <= sp; i++)
|
||||
if (sstack[i])
|
||||
mstack[i].sstr = (mstack[i].sstr - strspace)
|
||||
+ newstrspace;
|
||||
ep = (ep-strspace) + newstrspace;
|
||||
free(strspace);
|
||||
strspace = newstrspace;
|
||||
endest = strspace + strsize;
|
||||
}
|
||||
|
||||
void
|
||||
enlarge_bufspace()
|
||||
{
|
||||
unsigned char *newbuf;
|
||||
int i;
|
||||
|
||||
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;
|
||||
bufbase = (bufbase-buf)+newbuf;
|
||||
buf = newbuf;
|
||||
endpbb = buf+bufsize;
|
||||
}
|
||||
|
||||
/*
|
||||
* chrsave - put single char on string space
|
||||
*/
|
||||
void
|
||||
chrsave(int c)
|
||||
{
|
||||
if (ep >= endest)
|
||||
enlarge_strspace();
|
||||
*ep++ = c;
|
||||
}
|
||||
|
||||
/*
|
||||
* read in a diversion file, and dispose it.
|
||||
*/
|
||||
void
|
||||
getdiv(int n)
|
||||
{
|
||||
int c;
|
||||
|
||||
if (active == outfile[n])
|
||||
m4errx(1, "undivert: diversion still active.");
|
||||
rewind(outfile[n]);
|
||||
while ((c = getc(outfile[n])) != EOF)
|
||||
putc(c, active);
|
||||
(void) fclose(outfile[n]);
|
||||
outfile[n] = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
onintr(int signo)
|
||||
{
|
||||
#define intrmessage "m4: interrupted.\n"
|
||||
write(STDERR_FILENO, intrmessage, sizeof(intrmessage)-1);
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* killdiv - get rid of the diversion files
|
||||
*/
|
||||
void
|
||||
killdiv()
|
||||
{
|
||||
int n;
|
||||
|
||||
for (n = 0; n < maxout; n++)
|
||||
if (outfile[n] != NULL) {
|
||||
(void) fclose(outfile[n]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
m4errx(int exval, const char *fmt, ...)
|
||||
{
|
||||
fprintf(stderr, "%s: ", getprogname());
|
||||
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(exval);
|
||||
}
|
||||
|
||||
/*
|
||||
* resizedivs: allocate more diversion files */
|
||||
void
|
||||
resizedivs(int n)
|
||||
{
|
||||
int i;
|
||||
|
||||
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, const char *fmt, ...)
|
||||
{
|
||||
void *p = malloc(n);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
char *
|
||||
xstrdup(const char *s)
|
||||
{
|
||||
char *p = strdup(s);
|
||||
if (p == NULL)
|
||||
err(1, "strdup");
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [-gPs] [-Dname[=value]] [-d flags] "
|
||||
"[-I dirname] [-o filename]\n"
|
||||
"\t[-t macro] [-Uname] [file ...]\n", getprogname());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
obtain_char(struct input_file *f)
|
||||
{
|
||||
if (f->c == EOF)
|
||||
return EOF;
|
||||
|
||||
f->c = fgetc(f->file);
|
||||
if (f->c == '\n')
|
||||
f->lineno++;
|
||||
|
||||
return f->c;
|
||||
}
|
||||
|
||||
void
|
||||
set_input(struct input_file *f, FILE *real, const char *name)
|
||||
{
|
||||
f->file = real;
|
||||
f->lineno = 1;
|
||||
f->c = 0;
|
||||
f->name = xstrdup(name);
|
||||
emit_synchline();
|
||||
}
|
||||
|
||||
void
|
||||
do_emit_synchline()
|
||||
{
|
||||
fprintf(active, "#line %lu \"%s\"\n",
|
||||
infile[ilevel].lineno, infile[ilevel].name);
|
||||
infile[ilevel].synch_lineno = infile[ilevel].lineno;
|
||||
}
|
||||
|
||||
void
|
||||
release_input(struct input_file *f)
|
||||
{
|
||||
if (f->file != stdin)
|
||||
fclose(f->file);
|
||||
f->c = EOF;
|
||||
/*
|
||||
* XXX can't free filename, as there might still be
|
||||
* error information pointing to it.
|
||||
*/
|
||||
}
|
||||
|
||||
void
|
||||
doprintlineno(struct input_file *f)
|
||||
{
|
||||
pbunsigned(f->lineno);
|
||||
}
|
||||
|
||||
void
|
||||
doprintfilename(struct input_file *f)
|
||||
{
|
||||
pbstr(rquote);
|
||||
pbstr(f->name);
|
||||
pbstr(lquote);
|
||||
}
|
||||
|
||||
/*
|
||||
* buffer_mark/dump_buffer: allows one to save a mark in a buffer,
|
||||
* and later dump everything that was added since then to a file.
|
||||
*/
|
||||
size_t
|
||||
buffer_mark()
|
||||
{
|
||||
return bp - buf;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
dump_buffer(FILE *f, size_t m)
|
||||
{
|
||||
unsigned char *s;
|
||||
|
||||
for (s = bp; (size_t)(s - buf) > m;)
|
||||
fputc(*--s, f);
|
||||
}
|
||||
85
usr.bin/m4/parser.y
Normal file
85
usr.bin/m4/parser.y
Normal file
@@ -0,0 +1,85 @@
|
||||
%{
|
||||
/* $NetBSD: parser.y,v 1.2 2009/10/26 21:11:28 christos Exp $ */
|
||||
/* $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.
|
||||
*/
|
||||
#if HAVE_NBTOOL_CONFIG_H
|
||||
#include "nbtool_config.h"
|
||||
#endif
|
||||
__RCSID("$NetBSD: parser.y,v 1.2 2009/10/26 21:11:28 christos Exp $");
|
||||
#include <stdint.h>
|
||||
#define YYSTYPE int32_t
|
||||
extern int32_t end_result;
|
||||
extern int yylex(void);
|
||||
extern int yyerror(const char *);
|
||||
%}
|
||||
%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
|
||||
;
|
||||
%%
|
||||
|
||||
40
usr.bin/m4/pathnames.h
Normal file
40
usr.bin/m4/pathnames.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/* $NetBSD: pathnames.h,v 1.13 2009/10/31 23:25:04 joerg 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.
|
||||
*
|
||||
* @(#)pathnames.h 8.1 (Berkeley) 6/6/93
|
||||
*/
|
||||
|
||||
/*
|
||||
* Definitions of diversion files.
|
||||
*/
|
||||
#define _PATH_DIVNAME "/tmp/m4.0XXXXXXXXXX" /* unix diversion files */
|
||||
54
usr.bin/m4/stdd.h
Normal file
54
usr.bin/m4/stdd.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/* $NetBSD: stdd.h,v 1.4 2003/08/07 11:14:34 agc Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 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.
|
||||
*
|
||||
* @(#)stdd.h 8.1 (Berkeley) 6/6/93
|
||||
*/
|
||||
|
||||
/*
|
||||
* standard defines
|
||||
*/
|
||||
|
||||
#define max(a,b) ((a) > (b)? (a): (b))
|
||||
#define min(a,b) ((a) < (b)? (a): (b))
|
||||
|
||||
#define iswhite(c) ((c) == ' ' || (c) == '\t')
|
||||
|
||||
/*
|
||||
* STREQ is an optimised strcmp(a,b)==0
|
||||
* STREQN is an optimised strncmp(a,b,n)==0; assumes n > 0
|
||||
*/
|
||||
#define STREQ(a, b) ((a)[0] == (b)[0] && strcmp(a, b) == 0)
|
||||
#define STREQN(a, b, n) ((a)[0] == (b)[0] && strncmp(a, b, n) == 0)
|
||||
|
||||
#define YES 1
|
||||
#define NO 0
|
||||
107
usr.bin/m4/tokenizer.l
Normal file
107
usr.bin/m4/tokenizer.l
Normal file
@@ -0,0 +1,107 @@
|
||||
%{
|
||||
/* $NetBSD: tokenizer.l,v 1.4 2009/10/29 14:49:03 christos Exp $ */
|
||||
/* $OpenBSD: tokenizer.l,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.
|
||||
*/
|
||||
#if HAVE_NBTOOL_CONFIG_H
|
||||
#include "nbtool_config.h"
|
||||
#endif
|
||||
#include "parser.h"
|
||||
__RCSID("$NetBSD: tokenizer.l,v 1.4 2009/10/29 14:49:03 christos Exp $");
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
|
||||
extern int mimic_gnu;
|
||||
extern int32_t yylval;
|
||||
extern int yylex(void);
|
||||
extern int yywrap(void);
|
||||
|
||||
int32_t number(void);
|
||||
int32_t parse_radix(void);
|
||||
|
||||
%}
|
||||
|
||||
%option nounput
|
||||
|
||||
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()
|
||||
{
|
||||
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()
|
||||
{
|
||||
long base;
|
||||
char *next;
|
||||
long l;
|
||||
|
||||
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')
|
||||
l = base * l + *next - '0';
|
||||
else if (*next >= 'a' && *next <= 'z')
|
||||
l = base * l + *next - 'a' + 10;
|
||||
else if (*next >= 'A' && *next <= 'Z')
|
||||
l = base * l + *next - 'A' + 10;
|
||||
next++;
|
||||
}
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
203
usr.bin/m4/trace.c
Normal file
203
usr.bin/m4/trace.c
Normal file
@@ -0,0 +1,203 @@
|
||||
/* $NetBSD: trace.c,v 1.6 2009/10/26 21:11:28 christos Exp $ */
|
||||
/* $OpenBSD: trace.c,v 1.15 2006/03/24 08:03:44 espie Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2001 Marc Espie.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT 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 OPENBSD
|
||||
* PROJECT 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.
|
||||
*/
|
||||
#if HAVE_NBTOOL_CONFIG_H
|
||||
#include "nbtool_config.h"
|
||||
#endif
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: trace.c,v 1.6 2009/10/26 21:11:28 christos Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <err.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "mdef.h"
|
||||
#include "stdd.h"
|
||||
#include "extern.h"
|
||||
|
||||
FILE *traceout;
|
||||
|
||||
#define TRACE_ARGS 1
|
||||
#define TRACE_EXPANSION 2
|
||||
#define TRACE_QUOTE 4
|
||||
#define TRACE_FILENAME 8
|
||||
#define TRACE_LINENO 16
|
||||
#define TRACE_CONT 32
|
||||
#define TRACE_ID 64
|
||||
#define TRACE_NEWFILE 128 /* not implemented yet */
|
||||
#define TRACE_INPUT 256 /* not implemented yet */
|
||||
|
||||
static unsigned int letter_to_flag(int);
|
||||
static void print_header(struct input_file *);
|
||||
static int frame_level(void);
|
||||
|
||||
|
||||
unsigned int trace_flags = TRACE_QUOTE | TRACE_EXPANSION;
|
||||
|
||||
void
|
||||
trace_file(const char *name)
|
||||
{
|
||||
|
||||
if (traceout && traceout != stderr)
|
||||
fclose(traceout);
|
||||
traceout = fopen(name, "w");
|
||||
if (!traceout)
|
||||
err(1, "can't open %s", name);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
letter_to_flag(int c)
|
||||
{
|
||||
switch(c) {
|
||||
case 'a':
|
||||
return TRACE_ARGS;
|
||||
case 'e':
|
||||
return TRACE_EXPANSION;
|
||||
case 'q':
|
||||
return TRACE_QUOTE;
|
||||
case 'c':
|
||||
return TRACE_CONT;
|
||||
case 'x':
|
||||
return TRACE_ID;
|
||||
case 'f':
|
||||
return TRACE_FILENAME;
|
||||
case 'l':
|
||||
return TRACE_LINENO;
|
||||
case 'p':
|
||||
return TRACE_NEWFILE;
|
||||
case 'i':
|
||||
return TRACE_INPUT;
|
||||
case 't':
|
||||
return TRACE_ALL;
|
||||
case 'V':
|
||||
return ~0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
set_trace_flags(const char *s)
|
||||
{
|
||||
char mode = 0;
|
||||
unsigned int f = 0;
|
||||
|
||||
if (*s == '+' || *s == '-')
|
||||
mode = *s++;
|
||||
while (*s)
|
||||
f |= letter_to_flag(*s++);
|
||||
switch(mode) {
|
||||
case 0:
|
||||
trace_flags = f;
|
||||
break;
|
||||
case '+':
|
||||
trace_flags |= f;
|
||||
break;
|
||||
case '-':
|
||||
trace_flags &= ~f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
frame_level()
|
||||
{
|
||||
int level;
|
||||
int framep;
|
||||
|
||||
for (framep = fp, level = 0; framep != 0;
|
||||
level++,framep = mstack[framep-3].sfra)
|
||||
;
|
||||
return level;
|
||||
}
|
||||
|
||||
static void
|
||||
print_header(struct input_file *inp)
|
||||
{
|
||||
fprintf(traceout, "m4trace:");
|
||||
if (trace_flags & TRACE_FILENAME)
|
||||
fprintf(traceout, "%s:", inp->name);
|
||||
if (trace_flags & TRACE_LINENO)
|
||||
fprintf(traceout, "%lu:", inp->lineno);
|
||||
fprintf(traceout, " -%d- ", frame_level());
|
||||
if (trace_flags & TRACE_ID)
|
||||
fprintf(traceout, "id %lu: ", expansion_id);
|
||||
}
|
||||
|
||||
size_t
|
||||
trace(const char *argv[], int argc, struct input_file *inp)
|
||||
{
|
||||
if (!traceout)
|
||||
traceout = stderr;
|
||||
print_header(inp);
|
||||
if (trace_flags & TRACE_CONT) {
|
||||
fprintf(traceout, "%s ...\n", argv[1]);
|
||||
print_header(inp);
|
||||
}
|
||||
fprintf(traceout, "%s", argv[1]);
|
||||
if ((trace_flags & TRACE_ARGS) && argc > 2) {
|
||||
char delim[3];
|
||||
int i;
|
||||
|
||||
delim[0] = LPAREN;
|
||||
delim[1] = EOS;
|
||||
for (i = 2; i < argc; i++) {
|
||||
fprintf(traceout, "%s%s%s%s", delim,
|
||||
(trace_flags & TRACE_QUOTE) ? lquote : "",
|
||||
argv[i],
|
||||
(trace_flags & TRACE_QUOTE) ? rquote : "");
|
||||
delim[0] = COMMA;
|
||||
delim[1] = ' ';
|
||||
delim[2] = EOS;
|
||||
}
|
||||
fprintf(traceout, "%c", RPAREN);
|
||||
}
|
||||
if (trace_flags & TRACE_CONT) {
|
||||
fprintf(traceout, " -> ???\n");
|
||||
print_header(inp);
|
||||
fprintf(traceout, argc > 2 ? "%s(...)" : "%s", argv[1]);
|
||||
}
|
||||
if (trace_flags & TRACE_EXPANSION)
|
||||
return buffer_mark();
|
||||
else {
|
||||
fprintf(traceout, "\n");
|
||||
return SIZE_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
finish_trace(size_t mark)
|
||||
{
|
||||
fprintf(traceout, " -> ");
|
||||
if (trace_flags & TRACE_QUOTE)
|
||||
fprintf(traceout, "%s", lquote);
|
||||
dump_buffer(traceout, mark);
|
||||
if (trace_flags & TRACE_QUOTE)
|
||||
fprintf(traceout, "%s", rquote);
|
||||
fprintf(traceout, "\n");
|
||||
}
|
||||
Reference in New Issue
Block a user