Replace m4 with NetBSD version
-Create usr.bin hierarchy -Update minix-port.patch to include m4
This commit is contained in:
parent
ef60bcc0a6
commit
2e8d1eda1b
63 changed files with 6081 additions and 3073 deletions
6
Makefile
6
Makefile
|
@ -54,10 +54,12 @@ elf-libraries: includes
|
|||
|
||||
commands: includes libraries
|
||||
$(MAKE) -C commands all
|
||||
$(MAKE) -C usr.bin all
|
||||
|
||||
depend:
|
||||
$(MAKE) CC=cc -C boot depend
|
||||
$(MAKE) -C commands depend
|
||||
$(MAKE) -C usr.bin depend
|
||||
$(MAKE) -C kernel depend
|
||||
$(MAKE) -C servers depend
|
||||
$(MAKE) -C drivers depend
|
||||
|
@ -71,18 +73,21 @@ etcforce:
|
|||
all:
|
||||
$(MAKE) CC=cc -C boot all
|
||||
$(MAKE) -C commands all
|
||||
$(MAKE) -C usr.bin all
|
||||
$(MAKE) -C tools all
|
||||
|
||||
install:
|
||||
$(MAKE) CC=cc -C boot install
|
||||
$(MAKE) -C man install makedb
|
||||
$(MAKE) -C commands install
|
||||
$(MAKE) -C usr.bin install
|
||||
$(MAKE) -C share install
|
||||
$(MAKE) -C tools install
|
||||
|
||||
clean:
|
||||
$(MAKE) -C boot clean
|
||||
$(MAKE) -C commands clean
|
||||
$(MAKE) -C usr.bin clean
|
||||
$(MAKE) -C tools clean
|
||||
$(MAKE) -C lib clean_all
|
||||
$(MAKE) -C test clean
|
||||
|
@ -90,4 +95,5 @@ clean:
|
|||
cleandepend:
|
||||
$(MAKE) -C boot cleandepend
|
||||
$(MAKE) -C commands cleandepend
|
||||
$(MAKE) -C usr.bin cleandepend
|
||||
$(MAKE) -C tools cleandepend
|
||||
|
|
|
@ -16,7 +16,7 @@ SUBDIR= aal add_route adduser advent arp ash at autil awk \
|
|||
hostaddr id ifconfig ifdef indent install \
|
||||
intr ipcrm ipcs irdpd isoread join kill last leave \
|
||||
less lex life loadkeys loadramdisk logger login look lp \
|
||||
lpd ls lspci M m4 mail make MAKEDEV man \
|
||||
lpd ls lspci M mail make MAKEDEV man \
|
||||
mdb mdocml mesg mined mkdep mkdir mkfifo mkfs.mfs mknod \
|
||||
mkproto modem mount mt netconf newroot nice acknm nohup \
|
||||
nonamed od packman passwd paste patch pax \
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
define(ack, `ifelse($1,0,incr($2),$2,0,`ack(DECR($1),1)',
|
||||
`ack(DECR($1), ack($1,DECR($2)))')')
|
|
@ -1,7 +0,0 @@
|
|||
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))')')
|
|
@ -1,17 +0,0 @@
|
|||
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
|
|
@ -1,462 +0,0 @@
|
|||
#
|
||||
# test file for mp (not comprehensive)
|
||||
#
|
||||
# v7 m4 does not have `decr'.
|
||||
#
|
||||
|
||||
#
|
||||
# include string macros
|
||||
#
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# create some fortrash strings for an even uglier language
|
||||
#
|
||||
integer TEXT(5)
|
||||
data TEXT(1)/LETt/
|
||||
data TEXT(2)/LETe/
|
||||
data TEXT(3)/LETx/
|
||||
data TEXT(4)/LETt/
|
||||
|
||||
data TEXT(5)/EOS/
|
||||
|
||||
integer DATA(5)
|
||||
data DATA(1)/LETd/
|
||||
data DATA(2)/LETa/
|
||||
data DATA(3)/LETt/
|
||||
data DATA(4)/LETa/
|
||||
|
||||
data DATA(5)/EOS/
|
||||
|
||||
integer BEGIN(6)
|
||||
data BEGIN(1)/LETb/
|
||||
data BEGIN(2)/LETe/
|
||||
data BEGIN(3)/LETg/
|
||||
data BEGIN(4)/LETi/
|
||||
data BEGIN(5)/LETn/
|
||||
|
||||
data BEGIN(6)/EOS/
|
||||
|
||||
integer END(4)
|
||||
data END(1)/LETe/
|
||||
data END(2)/LETn/
|
||||
data END(3)/LETd/
|
||||
|
||||
data END(4)/EOS/
|
||||
|
||||
integer IF(3)
|
||||
data IF(1)/LETi/
|
||||
data IF(2)/LETf/
|
||||
|
||||
data IF(3)/EOS/
|
||||
|
||||
integer THEN(5)
|
||||
data THEN(1)/LETt/
|
||||
data THEN(2)/LETh/
|
||||
data THEN(3)/LETe/
|
||||
data THEN(4)/LETn/
|
||||
|
||||
data THEN(5)/EOS/
|
||||
|
||||
integer ELSE(5)
|
||||
data ELSE(1)/LETe/
|
||||
data ELSE(2)/LETl/
|
||||
data ELSE(3)/LETs/
|
||||
data ELSE(4)/LETe/
|
||||
|
||||
data ELSE(5)/EOS/
|
||||
|
||||
integer CASE(5)
|
||||
data CASE(1)/LETc/
|
||||
data CASE(2)/LETa/
|
||||
data CASE(3)/LETs/
|
||||
data CASE(4)/LETe/
|
||||
|
||||
data CASE(5)/EOS/
|
||||
|
||||
integer REPEAT(7)
|
||||
data REPEAT(1)/LETr/
|
||||
data REPEAT(2)/LETe/
|
||||
data REPEAT(3)/LETp/
|
||||
data REPEAT(4)/LETe/
|
||||
data REPEAT(5)/LETa/
|
||||
data REPEAT(6)/LETt/
|
||||
|
||||
data REPEAT(7)/EOS/
|
||||
|
||||
integer WHILE(6)
|
||||
data WHILE(1)/LETw/
|
||||
data WHILE(2)/LETh/
|
||||
data WHILE(3)/LETi/
|
||||
data WHILE(4)/LETl/
|
||||
data WHILE(5)/LETe/
|
||||
|
||||
data WHILE(6)/EOS/
|
||||
|
||||
integer DEFAULT(8)
|
||||
data DEFAULT(1)/LETd/
|
||||
data DEFAULT(2)/LETe/
|
||||
data DEFAULT(3)/LETf/
|
||||
data DEFAULT(4)/LETa/
|
||||
data DEFAULT(5)/LETu/
|
||||
data DEFAULT(6)/LETl/
|
||||
data DEFAULT(7)/LETt/
|
||||
|
||||
data DEFAULT(8)/EOS/
|
||||
|
||||
integer UNTIL(6)
|
||||
data UNTIL(1)/LETu/
|
||||
data UNTIL(2)/LETn/
|
||||
data UNTIL(3)/LETt/
|
||||
data UNTIL(4)/LETi/
|
||||
data UNTIL(5)/LETl/
|
||||
|
||||
data UNTIL(6)/EOS/
|
||||
|
||||
integer FUNCTION(9)
|
||||
data FUNCTION(1)/LETf/
|
||||
data FUNCTION(2)/LETu/
|
||||
data FUNCTION(3)/LETn/
|
||||
data FUNCTION(4)/LETc/
|
||||
data FUNCTION(5)/LETt/
|
||||
data FUNCTION(6)/LETi/
|
||||
data FUNCTION(7)/LETo/
|
||||
data FUNCTION(8)/LETn/
|
||||
|
||||
data FUNCTION(9)/EOS/
|
||||
|
||||
integer PROCEDURE(10)
|
||||
data PROCEDURE(1)/LETp/
|
||||
data PROCEDURE(2)/LETr/
|
||||
data PROCEDURE(3)/LETo/
|
||||
data PROCEDURE(4)/LETc/
|
||||
data PROCEDURE(5)/LETe/
|
||||
data PROCEDURE(6)/LETd/
|
||||
data PROCEDURE(7)/LETu/
|
||||
data PROCEDURE(8)/LETr/
|
||||
data PROCEDURE(9)/LETe/
|
||||
|
||||
data PROCEDURE(10)/EOS/
|
||||
|
||||
integer EXTERNAL(9)
|
||||
data EXTERNAL(1)/LETe/
|
||||
data EXTERNAL(2)/LETx/
|
||||
data EXTERNAL(3)/LETt/
|
||||
data EXTERNAL(4)/LETe/
|
||||
data EXTERNAL(5)/LETr/
|
||||
data EXTERNAL(6)/LETn/
|
||||
data EXTERNAL(7)/LETa/
|
||||
data EXTERNAL(8)/LETl/
|
||||
|
||||
data EXTERNAL(9)/EOS/
|
||||
|
||||
integer FORWARD(8)
|
||||
data FORWARD(1)/LETf/
|
||||
data FORWARD(2)/LETo/
|
||||
data FORWARD(3)/LETr/
|
||||
data FORWARD(4)/LETw/
|
||||
data FORWARD(5)/LETa/
|
||||
data FORWARD(6)/LETr/
|
||||
data FORWARD(7)/LETd/
|
||||
|
||||
data FORWARD(8)/EOS/
|
||||
|
||||
integer TYPE(5)
|
||||
data TYPE(1)/LETt/
|
||||
data TYPE(2)/LETy/
|
||||
data TYPE(3)/LETp/
|
||||
data TYPE(4)/LETe/
|
||||
|
||||
data TYPE(5)/EOS/
|
||||
|
||||
integer VAR(4)
|
||||
data VAR(1)/LETv/
|
||||
data VAR(2)/LETa/
|
||||
data VAR(3)/LETr/
|
||||
|
||||
data VAR(4)/EOS/
|
||||
|
||||
integer CONST(6)
|
||||
data CONST(1)/LETc/
|
||||
data CONST(2)/LETo/
|
||||
data CONST(3)/LETn/
|
||||
data CONST(4)/LETs/
|
||||
data CONST(5)/LETt/
|
||||
|
||||
data CONST(6)/EOS/
|
||||
|
||||
integer PROGRAM(8)
|
||||
data PROGRAM(1)/LETp/
|
||||
data PROGRAM(2)/LETr/
|
||||
data PROGRAM(3)/LETo/
|
||||
data PROGRAM(4)/LETg/
|
||||
data PROGRAM(5)/LETr/
|
||||
data PROGRAM(6)/LETa/
|
||||
data PROGRAM(7)/LETm/
|
||||
|
||||
data PROGRAM(8)/EOS/
|
||||
|
||||
integer INPUT(6)
|
||||
data INPUT(1)/LETi/
|
||||
data INPUT(2)/LETn/
|
||||
data INPUT(3)/LETp/
|
||||
data INPUT(4)/LETu/
|
||||
data INPUT(5)/LETt/
|
||||
|
||||
data INPUT(6)/EOS/
|
||||
|
||||
integer OUTPUT(7)
|
||||
data OUTPUT(1)/LETo/
|
||||
data OUTPUT(2)/LETu/
|
||||
data OUTPUT(3)/LETt/
|
||||
data OUTPUT(4)/LETp/
|
||||
data OUTPUT(5)/LETu/
|
||||
data OUTPUT(6)/LETt/
|
||||
|
||||
data OUTPUT(7)/EOS/
|
||||
|
||||
#
|
||||
|
||||
|
||||
defined
|
||||
#
|
||||
# v7 m4 does this wrong. The right output is
|
||||
# this is A vEry lon sEntEnCE
|
||||
# see m4 documentation for translit.
|
||||
#
|
||||
this is A vEry lon sEntEnCE
|
||||
#
|
||||
# include towers-of-hanoi
|
||||
#
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# some reasonable set of disks
|
||||
#
|
||||
move disk from A to C
|
||||
move disk from A to B
|
||||
move disk from C to B
|
||||
move disk from A to C
|
||||
move disk from B to A
|
||||
move disk from B to C
|
||||
move disk from A to C
|
||||
move disk from A to B
|
||||
move disk from C to B
|
||||
move disk from C to A
|
||||
move disk from B to A
|
||||
move disk from C to B
|
||||
move disk from A to C
|
||||
move disk from A to B
|
||||
move disk from C to B
|
||||
move disk from A to C
|
||||
move disk from B to A
|
||||
move disk from B to C
|
||||
move disk from A to C
|
||||
move disk from B to A
|
||||
move disk from C to B
|
||||
move disk from C to A
|
||||
move disk from B to A
|
||||
move disk from B to C
|
||||
move disk from A to C
|
||||
move disk from A to B
|
||||
move disk from C to B
|
||||
move disk from A to C
|
||||
move disk from B to A
|
||||
move disk from B to C
|
||||
move disk from A to C
|
||||
move disk from A to B
|
||||
move disk from C to B
|
||||
move disk from C to A
|
||||
move disk from B to A
|
||||
move disk from C to B
|
||||
move disk from A to C
|
||||
move disk from A to B
|
||||
move disk from C to B
|
||||
move disk from C to A
|
||||
move disk from B to A
|
||||
move disk from B to C
|
||||
move disk from A to C
|
||||
move disk from B to A
|
||||
move disk from C to B
|
||||
move disk from C to A
|
||||
move disk from B to A
|
||||
move disk from C to B
|
||||
move disk from A to C
|
||||
move disk from A to B
|
||||
move disk from C to B
|
||||
move disk from A to C
|
||||
move disk from B to A
|
||||
move disk from B to C
|
||||
move disk from A to C
|
||||
move disk from A to B
|
||||
move disk from C to B
|
||||
move disk from C to A
|
||||
move disk from B to A
|
||||
move disk from C to B
|
||||
move disk from A to C
|
||||
move disk from A to B
|
||||
move disk from C to B
|
||||
|
||||
#
|
||||
# include ackermann's function
|
||||
#
|
||||
|
||||
|
||||
#
|
||||
# something like (3,3) will blow away un*x m4.
|
||||
#
|
||||
9
|
||||
#
|
||||
# include a square_root function for fixed nums
|
||||
#
|
||||
|
||||
|
||||
|
||||
#
|
||||
# some square roots.
|
||||
#
|
||||
3
|
||||
10
|
||||
negative-square-root
|
||||
146
|
||||
#
|
||||
# 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..
|
||||
#
|
||||
|
||||
diversion #1
|
||||
|
||||
diversion #2
|
||||
|
||||
diversion #3
|
||||
|
||||
diversion #4
|
|
@ -1,14 +0,0 @@
|
|||
# Makefile for M4
|
||||
|
||||
# -DEXTENDED #if you like to get paste & spaste macros.
|
||||
# -DVOID #if your C compiler does NOT support void.
|
||||
# -DGETOPT #if you STILL do not have getopt in your library.
|
||||
# -DDUFFCP #if you do not have fast memcpy in your library.
|
||||
#
|
||||
|
||||
PROG= m4
|
||||
SRCS= main.c eval.c serv.c look.c misc.c expr.c
|
||||
CPPFLAGS+= -DEXTENDED
|
||||
MAN=
|
||||
|
||||
.include <bsd.prog.mk>
|
|
@ -1,32 +0,0 @@
|
|||
This code *is* PD. You (public) have all the rights to the code. [But
|
||||
this also means you (singular) do not have any *extra* rights to the code,
|
||||
hence it is impossible for you to restrict the use and distribution of
|
||||
this code (original) in any way.]
|
||||
|
||||
Dedication:
|
||||
|
||||
This posting is a dedication to an old 750 that started out running 4.1BSD
|
||||
and had 1.5 meg, 1 dz11, and 2 Rk07 drives. It was named yetti [sic] by
|
||||
accident, and was managed by the author until its retirement two years
|
||||
ago. [the name yetti now identifies a different machine]
|
||||
|
||||
If you have any important fixes and/or speed improvements, I am much
|
||||
interested. I am also interested in hearing about any unique applica-
|
||||
tions of M4. I am NOT interested in gratuitous hacks or "neat"
|
||||
kitchen-sink features.
|
||||
|
||||
Author:
|
||||
Usenet: uunet!utai!yunexus!oz || oz@nexus.yorku.ca
|
||||
Bitnet: oz@yulibra.BITNET
|
||||
Phonet: [416] 736-5257 x 3976
|
||||
|
||||
|
||||
enjoy. oz
|
||||
|
||||
Testing:
|
||||
|
||||
This directory contains a test file called test.m4. To use it, type
|
||||
|
||||
m4 <Test.m4 >out
|
||||
|
||||
The output file, out, should be identical to M4.out
|
|
@ -1,7 +0,0 @@
|
|||
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))')')
|
|
@ -1,8 +0,0 @@
|
|||
|
||||
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))')')
|
|
@ -1,331 +0,0 @@
|
|||
/*
|
||||
* eval.c
|
||||
* Facility: m4 macro processor
|
||||
* by: oz
|
||||
*/
|
||||
|
||||
#include "mdef.h"
|
||||
#include "extr.h"
|
||||
|
||||
/*
|
||||
* eval - evaluate built-in macros.
|
||||
* argc - number of elements in argv.
|
||||
* argv - element vector :
|
||||
* argv[0] = definition of a user
|
||||
* macro or nil if built-in.
|
||||
* argv[1] = name of the macro or
|
||||
* built-in.
|
||||
* argv[2] = parameters to user-defined
|
||||
* . macro or built-in.
|
||||
* .
|
||||
*
|
||||
* Note that the minimum value for argc is 3. A call in the form
|
||||
* of macro-or-builtin() will result in:
|
||||
* argv[0] = nullstr
|
||||
* argv[1] = macro-or-builtin
|
||||
* argv[2] = nullstr
|
||||
*
|
||||
*/
|
||||
|
||||
void eval (argv, argc, td)
|
||||
register char *argv[];
|
||||
register int argc;
|
||||
register int td;
|
||||
{
|
||||
register int c, n;
|
||||
static int sysval;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("argc = %d\n", argc);
|
||||
for (n = 0; n < argc; n++)
|
||||
printf("argv[%d] = %s\n", n, argv[n]);
|
||||
#endif
|
||||
/*
|
||||
* if argc == 3 and argv[2] is null,
|
||||
* then we have macro-or-builtin() type call.
|
||||
* We adjust argc to avoid further checking..
|
||||
*
|
||||
*/
|
||||
if (argc == 3 && !*(argv[2]))
|
||||
argc--;
|
||||
|
||||
switch (td & ~STATIC) {
|
||||
|
||||
case DEFITYPE:
|
||||
if (argc > 2)
|
||||
dodefine(argv[2], (argc > 3) ? argv[3] : null);
|
||||
break;
|
||||
|
||||
case PUSDTYPE:
|
||||
if (argc > 2)
|
||||
dopushdef(argv[2], (argc > 3) ? argv[3] : null);
|
||||
break;
|
||||
|
||||
case DUMPTYPE:
|
||||
dodump(argv, argc);
|
||||
break;
|
||||
|
||||
case EXPRTYPE:
|
||||
/*
|
||||
* doexpr - evaluate arithmetic expression
|
||||
*
|
||||
*/
|
||||
if (argc > 2)
|
||||
pbnum(expr(argv[2]));
|
||||
break;
|
||||
|
||||
case IFELTYPE:
|
||||
if (argc > 4)
|
||||
doifelse(argv, argc);
|
||||
break;
|
||||
|
||||
case IFDFTYPE:
|
||||
/*
|
||||
* doifdef - select one of two alternatives based
|
||||
* on the existence of another definition
|
||||
*/
|
||||
if (argc > 3) {
|
||||
if (lookup(argv[2]) != nil)
|
||||
pbstr(argv[3]);
|
||||
else if (argc > 4)
|
||||
pbstr(argv[4]);
|
||||
}
|
||||
break;
|
||||
|
||||
case LENGTYPE:
|
||||
/*
|
||||
* dolen - find the length of the argument
|
||||
*
|
||||
*/
|
||||
if (argc > 2)
|
||||
pbnum((argc > 2) ? strlen(argv[2]) : 0);
|
||||
break;
|
||||
|
||||
case INCRTYPE:
|
||||
/*
|
||||
* doincr - increment the value of the argument
|
||||
*
|
||||
*/
|
||||
if (argc > 2)
|
||||
pbnum(atoi(argv[2]) + 1);
|
||||
break;
|
||||
|
||||
case DECRTYPE:
|
||||
/*
|
||||
* dodecr - decrement the value of the argument
|
||||
*
|
||||
*/
|
||||
if (argc > 2)
|
||||
pbnum(atoi(argv[2]) - 1);
|
||||
break;
|
||||
|
||||
#if unix || vms
|
||||
|
||||
case SYSCTYPE:
|
||||
/*
|
||||
* dosys - execute system command
|
||||
*
|
||||
*/
|
||||
if (argc > 2)
|
||||
sysval = system(argv[2]);
|
||||
break;
|
||||
|
||||
case SYSVTYPE:
|
||||
/*
|
||||
* dosysval - return value of the last system call.
|
||||
*
|
||||
*/
|
||||
pbnum(sysval);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case INCLTYPE:
|
||||
if (argc > 2)
|
||||
if (!doincl(argv[2])) {
|
||||
fprintf(stderr,"m4: %s: ",argv[2]);
|
||||
error("cannot open for read.");
|
||||
}
|
||||
break;
|
||||
|
||||
case SINCTYPE:
|
||||
if (argc > 2)
|
||||
(void) doincl(argv[2]);
|
||||
break;
|
||||
#ifdef EXTENDED
|
||||
case PASTTYPE:
|
||||
if (argc > 2)
|
||||
if (!dopaste(argv[2])) {
|
||||
fprintf(stderr,"m4: %s: ",argv[2]);
|
||||
error("cannot open for read.");
|
||||
}
|
||||
break;
|
||||
|
||||
case SPASTYPE:
|
||||
if (argc > 2)
|
||||
(void) dopaste(argv[2]);
|
||||
break;
|
||||
#endif
|
||||
case CHNQTYPE:
|
||||
dochq(argv, argc);
|
||||
break;
|
||||
|
||||
case CHNCTYPE:
|
||||
dochc(argv, argc);
|
||||
break;
|
||||
|
||||
case SUBSTYPE:
|
||||
/*
|
||||
* dosub - select substring
|
||||
*
|
||||
*/
|
||||
if (argc > 3)
|
||||
dosub(argv,argc);
|
||||
break;
|
||||
|
||||
case SHIFTYPE:
|
||||
/*
|
||||
* doshift - push back all arguments except the
|
||||
* first one (i.e. skip argv[2])
|
||||
*/
|
||||
if (argc > 3) {
|
||||
for (n = argc-1; n > 3; n--) {
|
||||
putback(rquote);
|
||||
pbstr(argv[n]);
|
||||
putback(lquote);
|
||||
putback(',');
|
||||
}
|
||||
putback(rquote);
|
||||
pbstr(argv[3]);
|
||||
putback(lquote);
|
||||
}
|
||||
break;
|
||||
|
||||
case DIVRTYPE:
|
||||
if (argc > 2 && (n = atoi(argv[2])) != 0)
|
||||
dodiv(n);
|
||||
else {
|
||||
active = stdout;
|
||||
oindex = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case UNDVTYPE:
|
||||
doundiv(argv, argc);
|
||||
break;
|
||||
|
||||
case DIVNTYPE:
|
||||
/*
|
||||
* dodivnum - return the number of current
|
||||
* output diversion
|
||||
*
|
||||
*/
|
||||
pbnum(oindex);
|
||||
break;
|
||||
|
||||
case UNDFTYPE:
|
||||
/*
|
||||
* doundefine - undefine a previously defined
|
||||
* macro(s) or m4 keyword(s).
|
||||
*/
|
||||
if (argc > 2)
|
||||
for (n = 2; n < argc; n++)
|
||||
remhash(argv[n], ALL);
|
||||
break;
|
||||
|
||||
case POPDTYPE:
|
||||
/*
|
||||
* dopopdef - remove the topmost definitions of
|
||||
* macro(s) or m4 keyword(s).
|
||||
*/
|
||||
if (argc > 2)
|
||||
for (n = 2; n < argc; n++)
|
||||
remhash(argv[n], TOP);
|
||||
break;
|
||||
|
||||
case MKTMTYPE:
|
||||
/*
|
||||
* dotemp - create a temporary file
|
||||
*
|
||||
*/
|
||||
if (argc > 2)
|
||||
pbstr(mktemp(argv[2]));
|
||||
break;
|
||||
|
||||
case TRNLTYPE:
|
||||
/*
|
||||
* dotranslit - replace all characters in the
|
||||
* source string that appears in
|
||||
* the "from" string with the corresponding
|
||||
* characters in the "to" string.
|
||||
*
|
||||
*/
|
||||
if (argc > 3) {
|
||||
char temp[MAXTOK];
|
||||
if (argc > 4)
|
||||
map(temp, argv[2], argv[3], argv[4]);
|
||||
else
|
||||
map(temp, argv[2], argv[3], null);
|
||||
pbstr(temp);
|
||||
}
|
||||
else
|
||||
if (argc > 2)
|
||||
pbstr(argv[2]);
|
||||
break;
|
||||
|
||||
case INDXTYPE:
|
||||
/*
|
||||
* doindex - find the index of the second argument
|
||||
* string in the first argument string.
|
||||
* -1 if not present.
|
||||
*/
|
||||
pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
|
||||
break;
|
||||
|
||||
case ERRPTYPE:
|
||||
/*
|
||||
* doerrp - print the arguments to stderr file
|
||||
*
|
||||
*/
|
||||
if (argc > 2) {
|
||||
for (n = 2; n < argc; n++)
|
||||
fprintf(stderr,"%s ", argv[n]);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case DNLNTYPE:
|
||||
/*
|
||||
* dodnl - eat-up-to and including newline
|
||||
*
|
||||
*/
|
||||
while ((c = gpbc()) != '\n' && c != EOF)
|
||||
;
|
||||
break;
|
||||
|
||||
case M4WRTYPE:
|
||||
/*
|
||||
* dom4wrap - set up for wrap-up/wind-down activity
|
||||
*
|
||||
*/
|
||||
m4wraps = (argc > 2) ? strsave(argv[2]) : null;
|
||||
break;
|
||||
|
||||
case EXITTYPE:
|
||||
/*
|
||||
* doexit - immediate exit from m4.
|
||||
*
|
||||
*/
|
||||
exit((argc > 2) ? atoi(argv[2]) : 0);
|
||||
break;
|
||||
|
||||
case DEFNTYPE:
|
||||
if (argc > 2)
|
||||
for (n = 2; n < argc; n++)
|
||||
dodefn(argv[n]);
|
||||
break;
|
||||
|
||||
default:
|
||||
error("m4: major botch in eval.");
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -1,587 +0,0 @@
|
|||
/*
|
||||
* expression evaluator: performs a standard recursive
|
||||
* descent parse to evaluate any expression permissible
|
||||
* within the following grammar:
|
||||
*
|
||||
* expr : query EOS
|
||||
* query : lor
|
||||
* | lor "?" query ":" query
|
||||
* lor : land { "||" land }
|
||||
* land : bor { "&&" bor }
|
||||
* bor : bxor { "|" bxor }
|
||||
* bxor : band { "^" band }
|
||||
* band : eql { "&" eql }
|
||||
* eql : relat { eqrel relat }
|
||||
* relat : shift { rel shift }
|
||||
* shift : primary { shop primary }
|
||||
* primary : term { addop term }
|
||||
* term : unary { mulop unary }
|
||||
* unary : factor
|
||||
* | unop unary
|
||||
* factor : constant
|
||||
* | "(" query ")"
|
||||
* constant: num
|
||||
* | "'" CHAR "'"
|
||||
* num : decnum
|
||||
* | "0" octnum
|
||||
* | "0x" hexnum
|
||||
* octnum : OCTDIGIT
|
||||
* | OCTDIGIT octnum
|
||||
* decnum : DECDIGIT
|
||||
* | DECDIGIT decnum
|
||||
* hexnum : HEXDIGIT
|
||||
* | HEXDIGIT hexnum
|
||||
* shop : "<<"
|
||||
* | ">>"
|
||||
* eqlrel : "="
|
||||
* | "=="
|
||||
* | "!="
|
||||
* rel : "<"
|
||||
* | ">"
|
||||
* | "<="
|
||||
* | ">="
|
||||
*
|
||||
*
|
||||
* This expression evaluator is lifted from a public-domain
|
||||
* C Pre-Processor included with the DECUS C Compiler distribution.
|
||||
* It is hacked somewhat to be suitable for m4.
|
||||
*
|
||||
* Originally by: Mike Lutz
|
||||
* Bob Harper
|
||||
*/
|
||||
|
||||
#include "mdef.h"
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#define EOS (char) 0
|
||||
#define EQL 0
|
||||
#define NEQ 1
|
||||
#define LSS 2
|
||||
#define LEQ 3
|
||||
#define GTR 4
|
||||
#define GEQ 5
|
||||
|
||||
static char *nxtch; /* Parser scan pointer */
|
||||
|
||||
/*
|
||||
* For longjmp
|
||||
*/
|
||||
#include <setjmp.h>
|
||||
static jmp_buf expjump;
|
||||
|
||||
/*
|
||||
* macros:
|
||||
*
|
||||
* ungetch - Put back the last character examined.
|
||||
* getch - return the next character from expr string.
|
||||
*/
|
||||
#define ungetch() nxtch--
|
||||
#define getch() *nxtch++
|
||||
|
||||
int expr(expbuf)
|
||||
char *expbuf;
|
||||
{
|
||||
register int rval;
|
||||
|
||||
nxtch = expbuf;
|
||||
if (setjmp(expjump) != 0)
|
||||
return (FALSE);
|
||||
rval = query();
|
||||
if (skipws() == EOS)
|
||||
return(rval);
|
||||
experr("Ill-formed expression");
|
||||
/* NOTREACHED */
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* query : lor | lor '?' query ':' query
|
||||
*
|
||||
*/
|
||||
int query()
|
||||
{
|
||||
register int bool, true_val, false_val;
|
||||
|
||||
bool = lor();
|
||||
if (skipws() != '?') {
|
||||
ungetch();
|
||||
return(bool);
|
||||
}
|
||||
|
||||
true_val = query();
|
||||
if (skipws() != ':')
|
||||
experr("Bad query");
|
||||
|
||||
false_val = query();
|
||||
return(bool ? true_val : false_val);
|
||||
}
|
||||
|
||||
/*
|
||||
* lor : land { '||' land }
|
||||
*
|
||||
*/
|
||||
int lor()
|
||||
{
|
||||
register int c, vl, vr;
|
||||
|
||||
vl = land();
|
||||
while ((c = skipws()) == '|' && getch() == '|') {
|
||||
vr = land();
|
||||
vl = vl || vr;
|
||||
}
|
||||
|
||||
if (c == '|')
|
||||
ungetch();
|
||||
ungetch();
|
||||
return(vl);
|
||||
}
|
||||
|
||||
/*
|
||||
* land : bor { '&&' bor }
|
||||
*
|
||||
*/
|
||||
int land()
|
||||
{
|
||||
register int c, vl, vr;
|
||||
|
||||
vl = bor();
|
||||
while ((c = skipws()) == '&' && getch() == '&') {
|
||||
vr = bor();
|
||||
vl = vl && vr;
|
||||
}
|
||||
|
||||
if (c == '&')
|
||||
ungetch();
|
||||
ungetch();
|
||||
return(vl);
|
||||
}
|
||||
|
||||
/*
|
||||
* bor : bxor { '|' bxor }
|
||||
*
|
||||
*/
|
||||
int bor()
|
||||
{
|
||||
register int vl, vr, c;
|
||||
|
||||
vl = bxor();
|
||||
while ((c = skipws()) == '|' && getch() != '|') {
|
||||
ungetch();
|
||||
vr = bxor();
|
||||
vl |= vr;
|
||||
}
|
||||
|
||||
if (c == '|')
|
||||
ungetch();
|
||||
ungetch();
|
||||
return(vl);
|
||||
}
|
||||
|
||||
/*
|
||||
* bxor : band { '^' band }
|
||||
*
|
||||
*/
|
||||
int bxor()
|
||||
{
|
||||
register int vl, vr;
|
||||
|
||||
vl = band();
|
||||
while (skipws() == '^') {
|
||||
vr = band();
|
||||
vl ^= vr;
|
||||
}
|
||||
|
||||
ungetch();
|
||||
return(vl);
|
||||
}
|
||||
|
||||
/*
|
||||
* band : eql { '&' eql }
|
||||
*
|
||||
*/
|
||||
int band()
|
||||
{
|
||||
register int vl, vr, c;
|
||||
|
||||
vl = eql();
|
||||
while ((c = skipws()) == '&' && getch() != '&') {
|
||||
ungetch();
|
||||
vr = eql();
|
||||
vl &= vr;
|
||||
}
|
||||
|
||||
if (c == '&')
|
||||
ungetch();
|
||||
ungetch();
|
||||
return(vl);
|
||||
}
|
||||
|
||||
/*
|
||||
* eql : relat { eqrel relat }
|
||||
*
|
||||
*/
|
||||
int eql()
|
||||
{
|
||||
register int vl, vr, rel;
|
||||
|
||||
vl = relat();
|
||||
while ((rel = geteql()) != -1) {
|
||||
vr = relat();
|
||||
|
||||
switch (rel) {
|
||||
|
||||
case EQL:
|
||||
vl = (vl == vr);
|
||||
break;
|
||||
case NEQ:
|
||||
vl = (vl != vr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return(vl);
|
||||
}
|
||||
|
||||
/*
|
||||
* relat : shift { rel shift }
|
||||
*
|
||||
*/
|
||||
int relat()
|
||||
{
|
||||
register int vl, vr, rel;
|
||||
|
||||
vl = shift();
|
||||
while ((rel = getrel()) != -1) {
|
||||
|
||||
vr = shift();
|
||||
switch (rel) {
|
||||
|
||||
case LEQ:
|
||||
vl = (vl <= vr);
|
||||
break;
|
||||
case LSS:
|
||||
vl = (vl < vr);
|
||||
break;
|
||||
case GTR:
|
||||
vl = (vl > vr);
|
||||
break;
|
||||
case GEQ:
|
||||
vl = (vl >= vr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return(vl);
|
||||
}
|
||||
|
||||
/*
|
||||
* shift : primary { shop primary }
|
||||
*
|
||||
*/
|
||||
int shift()
|
||||
{
|
||||
register int vl, vr, c;
|
||||
|
||||
vl = primary();
|
||||
while (((c = skipws()) == '<' || c == '>') && c == getch()) {
|
||||
vr = primary();
|
||||
|
||||
if (c == '<')
|
||||
vl <<= vr;
|
||||
else
|
||||
vl >>= vr;
|
||||
}
|
||||
|
||||
if (c == '<' || c == '>')
|
||||
ungetch();
|
||||
ungetch();
|
||||
return(vl);
|
||||
}
|
||||
|
||||
/*
|
||||
* primary : term { addop term }
|
||||
*
|
||||
*/
|
||||
int primary()
|
||||
{
|
||||
register int c, vl, vr;
|
||||
|
||||
vl = term();
|
||||
while ((c = skipws()) == '+' || c == '-') {
|
||||
vr = term();
|
||||
if (c == '+')
|
||||
vl += vr;
|
||||
else
|
||||
vl -= vr;
|
||||
}
|
||||
|
||||
ungetch();
|
||||
return(vl);
|
||||
}
|
||||
|
||||
/*
|
||||
* <term> := <unary> { <mulop> <unary> }
|
||||
*
|
||||
*/
|
||||
int term()
|
||||
{
|
||||
register int c, vl, vr;
|
||||
|
||||
vl = unary();
|
||||
while ((c = skipws()) == '*' || c == '/' || c == '%') {
|
||||
vr = unary();
|
||||
|
||||
switch (c) {
|
||||
case '*':
|
||||
vl *= vr;
|
||||
break;
|
||||
case '/':
|
||||
vl /= vr;
|
||||
break;
|
||||
case '%':
|
||||
vl %= vr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ungetch();
|
||||
return(vl);
|
||||
}
|
||||
|
||||
/*
|
||||
* unary : factor | unop unary
|
||||
*
|
||||
*/
|
||||
int unary()
|
||||
{
|
||||
register int val, c;
|
||||
|
||||
if ((c = skipws()) == '!' || c == '~' || c == '-') {
|
||||
val = unary();
|
||||
|
||||
switch (c) {
|
||||
case '!':
|
||||
return(! val);
|
||||
case '~':
|
||||
return(~ val);
|
||||
case '-':
|
||||
return(- val);
|
||||
}
|
||||
}
|
||||
|
||||
ungetch();
|
||||
return(factor());
|
||||
}
|
||||
|
||||
/*
|
||||
* factor : constant | '(' query ')'
|
||||
*
|
||||
*/
|
||||
int factor()
|
||||
{
|
||||
register int val;
|
||||
|
||||
if (skipws() == '(') {
|
||||
val = query();
|
||||
if (skipws() != ')')
|
||||
experr("Bad factor");
|
||||
return(val);
|
||||
}
|
||||
|
||||
ungetch();
|
||||
return(constant());
|
||||
}
|
||||
|
||||
/*
|
||||
* constant: num | 'char'
|
||||
*
|
||||
*/
|
||||
int constant()
|
||||
{
|
||||
/*
|
||||
* Note: constant() handles multi-byte constants
|
||||
*/
|
||||
|
||||
register int i;
|
||||
register int value;
|
||||
register char c;
|
||||
int v[sizeof (int)];
|
||||
|
||||
if (skipws() != '\'') {
|
||||
ungetch();
|
||||
return(num());
|
||||
}
|
||||
for (i = 0; i < sizeof(int); i++) {
|
||||
if ((c = getch()) == '\'') {
|
||||
ungetch();
|
||||
break;
|
||||
}
|
||||
if (c == '\\') {
|
||||
switch (c = getch()) {
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
ungetch();
|
||||
c = num();
|
||||
break;
|
||||
case 'n':
|
||||
c = 012;
|
||||
break;
|
||||
case 'r':
|
||||
c = 015;
|
||||
break;
|
||||
case 't':
|
||||
c = 011;
|
||||
break;
|
||||
case 'b':
|
||||
c = 010;
|
||||
break;
|
||||
case 'f':
|
||||
c = 014;
|
||||
break;
|
||||
}
|
||||
}
|
||||
v[i] = c;
|
||||
}
|
||||
if (i == 0 || getch() != '\'')
|
||||
experr("Illegal character constant");
|
||||
for (value = 0; --i >= 0;) {
|
||||
value <<= 8;
|
||||
value += v[i];
|
||||
}
|
||||
return(value);
|
||||
}
|
||||
|
||||
/*
|
||||
* num : digit | num digit
|
||||
*
|
||||
*/
|
||||
int num()
|
||||
{
|
||||
register int rval, c, base;
|
||||
int ndig;
|
||||
|
||||
ndig = 0;
|
||||
if ((c = skipws()) == '0') {
|
||||
c = getch ();
|
||||
if (c == 'x' || c == 'X') {
|
||||
base = 16;
|
||||
c = getch ();
|
||||
} else {
|
||||
base = 8;
|
||||
ndig = 1;
|
||||
}
|
||||
} else {
|
||||
base = 10;
|
||||
}
|
||||
rval = 0;
|
||||
for (;;) {
|
||||
if (isdigit(c)) c -= '0';
|
||||
else if (isupper (c)) c -= ('A' - 10);
|
||||
else if (islower (c)) c -= ('a' - 10);
|
||||
else break;
|
||||
if (c < 0 || c >= base)
|
||||
break;
|
||||
|
||||
rval *= base;
|
||||
rval += c;
|
||||
c = getch();
|
||||
ndig++;
|
||||
}
|
||||
ungetch();
|
||||
if (ndig)
|
||||
return(rval);
|
||||
experr("Bad constant");
|
||||
/* NOTREACHED */
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* eqlrel : '=' | '==' | '!='
|
||||
*
|
||||
*/
|
||||
int geteql()
|
||||
{
|
||||
register int c1, c2;
|
||||
|
||||
c1 = skipws();
|
||||
c2 = getch();
|
||||
|
||||
switch (c1) {
|
||||
|
||||
case '=':
|
||||
if (c2 != '=')
|
||||
ungetch();
|
||||
return(EQL);
|
||||
|
||||
case '!':
|
||||
if (c2 == '=')
|
||||
return(NEQ);
|
||||
ungetch();
|
||||
ungetch();
|
||||
return(-1);
|
||||
|
||||
default:
|
||||
ungetch();
|
||||
ungetch();
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* rel : '<' | '>' | '<=' | '>='
|
||||
*
|
||||
*/
|
||||
int getrel()
|
||||
{
|
||||
register int c1, c2;
|
||||
|
||||
c1 = skipws();
|
||||
c2 = getch();
|
||||
|
||||
switch (c1) {
|
||||
|
||||
case '<':
|
||||
if (c2 == '=')
|
||||
return(LEQ);
|
||||
ungetch();
|
||||
return(LSS);
|
||||
|
||||
case '>':
|
||||
if (c2 == '=')
|
||||
return(GEQ);
|
||||
ungetch();
|
||||
return(GTR);
|
||||
|
||||
default:
|
||||
ungetch();
|
||||
ungetch();
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip over any white space and return terminating char.
|
||||
*/
|
||||
int skipws()
|
||||
{
|
||||
register char c;
|
||||
|
||||
while ((c = getch()) <= ' ' && c > EOS)
|
||||
;
|
||||
return(c);
|
||||
}
|
||||
|
||||
/*
|
||||
* Error handler - resets environment to eval(), prints an error,
|
||||
* and returns FALSE.
|
||||
*/
|
||||
int experr(msg)
|
||||
char *msg;
|
||||
{
|
||||
printf("mp: %s\n",msg);
|
||||
longjmp(expjump, -1); /* Force eval() to return FALSE */
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
extern ndptr hashtab[]; /* hash table for macros etc. */
|
||||
extern char buf[]; /* push-back buffer */
|
||||
extern char *bp; /* first available character */
|
||||
extern char *endpbb; /* end of push-back buffer */
|
||||
extern stae mstack[]; /* stack of m4 machine */
|
||||
extern char *ep; /* first free char in strspace */
|
||||
extern char *endest; /* end of string space */
|
||||
extern int sp; /* current m4 stack pointer */
|
||||
extern int fp; /* m4 call frame pointer */
|
||||
extern FILE *infile[]; /* input file stack (0=stdin) */
|
||||
extern FILE *outfile[]; /* diversion array(0=bitbucket)*/
|
||||
extern FILE *active; /* active output file pointer */
|
||||
extern char *m4temp; /* filename for diversions */
|
||||
extern int ilevel; /* input file stack pointer */
|
||||
extern int oindex; /* diversion index.. */
|
||||
extern char *null; /* as it says.. just a null.. */
|
||||
extern char *m4wraps; /* m4wrap string default.. */
|
||||
extern char lquote; /* left quote character (`) */
|
||||
extern char rquote; /* right quote character (') */
|
||||
extern char scommt; /* start character for comment */
|
||||
extern char ecommt; /* end character for comment */
|
|
@ -1,110 +0,0 @@
|
|||
/*
|
||||
* look.c
|
||||
* Facility: m4 macro processor
|
||||
* by: oz
|
||||
*/
|
||||
|
||||
#include "mdef.h"
|
||||
#include "extr.h"
|
||||
|
||||
/*
|
||||
* hash - compute hash value using the proverbial
|
||||
* hashing function. Taken from K&R.
|
||||
*/
|
||||
int hash (name)
|
||||
register char *name;
|
||||
{
|
||||
register int h = 0;
|
||||
while (*name)
|
||||
h += *name++;
|
||||
return (h % HASHSIZE);
|
||||
}
|
||||
|
||||
/*
|
||||
* lookup - find name in the hash table
|
||||
*
|
||||
*/
|
||||
ndptr lookup(name)
|
||||
char *name;
|
||||
{
|
||||
register ndptr p;
|
||||
|
||||
for (p = hashtab[hash(name)]; p != nil; p = p->nxtptr)
|
||||
if (strcmp(name, p->name) == 0)
|
||||
break;
|
||||
return (p);
|
||||
}
|
||||
|
||||
/*
|
||||
* addent - hash and create an entry in the hash
|
||||
* table. The new entry is added in front
|
||||
* of a hash bucket.
|
||||
*/
|
||||
ndptr addent(name)
|
||||
char *name;
|
||||
{
|
||||
register int h;
|
||||
ndptr p;
|
||||
|
||||
h = hash(name);
|
||||
if ((p = (ndptr) malloc(sizeof(struct ndblock))) != NULL) {
|
||||
p->nxtptr = hashtab[h];
|
||||
hashtab[h] = p;
|
||||
p->name = strsave(name);
|
||||
}
|
||||
else
|
||||
error("m4: no more memory.");
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* remhash - remove an entry from the hashtable
|
||||
*
|
||||
*/
|
||||
void remhash(name, all)
|
||||
char *name;
|
||||
int all;
|
||||
{
|
||||
register int h;
|
||||
register ndptr xp, tp, mp;
|
||||
|
||||
h = hash(name);
|
||||
mp = hashtab[h];
|
||||
tp = nil;
|
||||
while (mp != nil) {
|
||||
if (strcmp(mp->name, name) == 0) {
|
||||
mp = mp->nxtptr;
|
||||
if (tp == nil) {
|
||||
freent(hashtab[h]);
|
||||
hashtab[h] = mp;
|
||||
}
|
||||
else {
|
||||
xp = tp->nxtptr;
|
||||
tp->nxtptr = mp;
|
||||
freent(xp);
|
||||
}
|
||||
if (!all)
|
||||
break;
|
||||
}
|
||||
else {
|
||||
tp = mp;
|
||||
mp = mp->nxtptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* freent - free a hashtable information block
|
||||
*
|
||||
*/
|
||||
void freent(p)
|
||||
ndptr p;
|
||||
{
|
||||
if (!(p->type & STATIC)) {
|
||||
free(p->name);
|
||||
if (p->defn != null)
|
||||
free(p->defn);
|
||||
}
|
||||
free(p);
|
||||
}
|
||||
|
|
@ -1,457 +0,0 @@
|
|||
/*
|
||||
* main.c
|
||||
* Facility: m4 macro processor
|
||||
* by: oz
|
||||
*/
|
||||
|
||||
#include "mdef.h"
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Modification History:
|
||||
*
|
||||
* Jan 28 1986 Oz Break the whole thing into little
|
||||
* pieces, for easier (?) maintenance.
|
||||
*
|
||||
* Dec 12 1985 Oz Optimize the code, try to squeeze
|
||||
* few microseconds out..
|
||||
*
|
||||
* Dec 05 1985 Oz Add getopt interface, define (-D),
|
||||
* undefine (-U) options.
|
||||
*
|
||||
* Oct 21 1985 Oz Clean up various bugs, add comment handling.
|
||||
*
|
||||
* June 7 1985 Oz Add some of SysV m4 stuff (m4wrap, pushdef,
|
||||
* popdef, decr, shift etc.).
|
||||
*
|
||||
* June 5 1985 Oz Initial cut.
|
||||
*
|
||||
* 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 nonsense 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
|
||||
* . |
|
||||
* +-------+ |
|
||||
* | <----------+
|
||||
* +-------+
|
||||
*
|
||||
* [2] We have three types of null values:
|
||||
*
|
||||
* nil - nodeblock pointer type 0
|
||||
* null - null string ("")
|
||||
* NULL - Stdio-defined NULL
|
||||
*
|
||||
*/
|
||||
|
||||
ndptr hashtab[HASHSIZE]; /* hash table for macros etc. */
|
||||
char buf[BUFSIZE]; /* push-back buffer */
|
||||
char *bp = buf; /* first available character */
|
||||
char *endpbb = buf+BUFSIZE; /* end of push-back buffer */
|
||||
stae mstack[STACKMAX+1]; /* stack of m4 machine */
|
||||
char strspace[STRSPMAX+1]; /* string space for evaluation */
|
||||
char *ep = strspace; /* first free char in strspace */
|
||||
char *endest= strspace+STRSPMAX;/* end of string space */
|
||||
int sp; /* current m4 stack pointer */
|
||||
int fp; /* m4 call frame pointer */
|
||||
FILE *infile[MAXINP]; /* input file stack (0=stdin) */
|
||||
FILE *outfile[MAXOUT]; /* diversion array(0=bitbucket)*/
|
||||
FILE *active; /* active output file pointer */
|
||||
char *m4temp; /* filename for diversions */
|
||||
int ilevel = 0; /* input file stack pointer */
|
||||
int oindex = 0; /* diversion index.. */
|
||||
char *null = ""; /* as it says.. just a null.. */
|
||||
char *m4wraps = ""; /* m4wrap string default.. */
|
||||
char lquote = LQUOTE; /* left quote character (`) */
|
||||
char rquote = RQUOTE; /* right quote character (') */
|
||||
char scommt = SCOMMT; /* start character for comment */
|
||||
char ecommt = ECOMMT; /* end character for comment */
|
||||
struct keyblk keywrds[] = { /* m4 keywords to be installed */
|
||||
"include", INCLTYPE,
|
||||
"sinclude", SINCTYPE,
|
||||
"define", DEFITYPE,
|
||||
"defn", DEFNTYPE,
|
||||
"divert", DIVRTYPE,
|
||||
"expr", EXPRTYPE,
|
||||
"eval", EXPRTYPE,
|
||||
"substr", SUBSTYPE,
|
||||
"ifelse", IFELTYPE,
|
||||
"ifdef", IFDFTYPE,
|
||||
"len", LENGTYPE,
|
||||
"incr", INCRTYPE,
|
||||
"decr", DECRTYPE,
|
||||
"dnl", DNLNTYPE,
|
||||
"changequote", CHNQTYPE,
|
||||
"changecom", CHNCTYPE,
|
||||
"index", INDXTYPE,
|
||||
#ifdef EXTENDED
|
||||
"paste", PASTTYPE,
|
||||
"spaste", SPASTYPE,
|
||||
#endif
|
||||
"popdef", POPDTYPE,
|
||||
"pushdef", PUSDTYPE,
|
||||
"dumpdef", DUMPTYPE,
|
||||
"shift", SHIFTYPE,
|
||||
"translit", TRNLTYPE,
|
||||
"undefine", UNDFTYPE,
|
||||
"undivert", UNDVTYPE,
|
||||
"divnum", DIVNTYPE,
|
||||
"maketemp", MKTMTYPE,
|
||||
"errprint", ERRPTYPE,
|
||||
"m4wrap", M4WRTYPE,
|
||||
"m4exit", EXITTYPE,
|
||||
#if unix || vms
|
||||
"syscmd", SYSCTYPE,
|
||||
"sysval", SYSVTYPE,
|
||||
#endif
|
||||
#if unix
|
||||
"unix", MACRTYPE,
|
||||
#else
|
||||
#if vms
|
||||
"vms", MACRTYPE,
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
#define MAXKEYS (sizeof(keywrds)/sizeof(struct keyblk))
|
||||
|
||||
extern int optind;
|
||||
extern char *optarg;
|
||||
|
||||
int main(argc,argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
register int c;
|
||||
register int n;
|
||||
char *p;
|
||||
static char divnam[] = DIVNAM;
|
||||
|
||||
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
|
||||
signal(SIGINT, onintr);
|
||||
#ifdef NONZEROPAGES
|
||||
initm4();
|
||||
#endif
|
||||
initkwds();
|
||||
|
||||
while ((c = getopt(argc, argv, "tD:U:o:")) != EOF) {
|
||||
switch(c) {
|
||||
|
||||
case 'D': /* define something..*/
|
||||
for (p = optarg; *p; p++)
|
||||
if (*p == '=')
|
||||
break;
|
||||
if (*p)
|
||||
*p++ = EOS;
|
||||
dodefine(optarg, p);
|
||||
break;
|
||||
case 'U': /* undefine... */
|
||||
remhash(optarg, TOP);
|
||||
break;
|
||||
case 'o': /* specific output */
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if(argc > 1) { usage(); }
|
||||
infile[0] = stdin; /* default input (naturally) */
|
||||
if(argc == 1) {
|
||||
if(!(infile[0] = fopen(argv[0], "r"))) {
|
||||
perror(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
active = stdout; /* default active output */
|
||||
m4temp = mktemp(divnam); /* filename for diversions */
|
||||
|
||||
sp = -1; /* stack pointer initialized */
|
||||
fp = 0; /* frame pointer initialized */
|
||||
|
||||
macro(); /* get some work done here */
|
||||
|
||||
if (*m4wraps) { /* anything for rundown ?? */
|
||||
ilevel = 0; /* in case m4wrap includes.. */
|
||||
putback(EOF); /* eof is a must !! */
|
||||
pbstr(m4wraps); /* user-defined wrapup act */
|
||||
macro(); /* last will and testament */
|
||||
}
|
||||
else /* default wrap-up: undivert */
|
||||
for (n = 1; n < MAXOUT; n++)
|
||||
if (outfile[n] != NULL)
|
||||
getdiv(n);
|
||||
|
||||
/* remove bitbucket if used */
|
||||
if (outfile[0] != NULL) {
|
||||
(void) fclose(outfile[0]);
|
||||
m4temp[UNIQUE] = '0';
|
||||
#if vms
|
||||
(void) remove(m4temp);
|
||||
#else
|
||||
(void) unlink(m4temp);
|
||||
#endif
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* macro - the work horse..
|
||||
*
|
||||
*/
|
||||
void macro() {
|
||||
char token[MAXTOK];
|
||||
register char *s;
|
||||
register int t, l;
|
||||
register ndptr p;
|
||||
register int nlpar;
|
||||
|
||||
cycle {
|
||||
if ((t = gpbc()) == '_' || isalpha(t)) {
|
||||
putback(t);
|
||||
if ((p = inspect(s = token)) == nil) {
|
||||
if (sp < 0)
|
||||
while (*s)
|
||||
putc(*s++, active);
|
||||
else
|
||||
while (*s)
|
||||
chrsave(*s++);
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* real thing.. First build a call frame:
|
||||
*
|
||||
*/
|
||||
pushf(fp); /* previous call frm */
|
||||
pushf(p->type); /* type of the call */
|
||||
pushf(0); /* parenthesis level */
|
||||
fp = sp; /* new frame pointer */
|
||||
/*
|
||||
* now push the string arguments:
|
||||
*
|
||||
*/
|
||||
pushs(p->defn); /* defn string */
|
||||
pushs(p->name); /* macro name */
|
||||
pushs(ep); /* start next..*/
|
||||
|
||||
putback(l = gpbc());
|
||||
if (l != LPAREN) { /* add bracks */
|
||||
putback(RPAREN);
|
||||
putback(LPAREN);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (t == EOF) {
|
||||
if (sp > -1)
|
||||
error("m4: unexpected end of input");
|
||||
if (--ilevel < 0)
|
||||
break; /* all done thanks.. */
|
||||
(void) fclose(infile[ilevel+1]);
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* non-alpha single-char token seen..
|
||||
* [the order of else if .. stmts is
|
||||
* important.]
|
||||
*
|
||||
*/
|
||||
else if (t == lquote) { /* strip quotes */
|
||||
nlpar = 1;
|
||||
do {
|
||||
if ((l = gpbc()) == rquote)
|
||||
nlpar--;
|
||||
else if (l == lquote)
|
||||
nlpar++;
|
||||
else if (l == EOF)
|
||||
error("m4: missing right quote");
|
||||
if (nlpar > 0) {
|
||||
if (sp < 0)
|
||||
putc(l, active);
|
||||
else
|
||||
chrsave(l);
|
||||
}
|
||||
}
|
||||
while (nlpar != 0);
|
||||
}
|
||||
|
||||
else if (sp < 0) { /* not in a macro at all */
|
||||
if (t == scommt) { /* comment handling here */
|
||||
putc(t, active);
|
||||
while ((t = gpbc()) != ecommt)
|
||||
putc(t, active);
|
||||
}
|
||||
putc(t, active); /* output directly.. */
|
||||
}
|
||||
|
||||
else switch(t) {
|
||||
|
||||
case LPAREN:
|
||||
if (PARLEV > 0)
|
||||
chrsave(t);
|
||||
while (isspace(l = gpbc()))
|
||||
; /* skip blank, tab, nl.. */
|
||||
putback(l);
|
||||
PARLEV++;
|
||||
break;
|
||||
|
||||
case RPAREN:
|
||||
if (--PARLEV > 0)
|
||||
chrsave(t);
|
||||
else { /* end of argument list */
|
||||
chrsave(EOS);
|
||||
|
||||
if (sp == STACKMAX)
|
||||
error("m4: internal stack overflow");
|
||||
|
||||
if (CALTYP == MACRTYPE)
|
||||
expand((char**)mstack+fp+1,(int)sp-fp);
|
||||
else
|
||||
eval((char**)mstack+fp+1,sp-fp,CALTYP);
|
||||
|
||||
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()))
|
||||
;
|
||||
putback(l);
|
||||
pushs(ep);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
chrsave(t); /* stack the char */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* build an input token..
|
||||
* consider only those starting with _ or A-Za-z. This is a
|
||||
* combo with lookup to speed things up.
|
||||
*/
|
||||
ndptr
|
||||
inspect(tp)
|
||||
register char *tp;
|
||||
{
|
||||
register int h = 0;
|
||||
register char c;
|
||||
register char *name = tp;
|
||||
register char *etp = tp+MAXTOK;
|
||||
register ndptr p;
|
||||
|
||||
while (tp < etp && (isalnum(c = gpbc()) || c == '_'))
|
||||
h += (*tp++ = c);
|
||||
putback(c);
|
||||
if (tp == etp)
|
||||
error("m4: token too long");
|
||||
*tp = EOS;
|
||||
for (p = hashtab[h%HASHSIZE]; p != nil; p = p->nxtptr)
|
||||
if (strcmp(name, p->name) == 0)
|
||||
break;
|
||||
return(p);
|
||||
}
|
||||
|
||||
#ifdef NONZEROPAGES
|
||||
/*
|
||||
* initm4 - initialize various tables. Useful only if your system
|
||||
* does not know anything about demand-zero pages.
|
||||
*
|
||||
*/
|
||||
void initm4()
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 0; i < HASHSIZE; i++)
|
||||
hashtab[i] = nil;
|
||||
for (i = 0; i < MAXOUT; i++)
|
||||
outfile[i] = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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. We also assume that there is enough memory
|
||||
* to at least install the keywords (i.e. malloc won't fail).
|
||||
*
|
||||
*/
|
||||
void initkwds() {
|
||||
register int i;
|
||||
register int h;
|
||||
register ndptr p;
|
||||
|
||||
for (i = 0; i < MAXKEYS; i++) {
|
||||
h = hash(keywrds[i].knam);
|
||||
p = (ndptr) malloc(sizeof(struct ndblock));
|
||||
p->nxtptr = hashtab[h];
|
||||
hashtab[h] = p;
|
||||
p->name = keywrds[i].knam;
|
||||
p->defn = null;
|
||||
p->type = keywrds[i].ktyp | STATIC;
|
||||
}
|
||||
}
|
|
@ -1,276 +0,0 @@
|
|||
/*
|
||||
* mdef.h
|
||||
* Facility: m4 macro processor
|
||||
* by: oz
|
||||
*/
|
||||
|
||||
|
||||
#define unix 1 /* (kjb) */
|
||||
|
||||
#ifndef unix
|
||||
#define unix 0
|
||||
#endif
|
||||
|
||||
#ifndef vms
|
||||
#define vms 0
|
||||
#endif
|
||||
|
||||
#if vms
|
||||
|
||||
#include stdio
|
||||
#include ctype
|
||||
#include signal
|
||||
|
||||
#else
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <ctype.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
*
|
||||
* m4 constants..
|
||||
*
|
||||
*/
|
||||
|
||||
#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 STATIC 128
|
||||
|
||||
/*
|
||||
* m4 special characters
|
||||
*/
|
||||
|
||||
#define ARGFLAG '$'
|
||||
#define LPAREN '('
|
||||
#define RPAREN ')'
|
||||
#define LQUOTE '`'
|
||||
#define RQUOTE '\''
|
||||
#define COMMA ','
|
||||
#define SCOMMT '#'
|
||||
#define ECOMMT '\n'
|
||||
|
||||
/*
|
||||
* definitions of diversion files. If the name of
|
||||
* the file is changed, adjust UNIQUE to point to the
|
||||
* wildcard (*) character in the filename.
|
||||
*/
|
||||
|
||||
#if unix
|
||||
#define DIVNAM "/tmp/m4*XXXXXX" /* unix diversion files */
|
||||
#define UNIQUE 7 /* unique char location */
|
||||
#else
|
||||
#if vms
|
||||
#define DIVNAM "sys$login:m4*XXXXXX" /* vms diversion files */
|
||||
#define UNIQUE 12 /* unique char location */
|
||||
#else
|
||||
#define DIVNAM "\M4*XXXXXX" /* msdos diversion files */
|
||||
#define UNIQUE 3 /* unique char location */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* other important constants
|
||||
*/
|
||||
|
||||
#define EOS (char) 0
|
||||
#define MAXINP 10 /* maximum include files */
|
||||
#define MAXOUT 10 /* maximum # of diversions */
|
||||
#define MAXSTR 512 /* maximum size of string */
|
||||
#define BUFSIZE 4096 /* size of pushback buffer */
|
||||
#define STACKMAX 1024 /* size of call stack */
|
||||
#define STRSPMAX 4096 /* size of string space */
|
||||
#define MAXTOK MAXSTR /* maximum chars in a tokn */
|
||||
#define HASHSIZE 199 /* maximum size of hashtab */
|
||||
|
||||
#define ALL 1
|
||||
#define TOP 0
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#define cycle for(;;)
|
||||
|
||||
#ifdef VOID
|
||||
#define void int /* define if void is void. */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* m4 data structures
|
||||
*/
|
||||
|
||||
typedef struct ndblock *ndptr;
|
||||
|
||||
struct ndblock { /* hastable structure */
|
||||
char *name; /* entry name.. */
|
||||
char *defn; /* definition.. */
|
||||
int type; /* type of the entry.. */
|
||||
ndptr nxtptr; /* link to next entry.. */
|
||||
};
|
||||
|
||||
#define nil ((ndptr) 0)
|
||||
|
||||
struct keyblk {
|
||||
char *knam; /* keyword name */
|
||||
int ktyp; /* keyword type */
|
||||
};
|
||||
|
||||
typedef union { /* stack structure */
|
||||
int sfra; /* frame entry */
|
||||
char *sstr; /* string entry */
|
||||
} stae;
|
||||
|
||||
/*
|
||||
* macros for readibility and/or speed
|
||||
*
|
||||
* gpbc() - get a possibly pushed-back character
|
||||
* min() - select the minimum of two elements
|
||||
* pushf() - push a call frame entry onto stack
|
||||
* pushs() - push a string pointer onto stack
|
||||
*/
|
||||
#define gpbc() (bp > buf) ? *--bp : getc(infile[ilevel])
|
||||
#define min(x,y) ((x > y) ? y : x)
|
||||
#define pushf(x) if (sp < STACKMAX) mstack[++sp].sfra = (x)
|
||||
#define pushs(x) if (sp < STACKMAX) mstack[++sp].sstr = (x)
|
||||
|
||||
/*
|
||||
* . .
|
||||
* | . | <-- sp | . |
|
||||
* +-------+ +-----+
|
||||
* | arg 3 ----------------------->| str |
|
||||
* +-------+ | . |
|
||||
* | arg 2 ---PREVEP-----+ .
|
||||
* +-------+ |
|
||||
* . | | |
|
||||
* +-------+ | +-----+
|
||||
* | plev | PARLEV +-------->| str |
|
||||
* +-------+ | . |
|
||||
* | type | CALTYP .
|
||||
* +-------+
|
||||
* | prcf ---PREVFP--+
|
||||
* +-------+ |
|
||||
* | . | PREVSP |
|
||||
* . |
|
||||
* +-------+ |
|
||||
* | <----------+
|
||||
* +-------+
|
||||
*
|
||||
*/
|
||||
#define PARLEV (mstack[fp].sfra)
|
||||
#define CALTYP (mstack[fp-1].sfra)
|
||||
#define PREVEP (mstack[fp+3].sstr)
|
||||
#define PREVSP (fp-3)
|
||||
#define PREVFP (mstack[fp-2].sfra)
|
||||
|
||||
/* function prototypes */
|
||||
|
||||
/* eval.c */
|
||||
|
||||
_PROTOTYPE(void eval, (char *argv [], int argc, int td ));
|
||||
|
||||
/* expr.c */
|
||||
|
||||
_PROTOTYPE(int expr, (char *expbuf ));
|
||||
_PROTOTYPE(int query, (void));
|
||||
_PROTOTYPE(int lor, (void));
|
||||
_PROTOTYPE(int land, (void));
|
||||
_PROTOTYPE(int bor, (void));
|
||||
_PROTOTYPE(int bxor, (void));
|
||||
_PROTOTYPE(int band, (void));
|
||||
_PROTOTYPE(int eql, (void));
|
||||
_PROTOTYPE(int relat, (void));
|
||||
_PROTOTYPE(int shift, (void));
|
||||
_PROTOTYPE(int primary, (void));
|
||||
_PROTOTYPE(int term, (void));
|
||||
_PROTOTYPE(int unary, (void));
|
||||
_PROTOTYPE(int factor, (void));
|
||||
_PROTOTYPE(int constant, (void));
|
||||
_PROTOTYPE(int num, (void));
|
||||
_PROTOTYPE(int geteql, (void));
|
||||
_PROTOTYPE(int getrel, (void));
|
||||
_PROTOTYPE(int skipws, (void));
|
||||
_PROTOTYPE(int experr, (char *msg ));
|
||||
|
||||
/* look.c */
|
||||
|
||||
_PROTOTYPE(int hash, (char *name ));
|
||||
_PROTOTYPE(ndptr lookup, (char *name ));
|
||||
_PROTOTYPE(ndptr addent, (char *name ));
|
||||
_PROTOTYPE(void remhash, (char *name, int all ));
|
||||
_PROTOTYPE(void freent, (ndptr p ));
|
||||
|
||||
/* main.c */
|
||||
|
||||
_PROTOTYPE(int main, (int argc, char *argv []));
|
||||
_PROTOTYPE(void macro, (void));
|
||||
_PROTOTYPE(ndptr inspect, (char *tp ));
|
||||
_PROTOTYPE(void initm4, (void));
|
||||
_PROTOTYPE(void initkwds, (void));
|
||||
|
||||
/* misc.c */
|
||||
|
||||
_PROTOTYPE(int indx, (char *s1, char *s2 ));
|
||||
_PROTOTYPE(void putback, (int c ));
|
||||
_PROTOTYPE(void pbstr, (char *s ));
|
||||
_PROTOTYPE(void pbnum, (int n ));
|
||||
_PROTOTYPE(void chrsave, (int c ));
|
||||
_PROTOTYPE(void getdiv, (int ind ));
|
||||
_PROTOTYPE(void error, (char *s ));
|
||||
_PROTOTYPE(void onintr, (int s ));
|
||||
_PROTOTYPE(void killdiv, (void));
|
||||
_PROTOTYPE(char *strsave, (char *s ));
|
||||
_PROTOTYPE(void usage, (void));
|
||||
|
||||
/* serv.c */
|
||||
|
||||
_PROTOTYPE(void expand, (char *argv [], int argc ));
|
||||
_PROTOTYPE(void dodefine, (char *name, char *defn ));
|
||||
_PROTOTYPE(void dodefn, (char *name ));
|
||||
_PROTOTYPE(void dopushdef, (char *name, char *defn ));
|
||||
_PROTOTYPE(void dodump, (char *argv [], int argc ));
|
||||
_PROTOTYPE(void doifelse, (char *argv [], int argc ));
|
||||
_PROTOTYPE(int doincl, (char *ifile ));
|
||||
_PROTOTYPE(int dopaste, (char *pfile ));
|
||||
_PROTOTYPE(void dochq, (char *argv [], int argc ));
|
||||
_PROTOTYPE(void dochc, (char *argv [], int argc ));
|
||||
_PROTOTYPE(void dodiv, (int n ));
|
||||
_PROTOTYPE(void doundiv, (char *argv [], int argc ));
|
||||
_PROTOTYPE(void dosub, (char *argv [], int argc ));
|
||||
_PROTOTYPE(void map, (char *dest, char *src, char *from, char *to ));
|
|
@ -1,292 +0,0 @@
|
|||
/*
|
||||
* misc.c
|
||||
* Facility: m4 macro processor
|
||||
* by: oz
|
||||
*/
|
||||
|
||||
#include "mdef.h"
|
||||
#include "extr.h"
|
||||
|
||||
/*
|
||||
* indx - find the index of second str in the
|
||||
* first str.
|
||||
*/
|
||||
int indx(s1, s2)
|
||||
char *s1;
|
||||
char *s2;
|
||||
{
|
||||
register char *t;
|
||||
register char *p;
|
||||
register char *m;
|
||||
|
||||
for (p = s1; *p; p++) {
|
||||
for (t = p, m = s2; *m && *m == *t; m++, t++)
|
||||
;
|
||||
if (!*m)
|
||||
return(p - s1);
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* putback - push character back onto input
|
||||
*
|
||||
*/
|
||||
void putback (c)
|
||||
char c;
|
||||
{
|
||||
if (bp < endpbb)
|
||||
*bp++ = c;
|
||||
else
|
||||
error("m4: too many characters pushed back");
|
||||
}
|
||||
|
||||
/*
|
||||
* pbstr - push string back onto input
|
||||
* putback is replicated to improve
|
||||
* performance.
|
||||
*
|
||||
*/
|
||||
void pbstr(s)
|
||||
register char *s;
|
||||
{
|
||||
register char *es;
|
||||
register char *zp;
|
||||
|
||||
es = s;
|
||||
zp = bp;
|
||||
|
||||
while (*es)
|
||||
es++;
|
||||
es--;
|
||||
while (es >= s)
|
||||
if (zp < endpbb)
|
||||
*zp++ = *es--;
|
||||
if ((bp = zp) == endpbb)
|
||||
error("m4: too many characters pushed back");
|
||||
}
|
||||
|
||||
/*
|
||||
* pbnum - convert number to string, push back on input.
|
||||
*
|
||||
*/
|
||||
void pbnum (n)
|
||||
int n;
|
||||
{
|
||||
register int num;
|
||||
|
||||
num = (n < 0) ? -n : n;
|
||||
do {
|
||||
putback(num % 10 + '0');
|
||||
}
|
||||
while ((num /= 10) > 0);
|
||||
|
||||
if (n < 0) putback('-');
|
||||
}
|
||||
|
||||
/*
|
||||
* chrsave - put single char on string space
|
||||
*
|
||||
*/
|
||||
void chrsave (c)
|
||||
char c;
|
||||
{
|
||||
/*** if (sp < 0)
|
||||
putc(c, active);
|
||||
else ***/ if (ep < endest)
|
||||
*ep++ = c;
|
||||
else
|
||||
error("m4: string space overflow");
|
||||
}
|
||||
|
||||
/*
|
||||
* getdiv - read in a diversion file, and
|
||||
* trash it.
|
||||
*/
|
||||
void getdiv(ind)
|
||||
int ind;
|
||||
{
|
||||
register int c;
|
||||
register FILE *dfil;
|
||||
|
||||
if (active == outfile[ind])
|
||||
error("m4: undivert: diversion still active.");
|
||||
(void) fclose(outfile[ind]);
|
||||
outfile[ind] = NULL;
|
||||
m4temp[UNIQUE] = ind + '0';
|
||||
if ((dfil = fopen(m4temp, "r")) == NULL)
|
||||
error("m4: cannot undivert.");
|
||||
else
|
||||
while((c = getc(dfil)) != EOF)
|
||||
putc(c, active);
|
||||
(void) fclose(dfil);
|
||||
|
||||
#if vms
|
||||
if (remove(m4temp))
|
||||
#else
|
||||
if (unlink(m4temp) == -1)
|
||||
#endif
|
||||
error("m4: cannot unlink.");
|
||||
}
|
||||
|
||||
/*
|
||||
* Very fatal error. Close all files
|
||||
* and die hard.
|
||||
*/
|
||||
void error(s)
|
||||
char *s;
|
||||
{
|
||||
killdiv();
|
||||
fprintf(stderr,"%s\n",s);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Interrupt handling
|
||||
*/
|
||||
static char *msg = "\ninterrupted.";
|
||||
|
||||
void onintr(s)
|
||||
int s; /* ANSI requires the parameter */
|
||||
{
|
||||
error(msg);
|
||||
}
|
||||
|
||||
/*
|
||||
* killdiv - get rid of the diversion files
|
||||
*
|
||||
*/
|
||||
void killdiv() {
|
||||
register int n;
|
||||
|
||||
for (n = 0; n < MAXOUT; n++)
|
||||
if (outfile[n] != NULL) {
|
||||
(void) fclose (outfile[n]);
|
||||
m4temp[UNIQUE] = n + '0';
|
||||
#if vms
|
||||
(void) remove (m4temp);
|
||||
#else
|
||||
(void) unlink (m4temp);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* save a string somewhere..
|
||||
*
|
||||
*/
|
||||
char *strsave(s)
|
||||
char *s;
|
||||
{
|
||||
register int n;
|
||||
char *p;
|
||||
|
||||
n = strlen(s)+1;
|
||||
p = (char *) malloc(n);
|
||||
if (p != NULL) (void) memcpy(p, s, n);
|
||||
return (p);
|
||||
}
|
||||
|
||||
void usage() {
|
||||
fprintf(stderr, "Usage: m4 [-Dname[=val]] [-Uname]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef GETOPT
|
||||
/*
|
||||
* H. Spencer getopt - get option letter from argv
|
||||
*
|
||||
*
|
||||
#include <stdio.h>
|
||||
*
|
||||
*/
|
||||
|
||||
char *optarg; /* Global argument pointer. */
|
||||
int optind = 0; /* Global argv index. */
|
||||
|
||||
static char *scan = NULL; /* Private scan pointer. */
|
||||
|
||||
int
|
||||
getopt(argc, argv, optstring)
|
||||
int argc;
|
||||
char *argv[];
|
||||
char *optstring;
|
||||
{
|
||||
register char c;
|
||||
register char *place;
|
||||
|
||||
optarg = NULL;
|
||||
|
||||
if (scan == NULL || *scan == '\0') {
|
||||
if (optind == 0)
|
||||
optind++;
|
||||
|
||||
if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
|
||||
return(EOF);
|
||||
if (strcmp(argv[optind], "--")==0) {
|
||||
optind++;
|
||||
return(EOF);
|
||||
}
|
||||
|
||||
scan = argv[optind]+1;
|
||||
optind++;
|
||||
}
|
||||
|
||||
c = *scan++;
|
||||
place = index(optstring, c);
|
||||
|
||||
if (place == NULL || c == ':') {
|
||||
fprintf(stderr, "%s: unknown option -%c\n", argv[0], c);
|
||||
return('?');
|
||||
}
|
||||
|
||||
place++;
|
||||
if (*place == ':') {
|
||||
if (*scan != '\0') {
|
||||
optarg = scan;
|
||||
scan = NULL;
|
||||
} else {
|
||||
optarg = argv[optind];
|
||||
optind++;
|
||||
}
|
||||
}
|
||||
|
||||
return(c);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef DUFFCP
|
||||
/*
|
||||
* This code uses Duff's Device (tm Tom Duff)
|
||||
* to unroll the copying loop:
|
||||
* while (count-- > 0)
|
||||
* *to++ = *from++;
|
||||
*/
|
||||
|
||||
#define COPYBYTE *to++ = *from++
|
||||
|
||||
void memcpy(to, from, count)
|
||||
register char *from, *to;
|
||||
register int count;
|
||||
{
|
||||
if (count > 0) {
|
||||
register int loops = (count+8-1) >> 3; /* div 8 round up */
|
||||
|
||||
switch (count&(8-1)) { /* mod 8 */
|
||||
case 0: do {
|
||||
COPYBYTE;
|
||||
case 7: COPYBYTE;
|
||||
case 6: COPYBYTE;
|
||||
case 5: COPYBYTE;
|
||||
case 4: COPYBYTE;
|
||||
case 3: COPYBYTE;
|
||||
case 2: COPYBYTE;
|
||||
case 1: COPYBYTE;
|
||||
} while (--loops > 0);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1 +0,0 @@
|
|||
#define PATCHLEVEL 1
|
|
@ -1,423 +0,0 @@
|
|||
/*
|
||||
* serv.c
|
||||
* Facility: m4 macro processor
|
||||
* by: oz
|
||||
*/
|
||||
|
||||
#include "mdef.h"
|
||||
#include "extr.h"
|
||||
|
||||
char *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef */
|
||||
|
||||
/*
|
||||
* expand - user-defined macro expansion
|
||||
*
|
||||
*/
|
||||
void expand(argv, argc)
|
||||
register char *argv[];
|
||||
register int argc;
|
||||
{
|
||||
register char *t;
|
||||
register char *p;
|
||||
register int n;
|
||||
register int argno;
|
||||
|
||||
t = argv[0]; /* defn string as a whole */
|
||||
p = t;
|
||||
while (*p)
|
||||
p++;
|
||||
p--; /* last character of defn */
|
||||
while (p > t) {
|
||||
if (*(p-1) != ARGFLAG)
|
||||
putback(*p);
|
||||
else {
|
||||
switch (*p) {
|
||||
|
||||
case '#':
|
||||
pbnum(argc-2);
|
||||
break;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
if ((argno = *p - '0') < argc-1)
|
||||
pbstr(argv[argno+1]);
|
||||
break;
|
||||
case '*':
|
||||
for (n = argc - 1; n > 2; n--) {
|
||||
pbstr(argv[n]);
|
||||
putback(',');
|
||||
}
|
||||
pbstr(argv[2]);
|
||||
break;
|
||||
default :
|
||||
putback(*p);
|
||||
break;
|
||||
}
|
||||
p--;
|
||||
}
|
||||
p--;
|
||||
}
|
||||
if (p == t) /* do last character */
|
||||
putback(*p);
|
||||
}
|
||||
|
||||
/*
|
||||
* dodefine - install definition in the table
|
||||
*
|
||||
*/
|
||||
void dodefine(name, defn)
|
||||
register char *name;
|
||||
register char *defn;
|
||||
{
|
||||
register ndptr p;
|
||||
|
||||
if (!*name)
|
||||
error("m4: null definition.");
|
||||
if (strcmp(name, defn) == 0)
|
||||
error("m4: recursive definition.");
|
||||
if ((p = lookup(name)) == nil)
|
||||
p = addent(name);
|
||||
else if (p->defn != null)
|
||||
free(p->defn);
|
||||
if (!*defn)
|
||||
p->defn = null;
|
||||
else
|
||||
p->defn = strsave(defn);
|
||||
p->type = MACRTYPE;
|
||||
}
|
||||
|
||||
/*
|
||||
* dodefn - push back a quoted definition of
|
||||
* the given name.
|
||||
*/
|
||||
|
||||
void dodefn(name)
|
||||
char *name;
|
||||
{
|
||||
register ndptr p;
|
||||
|
||||
if ((p = lookup(name)) != nil && p->defn != null) {
|
||||
putback(rquote);
|
||||
pbstr(p->defn);
|
||||
putback(lquote);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* dopushdef - install a definition in the hash table
|
||||
* without removing a previous definition. Since
|
||||
* each new entry is entered in *front* of the
|
||||
* hash bucket, it hides a previous definition from
|
||||
* lookup.
|
||||
*/
|
||||
void dopushdef(name, defn)
|
||||
register char *name;
|
||||
register char *defn;
|
||||
{
|
||||
register ndptr p;
|
||||
|
||||
if (!*name)
|
||||
error("m4: null definition");
|
||||
if (strcmp(name, defn) == 0)
|
||||
error("m4: recursive definition.");
|
||||
p = addent(name);
|
||||
if (!*defn)
|
||||
p->defn = null;
|
||||
else
|
||||
p->defn = strsave(defn);
|
||||
p->type = MACRTYPE;
|
||||
}
|
||||
|
||||
/*
|
||||
* dodumpdef - dump the specified definitions in the hash
|
||||
* table to stderr. If nothing is specified, the entire
|
||||
* hash table is dumped.
|
||||
*
|
||||
*/
|
||||
void dodump(argv, argc)
|
||||
register char *argv[];
|
||||
register int argc;
|
||||
{
|
||||
register int n;
|
||||
ndptr p;
|
||||
|
||||
if (argc > 2) {
|
||||
for (n = 2; n < argc; n++)
|
||||
if ((p = lookup(argv[n])) != nil)
|
||||
fprintf(stderr, dumpfmt, p->name,
|
||||
p->defn);
|
||||
}
|
||||
else {
|
||||
for (n = 0; n < HASHSIZE; n++)
|
||||
for (p = hashtab[n]; p != nil; p = p->nxtptr)
|
||||
fprintf(stderr, dumpfmt, p->name,
|
||||
p->defn);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* doifelse - select one of two alternatives - loop.
|
||||
*
|
||||
*/
|
||||
void doifelse(argv,argc)
|
||||
register char *argv[];
|
||||
register int argc;
|
||||
{
|
||||
cycle {
|
||||
if (strcmp(argv[2], argv[3]) == 0)
|
||||
pbstr(argv[4]);
|
||||
else if (argc == 6)
|
||||
pbstr(argv[5]);
|
||||
else if (argc > 6) {
|
||||
argv += 3;
|
||||
argc -= 3;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* doinclude - include a given file.
|
||||
*
|
||||
*/
|
||||
int doincl(ifile)
|
||||
char *ifile;
|
||||
{
|
||||
if (ilevel+1 == MAXINP)
|
||||
error("m4: too many include files.");
|
||||
if ((infile[ilevel+1] = fopen(ifile, "r")) != NULL) {
|
||||
ilevel++;
|
||||
return (1);
|
||||
}
|
||||
else
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef EXTENDED
|
||||
/*
|
||||
* dopaste - include a given file without any
|
||||
* macro processing.
|
||||
*/
|
||||
int dopaste(pfile)
|
||||
char *pfile;
|
||||
{
|
||||
FILE *pf;
|
||||
register int c;
|
||||
|
||||
if ((pf = fopen(pfile, "r")) != NULL) {
|
||||
while((c = getc(pf)) != EOF)
|
||||
putc(c, active);
|
||||
(void) fclose(pf);
|
||||
return(1);
|
||||
}
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* dochq - change quote characters
|
||||
*
|
||||
*/
|
||||
void dochq(argv, argc)
|
||||
register char *argv[];
|
||||
register int argc;
|
||||
{
|
||||
if (argc > 2) {
|
||||
if (*argv[2])
|
||||
lquote = *argv[2];
|
||||
if (argc > 3) {
|
||||
if (*argv[3])
|
||||
rquote = *argv[3];
|
||||
}
|
||||
else
|
||||
rquote = lquote;
|
||||
}
|
||||
else {
|
||||
lquote = LQUOTE;
|
||||
rquote = RQUOTE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* dochc - change comment characters
|
||||
*
|
||||
*/
|
||||
void dochc(argv, argc)
|
||||
register char *argv[];
|
||||
register int argc;
|
||||
{
|
||||
if (argc > 2) {
|
||||
if (*argv[2])
|
||||
scommt = *argv[2];
|
||||
if (argc > 3) {
|
||||
if (*argv[3])
|
||||
ecommt = *argv[3];
|
||||
}
|
||||
else
|
||||
ecommt = ECOMMT;
|
||||
}
|
||||
else {
|
||||
scommt = SCOMMT;
|
||||
ecommt = ECOMMT;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* dodivert - divert the output to a temporary file
|
||||
*
|
||||
*/
|
||||
void dodiv(n)
|
||||
register int n;
|
||||
{
|
||||
if (n < 0 || n >= MAXOUT)
|
||||
n = 0; /* bitbucket */
|
||||
if (outfile[n] == NULL) {
|
||||
m4temp[UNIQUE] = n + '0';
|
||||
if ((outfile[n] = fopen(m4temp, "w")) == NULL)
|
||||
error("m4: cannot divert.");
|
||||
}
|
||||
oindex = n;
|
||||
active = outfile[n];
|
||||
}
|
||||
|
||||
/*
|
||||
* doundivert - undivert a specified output, or all
|
||||
* other outputs, in numerical order.
|
||||
*/
|
||||
void doundiv(argv, argc)
|
||||
register char *argv[];
|
||||
register int argc;
|
||||
{
|
||||
register int ind;
|
||||
register int n;
|
||||
|
||||
if (argc > 2) {
|
||||
for (ind = 2; ind < argc; ind++) {
|
||||
n = atoi(argv[ind]);
|
||||
if (n > 0 && n < MAXOUT && outfile[n] != NULL)
|
||||
getdiv(n);
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
for (n = 1; n < MAXOUT; n++)
|
||||
if (outfile[n] != NULL)
|
||||
getdiv(n);
|
||||
}
|
||||
|
||||
/*
|
||||
* dosub - select substring
|
||||
*
|
||||
*/
|
||||
void dosub (argv, argc)
|
||||
register char *argv[];
|
||||
register int argc;
|
||||
{
|
||||
register char *ap, *fc, *k;
|
||||
register int nc;
|
||||
|
||||
if (argc < 5)
|
||||
nc = MAXTOK;
|
||||
else
|
||||
#ifdef EXPR
|
||||
nc = expr(argv[4]);
|
||||
#else
|
||||
nc = atoi(argv[4]);
|
||||
#endif
|
||||
ap = argv[2]; /* target string */
|
||||
#ifdef EXPR
|
||||
fc = ap + expr(argv[3]); /* first char */
|
||||
#else
|
||||
fc = ap + atoi(argv[3]); /* first char */
|
||||
#endif
|
||||
if (fc >= ap && fc < ap+strlen(ap))
|
||||
for (k = fc+min(nc,strlen(fc))-1; k >= fc; k--)
|
||||
putback(*k);
|
||||
}
|
||||
|
||||
/*
|
||||
* map:
|
||||
* map every character of s1 that is specified in from
|
||||
* into s3 and replace in s. (source s1 remains untouched)
|
||||
*
|
||||
* This is a standard implementation of map(s,from,to) function of ICON
|
||||
* language. Within mapvec, we replace every character of "from" with
|
||||
* the corresponding character in "to". If "to" is shorter than "from",
|
||||
* than the corresponding entries are null, which means that those
|
||||
* characters dissapear altogether. Furthermore, imagine
|
||||
* map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
|
||||
* `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
|
||||
* ultimately maps to `*'. In order to achieve this effect in an efficient
|
||||
* manner (i.e. without multiple passes over the destination string), we
|
||||
* loop over mapvec, starting with the initial source character. if the
|
||||
* character value (dch) in this location is different than the source
|
||||
* character (sch), sch becomes dch, once again to index into mapvec, until
|
||||
* the character value stabilizes (i.e. sch = dch, in other words
|
||||
* mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
|
||||
* character, it will stabilize, since mapvec[0] == 0 at all times. At the
|
||||
* end, we restore mapvec* back to normal where mapvec[n] == n for
|
||||
* 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
|
||||
* about 5 times faster than any algorithm that makes multiple passes over
|
||||
* destination string.
|
||||
*
|
||||
*/
|
||||
|
||||
void map(dest,src,from,to)
|
||||
register char *dest;
|
||||
register char *src;
|
||||
register char *from;
|
||||
register char *to;
|
||||
{
|
||||
register char *tmp;
|
||||
register char sch, dch;
|
||||
static char mapvec[128] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
|
||||
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
|
||||
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
|
||||
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
|
||||
72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
|
||||
84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
|
||||
96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
|
||||
108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
|
||||
120, 121, 122, 123, 124, 125, 126, 127
|
||||
};
|
||||
|
||||
if (*src) {
|
||||
tmp = from;
|
||||
/*
|
||||
* create a mapping between "from" and "to"
|
||||
*/
|
||||
while (*from)
|
||||
mapvec[*from++] = (*to) ? *to++ : (char) 0;
|
||||
|
||||
while (*src) {
|
||||
sch = *src++;
|
||||
dch = mapvec[sch];
|
||||
while (dch != sch) {
|
||||
sch = dch;
|
||||
dch = mapvec[sch];
|
||||
}
|
||||
if (*dest = dch)
|
||||
dest++;
|
||||
}
|
||||
/*
|
||||
* restore all the changed characters
|
||||
*/
|
||||
while (*tmp) {
|
||||
mapvec[*tmp] = *tmp;
|
||||
tmp++;
|
||||
}
|
||||
}
|
||||
*dest = (char) 0;
|
||||
}
|
|
@ -1,3 +1,7 @@
|
|||
20110629:
|
||||
You must install clang. It is now used to build some of
|
||||
the userland utilities.
|
||||
|
||||
20110628:
|
||||
Since buildworld will also build the elf-libraries, you
|
||||
must follow the process in
|
||||
|
|
|
@ -2,3 +2,4 @@ common/lib/libc src/common/lib/libc
|
|||
lib/nbsd_libc src/lib/libc
|
||||
lib/nbsd_libm src/lib/libm
|
||||
nbsd_include src/include
|
||||
usr.bin/m4 src/usr.bin/m4
|
||||
|
|
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))')')
|
48
commands/m4/Test.m4 → usr.bin/m4/TEST/test.m4
Executable file → Normal file
48
commands/m4/Test.m4 → usr.bin/m4/TEST/test.m4
Executable file → Normal file
|
@ -1,4 +1,42 @@
|
|||
# $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'.
|
||||
|
@ -7,7 +45,7 @@ define(DECR,`eval($1-1)')
|
|||
#
|
||||
# include string macros
|
||||
#
|
||||
include(String.m4)
|
||||
include(string.m4)
|
||||
#
|
||||
# create some fortrash strings for an even uglier language
|
||||
#
|
||||
|
@ -47,14 +85,14 @@ define(abc,xxx)
|
|||
ifdef(`abc',defined,undefined)
|
||||
#
|
||||
# v7 m4 does this wrong. The right output is
|
||||
# this is A vEry lon sEntEnCE
|
||||
# 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)
|
||||
include(hanoi.m4)
|
||||
#
|
||||
# some reasonable set of disks
|
||||
#
|
||||
|
@ -62,7 +100,7 @@ hanoi(6)
|
|||
#
|
||||
# include ackermann's function
|
||||
#
|
||||
include(Ack.m4)
|
||||
include(ack.m4)
|
||||
#
|
||||
# something like (3,3) will blow away un*x m4.
|
||||
#
|
||||
|
@ -70,7 +108,7 @@ ack(2,3)
|
|||
#
|
||||
# include a square_root function for fixed nums
|
||||
#
|
||||
include(Sqroot.m4)
|
||||
include(sqroot.m4)
|
||||
#
|
||||
# some square roots.
|
||||
#
|
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");
|
||||
}
|
Loading…
Reference in a new issue