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
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
cleandepend:
$(MAKE) -C boot cleandepend
$(MAKE) -C commands cleandepend
+ $(MAKE) -C usr.bin cleandepend
$(MAKE) -C tools cleandepend
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 \
+++ /dev/null
-define(ack, `ifelse($1,0,incr($2),$2,0,`ack(DECR($1),1)',
-`ack(DECR($1), ack($1,DECR($2)))')')
+++ /dev/null
-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))')')
+++ /dev/null
-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
+++ /dev/null
-#
-# 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
+++ /dev/null
-# 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>
+++ /dev/null
-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
+++ /dev/null
-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))')')
+++ /dev/null
-
-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))')')
+++ /dev/null
-/*
- * 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;
- }
-}
+++ /dev/null
-/*
- * 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 */
-}
+++ /dev/null
-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 */
+++ /dev/null
-/*
- * 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);
-}
-
+++ /dev/null
-/*
- * 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;
- }
-}
+++ /dev/null
-/*
- * 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 ));
+++ /dev/null
-/*
- * 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
+++ /dev/null
-#define PATCHLEVEL 1
+++ /dev/null
-/*
- * 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;
-}
+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
lib/nbsd_libc src/lib/libc
lib/nbsd_libm src/lib/libm
nbsd_include src/include
+usr.bin/m4 src/usr.bin/m4
--- /dev/null
+# Makefile for usr.bin
+
+.include <bsd.own.mk>
+
+SUBDIR= m4
+
+.include <bsd.subdir.mk>
--- /dev/null
+# Require clang and NBSD_LIBC
+NBSD_LIBC:= yes
+CC:= clang
+COMPILER_TYPE:= gnu
+
+BINDIR?=/usr/bin
+
--- /dev/null
+# $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>
--- /dev/null
+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
+ . |
+ +-------+ |
+ | <----------+
+ +-------+
--- /dev/null
+# $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>
--- /dev/null
+# $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)))')')
--- /dev/null
+# $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))')')
--- /dev/null
+# $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
--- /dev/null
+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
--- /dev/null
+# $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))')')
--- /dev/null
+# $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))')')
+# $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'.
#
# include string macros
#
-include(String.m4)
+include(string.m4)
#
# create some fortrash strings for an even uglier language
#
define(abc,xxx)
ifdef(`abc',defined,undefined)
#
-# v7 m4 does this wrong. The right output is
-# this is A vEry lon sEntEnCE
+# v7 m4 does this wrong. The right output is
+# this is A vEry lon sEntEnCE
# see m4 documentation for translit.
#
translit(`this is a very long sentence', abcdefg, ABCDEF)
#
# include towers-of-hanoi
#
-include(Hanoi.m4)
+include(hanoi.m4)
#
# some reasonable set of disks
#
#
# include ackermann's function
#
-include(Ack.m4)
+include(ack.m4)
#
# something like (3,3) will blow away un*x m4.
#
#
# include a square_root function for fixed nums
#
-include(Sqroot.m4)
+include(sqroot.m4)
#
# some square roots.
#
#
[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
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
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
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
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
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
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
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.
--- /dev/null
+/* $OpenBSD: eval.c,v 1.66 2008/08/21 21:01:47 espie Exp $ */
+/* $NetBSD: eval.c,v 1.20 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.
+ */
+
+/*
+ * eval.c
+ * Facility: m4 macro processor
+ * by: oz
+ */
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: eval.c,v 1.20 2009/10/26 21:11:28 christos Exp $");
+
+#include <sys/types.h>
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <fcntl.h>
+#include "mdef.h"
+#include "stdd.h"
+#include "extern.h"
+#include "pathnames.h"
+
+static void dodefn(const char *);
+static void dopushdef(const char *, const char *);
+static void dodump(const char *[], int);
+static void dotrace(const char *[], int, int);
+static void doifelse(const char *[], int);
+static int doincl(const char *);
+static int dopaste(const char *);
+static void dochq(const char *[], int);
+static void dochc(const char *[], int);
+static void dom4wrap(const char *);
+static void dodiv(int);
+static void doundiv(const char *[], int);
+static void dosub(const char *[], int);
+static void map(char *, const char *, const char *, const char *);
+static const char *handledash(char *, char *, const char *);
+static void expand_builtin(const char *[], int, int);
+static void expand_macro(const char *[], int);
+static void dump_one_def(const char *, struct macro_definition *);
+
+unsigned long expansion_id;
+
+/*
+ * eval - eval all macros and builtins calls
+ * argc - number of elements in argv.
+ * argv - element vector :
+ * argv[0] = definition of a user
+ * macro or NULL if built-in.
+ * argv[1] = name of the macro or
+ * built-in.
+ * argv[2] = parameters to user-defined
+ * . macro or built-in.
+ * .
+ *
+ * A call in the form of macro-or-builtin() will result in:
+ * argv[0] = nullstr
+ * argv[1] = macro-or-builtin
+ * argv[2] = nullstr
+ *
+ * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin
+ */
+void
+eval(const char *argv[], int argc, int td, int is_traced)
+{
+ size_t mark = SIZE_MAX;
+
+ expansion_id++;
+ if (td & RECDEF)
+ m4errx(1, "expanding recursive definition for %s.", argv[1]);
+ if (is_traced)
+ mark = trace(argv, argc, infile+ilevel);
+ if (td == MACRTYPE)
+ expand_macro(argv, argc);
+ else
+ expand_builtin(argv, argc, td);
+ if (mark != SIZE_MAX)
+ finish_trace(mark);
+}
+
+/*
+ * expand_builtin - evaluate built-in macros.
+ */
+void
+expand_builtin(const char *argv[], int argc, int td)
+{
+ int c, n;
+ int ac;
+ static int sysval = 0;
+
+#ifdef DEBUG
+ printf("argc = %d\n", argc);
+ for (n = 0; n < argc; n++)
+ printf("argv[%d] = %s\n", n, argv[n]);
+ fflush(stdout);
+#endif
+
+ /*
+ * if argc == 3 and argv[2] is null, then we
+ * have macro-or-builtin() type call. We adjust
+ * argc to avoid further checking..
+ */
+ /* we keep the initial value for those built-ins that differentiate
+ * between builtin() and builtin.
+ */
+ ac = argc;
+
+ if (argc == 3 && !*(argv[2]) && !mimic_gnu)
+ argc--;
+
+ switch (td & TYPEMASK) {
+
+ 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 TRACEONTYPE:
+ dotrace(argv, argc, 1);
+ break;
+
+ case TRACEOFFTYPE:
+ dotrace(argv, argc, 0);
+ break;
+
+ case EXPRTYPE:
+ /*
+ * doexpr - evaluate arithmetic
+ * expression
+ */
+ {
+ int base = 10;
+ int maxdigits = 0;
+ const char *errstr;
+
+ if (argc > 3) {
+ base = strtonum(argv[3], 2, 36, &errstr);
+ if (errstr) {
+ m4errx(1, "expr: base %s invalid.", argv[3]);
+ }
+ }
+ if (argc > 4) {
+ maxdigits = strtonum(argv[4], 0, INT_MAX, &errstr);
+ if (errstr) {
+ m4errx(1, "expr: maxdigits %s invalid.", argv[4]);
+ }
+ }
+ if (argc > 2)
+ pbnumbase(expr(argv[2]), base, maxdigits);
+ 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_macro_definition(argv[2]) != NULL)
+ pbstr(argv[3]);
+ else if (argc > 4)
+ pbstr(argv[4]);
+ }
+ break;
+
+ case LENGTYPE:
+ /*
+ * dolen - find the length of the
+ * argument
+ */
+ 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;
+
+ case SYSCTYPE:
+ /*
+ * dosys - execute system command
+ */
+ if (argc > 2) {
+ fflush(stdout);
+ sysval = system(argv[2]);
+ }
+ break;
+
+ case SYSVTYPE:
+ /*
+ * dosysval - return value of the last
+ * system call.
+ *
+ */
+ pbnum(sysval);
+ break;
+
+ case ESYSCMDTYPE:
+ if (argc > 2)
+ doesyscmd(argv[2]);
+ break;
+ case INCLTYPE:
+ if (argc > 2)
+ if (!doincl(argv[2]))
+ err(1, "%s at line %lu: include(%s)",
+ CURRENT_NAME, CURRENT_LINE, argv[2]);
+ break;
+
+ case SINCTYPE:
+ if (argc > 2)
+ (void) doincl(argv[2]);
+ break;
+#ifdef EXTENDED
+ case PASTTYPE:
+ if (argc > 2)
+ if (!dopaste(argv[2]))
+ err(1, "%s at line %lu: paste(%s)",
+ CURRENT_NAME, CURRENT_LINE, argv[2]);
+ break;
+
+ case SPASTYPE:
+ if (argc > 2)
+ (void) dopaste(argv[2]);
+ break;
+ case FORMATTYPE:
+ doformat(argv, argc);
+ break;
+#endif
+ case CHNQTYPE:
+ dochq(argv, ac);
+ 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--) {
+ pbstr(rquote);
+ pbstr(argv[n]);
+ pbstr(lquote);
+ pushback(COMMA);
+ }
+ pbstr(rquote);
+ pbstr(argv[3]);
+ pbstr(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++)
+ macro_undefine(argv[n]);
+ break;
+
+ case POPDTYPE:
+ /*
+ * dopopdef - remove the topmost
+ * definitions of macro(s) or m4
+ * keyword(s).
+ */
+ if (argc > 2)
+ for (n = 2; n < argc; n++)
+ macro_popdef(argv[n]);
+ break;
+
+ case MKTMTYPE:
+ /*
+ * dotemp - create a temporary file
+ */
+ if (argc > 2) {
+ int fd;
+ char *temp;
+
+ temp = xstrdup(argv[2]);
+
+ fd = mkstemp(temp);
+ if (fd == -1)
+ err(1,
+ "%s at line %lu: couldn't make temp file %s",
+ CURRENT_NAME, CURRENT_LINE, argv[2]);
+ close(fd);
+ pbstr(temp);
+ free(temp);
+ }
+ 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;
+
+ temp = xalloc(strlen(argv[2])+1, NULL);
+ if (argc > 4)
+ map(temp, argv[2], argv[3], argv[4]);
+ else
+ map(temp, argv[2], argv[3], null);
+ pbstr(temp);
+ free(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
+ */
+ if (argc > 2)
+ dom4wrap(argv[2]);
+ break;
+
+ case EXITTYPE:
+ /*
+ * doexit - immediate exit from m4.
+ */
+ killdiv();
+ exit((argc > 2) ? atoi(argv[2]) : 0);
+ break;
+
+ case DEFNTYPE:
+ if (argc > 2)
+ for (n = 2; n < argc; n++)
+ dodefn(argv[n]);
+ break;
+
+ case INDIRTYPE: /* Indirect call */
+ if (argc > 2)
+ doindir(argv, argc);
+ break;
+
+ case BUILTINTYPE: /* Builtins only */
+ if (argc > 2)
+ dobuiltin(argv, argc);
+ break;
+
+ case PATSTYPE:
+ if (argc > 2)
+ dopatsubst(argv, argc);
+ break;
+ case REGEXPTYPE:
+ if (argc > 2)
+ doregexp(argv, argc);
+ break;
+ case LINETYPE:
+ doprintlineno(infile+ilevel);
+ break;
+ case FILENAMETYPE:
+ doprintfilename(infile+ilevel);
+ break;
+ case SELFTYPE:
+ pbstr(rquote);
+ pbstr(argv[1]);
+ pbstr(lquote);
+ break;
+ default:
+ m4errx(1, "eval: major botch.");
+ break;
+ }
+}
+
+/*
+ * expand_macro - user-defined macro expansion
+ */
+void
+expand_macro(const char *argv[], int argc)
+{
+ const char *t;
+ const char *p;
+ int n;
+ 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)
+ PUSHBACK(*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 '*':
+ if (argc > 2) {
+ for (n = argc - 1; n > 2; n--) {
+ pbstr(argv[n]);
+ pushback(COMMA);
+ }
+ pbstr(argv[2]);
+ }
+ break;
+ case '@':
+ if (argc > 2) {
+ for (n = argc - 1; n > 2; n--) {
+ pbstr(rquote);
+ pbstr(argv[n]);
+ pbstr(lquote);
+ pushback(COMMA);
+ }
+ pbstr(rquote);
+ pbstr(argv[2]);
+ pbstr(lquote);
+ }
+ break;
+ default:
+ PUSHBACK(*p);
+ PUSHBACK('$');
+ break;
+ }
+ p--;
+ }
+ p--;
+ }
+ if (p == t) /* do last character */
+ PUSHBACK(*p);
+}
+
+
+/*
+ * dodefine - install definition in the table
+ */
+void
+dodefine(const char *name, const char *defn)
+{
+ if (!*name && !mimic_gnu)
+ m4errx(1, "null definition.");
+ else
+ macro_define(name, defn);
+}
+
+/*
+ * dodefn - push back a quoted definition of
+ * the given name.
+ */
+static void
+dodefn(const char *name)
+{
+ struct macro_definition *p;
+
+ if ((p = lookup_macro_definition(name)) != NULL) {
+ if ((p->type & TYPEMASK) == MACRTYPE) {
+ pbstr(rquote);
+ pbstr(p->defn);
+ pbstr(lquote);
+ } else {
+ pbstr(p->defn);
+ pbstr(BUILTIN_MARKER);
+ }
+ }
+}
+
+/*
+ * 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.
+ */
+static void
+dopushdef(const char *name, const char *defn)
+{
+ if (!*name && !mimic_gnu)
+ m4errx(1, "null definition.");
+ else
+ macro_pushdef(name, defn);
+}
+
+/*
+ * dump_one_def - dump the specified definition.
+ */
+static void
+dump_one_def(const char *name, struct macro_definition *p)
+{
+ if (!traceout)
+ traceout = stderr;
+ if (mimic_gnu) {
+ if ((p->type & TYPEMASK) == MACRTYPE)
+ fprintf(traceout, "%s:\t%s\n", name, p->defn);
+ else {
+ fprintf(traceout, "%s:\t<%s>\n", name, p->defn);
+ }
+ } else
+ fprintf(traceout, "`%s'\t`%s'\n", name, p->defn);
+}
+
+/*
+ * dodumpdef - dump the specified definitions in the hash
+ * table to stderr. If nothing is specified, the entire
+ * hash table is dumped.
+ */
+static void
+dodump(const char *argv[], int argc)
+{
+ int n;
+ struct macro_definition *p;
+
+ if (argc > 2) {
+ for (n = 2; n < argc; n++)
+ if ((p = lookup_macro_definition(argv[n])) != NULL)
+ dump_one_def(argv[n], p);
+ } else
+ macro_for_all(dump_one_def);
+}
+
+/*
+ * dotrace - mark some macros as traced/untraced depending upon on.
+ */
+static void
+dotrace(const char *argv[], int argc, int on)
+{
+ int n;
+
+ if (argc > 2) {
+ for (n = 2; n < argc; n++)
+ mark_traced(argv[n], on);
+ } else
+ mark_traced(NULL, on);
+}
+
+/*
+ * doifelse - select one of two alternatives - loop.
+ */
+static void
+doifelse(const char *argv[], int argc)
+{
+ cycle {
+ if (STREQ(argv[2], argv[3]))
+ 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.
+ */
+static int
+doincl(const char *ifile)
+{
+ if (ilevel + 1 == MAXINP)
+ m4errx(1, "too many include files.");
+ if (fopen_trypath(infile+ilevel+1, ifile) != NULL) {
+ ilevel++;
+ bbase[ilevel] = bufbase = bp;
+ return (1);
+ } else
+ return (0);
+}
+
+#ifdef EXTENDED
+/*
+ * dopaste - include a given file without any
+ * macro processing.
+ */
+static int
+dopaste(const char *pfile)
+{
+ FILE *pf;
+ int c;
+
+ if ((pf = fopen(pfile, "r")) != NULL) {
+ if (synch_lines)
+ fprintf(active, "#line 1 \"%s\"\n", pfile);
+ while ((c = getc(pf)) != EOF)
+ putc(c, active);
+ (void) fclose(pf);
+ emit_synchline();
+ return (1);
+ } else
+ return (0);
+}
+#endif
+
+/*
+ * dochq - change quote characters
+ */
+static void
+dochq(const char *argv[], int ac)
+{
+ if (ac == 2) {
+ lquote[0] = LQUOTE; lquote[1] = EOS;
+ rquote[0] = RQUOTE; rquote[1] = EOS;
+ } else {
+ strlcpy(lquote, argv[2], sizeof(lquote));
+ if (ac > 3) {
+ strlcpy(rquote, argv[3], sizeof(rquote));
+ } else {
+ rquote[0] = ECOMMT; rquote[1] = EOS;
+ }
+ }
+}
+
+/*
+ * dochc - change comment characters
+ */
+static void
+dochc(const char *argv[], int argc)
+{
+/* XXX Note that there is no difference between no argument and a single
+ * empty argument.
+ */
+ if (argc == 2) {
+ scommt[0] = EOS;
+ ecommt[0] = EOS;
+ } else {
+ strlcpy(scommt, argv[2], sizeof(scommt));
+ if (argc == 3) {
+ ecommt[0] = ECOMMT; ecommt[1] = EOS;
+ } else {
+ strlcpy(ecommt, argv[3], sizeof(ecommt));
+ }
+ }
+}
+
+/*
+ * dom4wrap - expand text at EOF
+ */
+static void
+dom4wrap(const char *text)
+{
+ if (wrapindex >= maxwraps) {
+ if (maxwraps == 0)
+ maxwraps = 16;
+ else
+ maxwraps *= 2;
+ m4wraps = xrealloc(m4wraps, maxwraps * sizeof(*m4wraps),
+ "too many m4wraps");
+ }
+ m4wraps[wrapindex++] = xstrdup(text);
+}
+
+/*
+ * dodivert - divert the output to a temporary file
+ */
+static void
+dodiv(int n)
+{
+ int fd;
+
+ oindex = n;
+ if (n >= maxout) {
+ if (mimic_gnu)
+ resizedivs(n + 10);
+ else
+ n = 0; /* bitbucket */
+ }
+
+ if (n < 0)
+ n = 0; /* bitbucket */
+ if (outfile[n] == NULL) {
+ char fname[] = _PATH_DIVNAME;
+
+ if ((fd = mkstemp(fname)) < 0 ||
+ (outfile[n] = fdopen(fd, "w+")) == NULL)
+ err(1, "%s: cannot divert", fname);
+ if (unlink(fname) == -1)
+ err(1, "%s: cannot unlink", fname);
+ }
+ active = outfile[n];
+}
+
+/*
+ * doundivert - undivert a specified output, or all
+ * other outputs, in numerical order.
+ */
+static void
+doundiv(const char *argv[], int argc)
+{
+ int ind;
+ int n;
+
+ if (argc > 2) {
+ for (ind = 2; ind < argc; ind++) {
+ const char *errstr;
+ n = strtonum(argv[ind], 1, INT_MAX, &errstr);
+ if (errstr) {
+ if (errno == EINVAL && mimic_gnu)
+ getdivfile(argv[ind]);
+ } else {
+ if (n < maxout && outfile[n] != NULL)
+ getdiv(n);
+ }
+ }
+ }
+ else
+ for (n = 1; n < maxout; n++)
+ if (outfile[n] != NULL)
+ getdiv(n);
+}
+
+/*
+ * dosub - select substring
+ */
+static void
+dosub(const char *argv[], int argc)
+{
+ const char *ap, *fc, *k;
+ int nc;
+
+ ap = argv[2]; /* target string */
+#ifdef EXPR
+ fc = ap + expr(argv[3]); /* first char */
+#else
+ fc = ap + atoi(argv[3]); /* first char */
+#endif
+ nc = strlen(fc);
+ if (argc >= 5)
+#ifdef EXPR
+ nc = min(nc, expr(argv[4]));
+#else
+ nc = min(nc, atoi(argv[4]));
+#endif
+ if (fc >= ap && fc < ap + strlen(ap))
+ for (k = fc + nc - 1; k >= fc; k--)
+ pushback(*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.
+ */
+static void
+map(char *dest, const char *src, const char *from, const char *to)
+{
+ const char *tmp;
+ unsigned char sch, dch;
+ static char frombis[257];
+ static char tobis[257];
+ static unsigned char mapvec[256] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+ 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, 128,
+ 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
+ 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
+ 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
+ 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
+ 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
+ 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
+ 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
+ 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
+ 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
+ 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
+ };
+
+ if (*src) {
+ if (mimic_gnu) {
+ /*
+ * expand character ranges on the fly
+ */
+ from = handledash(frombis, frombis + 256, from);
+ to = handledash(tobis, tobis + 256, to);
+ }
+ tmp = from;
+ /*
+ * create a mapping between "from" and
+ * "to"
+ */
+ while (*from)
+ mapvec[(unsigned char)(*from++)] = (*to) ?
+ (unsigned char)(*to++) : 0;
+
+ while (*src) {
+ sch = (unsigned char)(*src++);
+ dch = mapvec[sch];
+ while (dch != sch) {
+ sch = dch;
+ dch = mapvec[sch];
+ }
+ if ((*dest = (char)dch))
+ dest++;
+ }
+ /*
+ * restore all the changed characters
+ */
+ while (*tmp) {
+ mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp);
+ tmp++;
+ }
+ }
+ *dest = '\0';
+}
+
+
+/*
+ * handledash:
+ * use buffer to copy the src string, expanding character ranges
+ * on the way.
+ */
+static const char *
+handledash(char *buffer, char *end, const char *src)
+{
+ char *p;
+
+ p = buffer;
+ while(*src) {
+ if (src[1] == '-' && src[2]) {
+ unsigned char i;
+ if ((unsigned char)src[0] <= (unsigned char)src[2]) {
+ for (i = (unsigned char)src[0];
+ i <= (unsigned char)src[2]; i++) {
+ *p++ = i;
+ if (p == end) {
+ *p = '\0';
+ return buffer;
+ }
+ }
+ } else {
+ for (i = (unsigned char)src[0];
+ i >= (unsigned char)src[2]; i--) {
+ *p++ = i;
+ if (p == end) {
+ *p = '\0';
+ return buffer;
+ }
+ }
+ }
+ src += 3;
+ } else
+ *p++ = *src++;
+ if (p == end)
+ break;
+ }
+ *p = '\0';
+ return buffer;
+}
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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 **);
--- /dev/null
+/* $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);
+}
--- /dev/null
+#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
+
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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
+}
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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;
+}
--- /dev/null
+.\" $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.
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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
--- /dev/null
+.\" $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.
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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);
+}
--- /dev/null
+/* $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);
+}
--- /dev/null
+/* $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);
+}
+
--- /dev/null
+/* $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;
+}
+
--- /dev/null
+.\" $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 .
--- /dev/null
+/* $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);
+}
--- /dev/null
+/* $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)
--- /dev/null
+/* $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);
+}
--- /dev/null
+%{
+/* $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
+ ;
+%%
+
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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
--- /dev/null
+%{
+/* $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;
+}
+
--- /dev/null
+/* $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");
+}