Subject: m4 can not handle new sendmail config files (#185) Index: usr.bin/m4 2.11BSD Description: The m4 program currently present in 2.11BSD can not handle the new sendmail configuration macro files. Repeat-By: Port V8 sendmail to 2.11BSD (yes it has been done, no I didn't do it but I am beginning to test it and will be releasing it 'real soon now'). Attempt to generate a configuration file using the existing m4. Note the lack of success. A likely symptom is the process just sits there forever waiting for input. Fix: This is a complete replacement m4 kit (from the redistributable sources archives). The port was actually quite simple, remove a dead/unused function or two, remove a bit of fluff (stdlib.h), and lastly fix up the "sizeof long == sizeof int" assumptions. The new m4 program is a bit bigger than the old but not overly so. An update to the existing man page was created rather than porting the man page that originally came with the m4 sources. It turns out that the newfangled 'mandoc' macro package is way too much for nroff (poor old nroff trying to inhale a quarter megabyte of macros/strings instead of 94kb - he tried but choked eventually) and I didn't feel like fixing that problem too. It was easier to just add a few paragraphs to the existing man page. Save the text below into a temporary file (/tmp/foo). Then: 1) cd /tmp 2) sh foo 3) patch -p0 < m4.man.patch 4) mv /usr/src/usr.bin/m4 /usr/src/usr.bin/m4.old (or optionally you can simply "rm -r /usr/src/usr.bin/m4") 5) sh m4.shar 6) rm foo m4.man.patch m4.shar 7) cd /usr/src/usr.bin/m4 8) make 9) make install 10) cd /usr/src/man/man1 11) /usr/man/manroff m4.1 > /usr/man/cat1/m4.0 -----cut here #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # /tmp/m4.man.patch # /tmp/m4.shar # This archive created: Thu Apr 14 20:27:39 1994 export PATH; PATH=/bin:/usr/bin:$PATH if test -f '/tmp/m4.man.patch' then echo shar: "will not over-write existing file '/tmp/m4.man.patch'" else sed 's/^Y//' << \SHAR_EOF > '/tmp/m4.man.patch' Y*** /usr/src/man/man1/m4.1.old Sun Dec 14 15:06:21 1986 Y--- /usr/src/man/man1/m4.1 Thu Apr 14 20:15:14 1994 Y*************** Y*** 1,19 **** Y! .\" @(#)m4.1 6.1 (Berkeley) 4/29/85 Y .\" Y! .TH M4 1 "April 29, 1985" Y! .AT 3 Y .SH NAME Y m4 \- macro processor Y .SH SYNOPSIS Y! .B m4 Y! [ files ] Y .SH DESCRIPTION Y! .I M4 Y! is a macro processor intended as a front end for Ratfor, C, and other languages. Y! Each of the argument files is processed in order; Y! if there are no arguments, or if an argument is `\-', Y! the standard input is read. Y! The processed text is written on the standard output. Y .PP Y Macro calls have the form Y .PP Y--- 1,17 ---- Y! .\" @(#)m4.1 1.0 (2.11BSD GTE) 4/14/94 Y .\" Y! .TH m4 1 "April 14, 1994" Y! .UC 2 Y .SH NAME Y m4 \- macro processor Y .SH SYNOPSIS Y! m4 [ -D\fBname\fP[\fB=value\fP]] [-U\fBname\fP] [files ...] Y .SH DESCRIPTION Y! .I m4 Y! is a macro processor intended as a front end for any language (e.g., C, Y! ratfor, fortran, lex, and yacc). \fIm4\fP reads from the standard input Y! and writes the processed text to the standard output. Y! Each of the optional argument files is processed in order. Y .PP Y Macro calls have the form Y .PP Y*************** Y*** 37,44 **** Y of a nested call are as effective as those in the original input text. Y After argument collection, the value of the macro is pushed back onto the Y input stream and rescanned. Y .PP Y! .I M4 Y makes available the following built-in macros. Y They may be redefined, but once this is done the original meaning is lost. Y Their values are null unless otherwise stated. Y--- 35,48 ---- Y of a nested call are as effective as those in the original input text. Y After argument collection, the value of the macro is pushed back onto the Y input stream and rescanned. Y+ .TP 10 Y+ -D\fBname\fP[\fB=value\fP] Y+ Define the symbol \fBname\fP to have some value (or NULL). Y+ .TP 10 Y+ -U\fBname\fP Y+ Undefine the symbol \fBname\fP. Y .PP Y! .I m4 Y makes available the following built-in macros. Y They may be redefined, but once this is done the original meaning is lost. Y Their values are null unless otherwise stated. Y*************** Y*** 59,76 **** Y .B ifdef Y If the first argument is defined, the value is the second argument, Y otherwise the third. If there is no third argument, the value is null. Y- The word Y- .I unix Y- is predefined on UNIX versions of Y- .IR m4 . Y .TP Y .B changequote Y Change quote characters to the first and second arguments. Y .I Changequote Y without arguments restores the original values (i.e., \`\|\'). Y .TP Y .B divert Y! .I M4 Y maintains 10 output streams, numbered 0-9. Y The final output is the concatenation of the streams in numerical order; Y initially stream 0 is the current stream. The Y--- 63,86 ---- Y .B ifdef Y If the first argument is defined, the value is the second argument, Y otherwise the third. If there is no third argument, the value is null. Y .TP Y+ .B changecom Y+ Change the start and end comment sequences. The default is the pound Y+ sign '#' and the newline character. With no arguments comments Y+ are turned off. The maximum legnth for a comment marker is five Y+ characters. Y+ .TP Y .B changequote Y Change quote characters to the first and second arguments. Y .I Changequote Y without arguments restores the original values (i.e., \`\|\'). Y .TP Y+ .B decr Y+ Decrements the argument by 1. The argument must be a valid numeric Y+ string. Y+ .TP Y .B divert Y! .I m4 Y maintains 10 output streams, numbered 0-9. Y The final output is the concatenation of the streams in numerical order; Y initially stream 0 is the current stream. The Y*************** Y*** 84,89 **** Y--- 94,103 ---- Y Text may be undiverted into another diversion. Y Undiverting discards the diverted text. Y .TP Y+ .B defn Y+ Returns the quoted definition for each argument. This can be used to Y+ rename macro definitions (even for builtin macros). Y+ .TP Y .B divnum Y returns the value of the current output stream. Y .TP Y*************** Y*** 90,95 **** Y--- 104,112 ---- Y .B dnl Y reads and discards characters up to and including the next newline. Y .TP Y+ .B expr Y+ This is an alias for eval. Y+ .TP Y .B ifelse Y has three or more arguments. Y If the first argument is the same string as the second, Y*************** Y*** 111,116 **** Y--- 128,142 ---- Y .B len Y returns the number of characters in its argument. Y .TP Y+ .B m4exit Y+ Immediately exits with the return value specified by the first Y+ argument, 0 if none. Y+ .TP Y+ .B m4wrap Y+ Allows you to define what happens at the final EOF, usually for cleanup Y+ purposes. (e.g., m4wrap("cleanup(tempfile)") causes the macro cleanup Y+ to be invoked after all processing is done.) Y+ .TP Y .B index Y returns the position in its first argument where the second argument Y begins (zero origin), or \-1 if the second argument does not occur. Y*************** Y*** 142,147 **** Y--- 168,196 ---- Y .B maketemp Y fills in a string of XXXXX in its argument with the current process id. Y .TP Y+ .B paste Y+ Includes the contents of the file specified by the first argument Y+ without any macro processing. Aborts with an error message if the Y+ file cannot be included. Y+ .TP Y+ .B popdef Y+ Restores the pushdef'd definition for each argument. Y+ .TP Y+ .B pushdef Y+ Takes the same arguments as define, but it saves the definition on a Y+ stack for later retrieval by popdef. Y+ .TP Y+ .B shift Y+ Returns all but the first argument, the remaining arguments are quoted Y+ and pushed back with commas in between. The quoting nullifies the effect Y+ of the extra scan that will subsequently be performed. Y+ .TP Y+ .B spaste Y+ Similar to paste, except it ignores any errors. Y+ .TP Y+ .B syscal Y+ Returns the return value from the last syscmd. Y+ .TP Y .B errprint Y prints its argument on the diagnostic output file. Y .TP Y*************** Y*** 148,154 **** Y .B dumpdef Y prints current names and definitions, Y for the named items, or for all if no arguments are given. Y .dt Y .SH "SEE ALSO" Y B. W. Kernighan and D. M. Ritchie, Y! .I The M4 Macro Processor Y--- 197,210 ---- Y .B dumpdef Y prints current names and definitions, Y for the named items, or for all if no arguments are given. Y+ .TP Y+ .B unix Y+ A pre-defined macro for testing the OS platform. Y .dt Y .SH "SEE ALSO" Y B. W. Kernighan and D. M. Ritchie, Y! .I The m4 Macro Processor Y! .SH HISTORY Y! An m4 command appeared in Version 6 AT&T UNIX. Y! .SH AUTHOR Y! Ozan Yigit SHAR_EOF fi if test -f '/tmp/m4.shar' then echo shar: "will not over-write existing file '/tmp/m4.shar'" else sed 's/^Y//' << \SHAR_EOF > '/tmp/m4.shar' Y#! /bin/sh Y# This is a shell archive, meaning: Y# 1. Remove everything above the #! /bin/sh line. Y# 2. Save the resulting text in a file. Y# 3. Execute the file with /bin/sh (not csh) to create: Y# /usr/src/usr.bin/m4 Y# This archive created: Thu Apr 14 20:23:41 1994 Yexport PATH; PATH=/bin:/usr/bin:$PATH Yif test ! -d '/usr/src/usr.bin/m4' Ythen Y mkdir '/usr/src/usr.bin/m4' Yfi Ycd '/usr/src/usr.bin/m4' Yif test ! -d 'TEST' Ythen Y mkdir 'TEST' Yfi Ycd 'TEST' Yif test -f 'test.m4' Ythen Y echo shar: "will not over-write existing file 'test.m4'" Yelse Ysed 's/^X//' << \SHAR_EOF > 'test.m4' YX# YX# Copyright (c) 1989, 1993 YX# The Regents of the University of California. All rights reserved. YX# YX# This code is derived from software contributed to Berkeley by YX# Ozan Yigit. YX# YX# Redistribution and use in source and binary forms, with or without YX# modification, are permitted provided that the following conditions YX# are met: YX# 1. Redistributions of source code must retain the above copyright YX# notice, this list of conditions and the following disclaimer. YX# 2. Redistributions in binary form must reproduce the above copyright YX# notice, this list of conditions and the following disclaimer in the YX# documentation and/or other materials provided with the distribution. YX# 3. All advertising materials mentioning features or use of this software YX# must display the following acknowledgement: YX# This product includes software developed by the University of YX# California, Berkeley and its contributors. YX# 4. Neither the name of the University nor the names of its contributors YX# may be used to endorse or promote products derived from this software YX# without specific prior written permission. YX# YX# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND YX# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE YX# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE YX# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE YX# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL YX# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS YX# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) YX# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT YX# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY YX# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF YX# SUCH DAMAGE. YX# YX# @(#)test.m4 8.1 (Berkeley) 6/6/93 YX# YX YX# test file for mp (not comprehensive) YX# YX# v7 m4 does not have `decr'. YX# YXdefine(DECR,`eval($1-1)') YX# YX# include string macros YX# YXinclude(string.m4) YX# YX# create some fortrash strings for an even uglier language YX# YXstring(TEXT, "text") YXstring(DATA, "data") YXstring(BEGIN, "begin") YXstring(END, "end") YXstring(IF, "if") YXstring(THEN, "then") YXstring(ELSE, "else") YXstring(CASE, "case") YXstring(REPEAT, "repeat") YXstring(WHILE, "while") YXstring(DEFAULT, "default") YXstring(UNTIL, "until") YXstring(FUNCTION, "function") YXstring(PROCEDURE, "procedure") YXstring(EXTERNAL, "external") YXstring(FORWARD, "forward") YXstring(TYPE, "type") YXstring(VAR, "var") YXstring(CONST, "const") YXstring(PROGRAM, "program") YXstring(INPUT, "input") YXstring(OUTPUT, "output") YX# YXdivert(2) YXdiversion #1 YXdivert(3) YXdiversion #2 YXdivert(4) YXdiversion #3 YXdivert(5) YXdiversion #4 YXdivert(0) YXdefine(abc,xxx) YXifdef(`abc',defined,undefined) YX# YX# v7 m4 does this wrong. The right output is YX# this is A vEry lon sEntEnCE YX# see m4 documentation for translit. YX# YXtranslit(`this is a very long sentence', abcdefg, ABCDEF) YX# YX# include towers-of-hanoi YX# YXinclude(hanoi.m4) YX# YX# some reasonable set of disks YX# YXhanoi(6) YX# YX# include ackermann's function YX# YXinclude(ack.m4) YX# YX# something like (3,3) will blow away un*x m4. YX# YXack(2,3) YX# YX# include a square_root function for fixed nums YX# YXinclude(sqroot.m4) YX# YX# some square roots. YX# YXsquare_root(15) YXsquare_root(100) YXsquare_root(-4) YXsquare_root(21372) YX# YX# some textual material for enjoyment. YX# YX[taken from the 'Clemson University Computer Newsletter', YX September 1981, pp. 6-7] YX YXI am a wizard in the magical Kingdom of Transformation and I YXslay dragons for a living. Actually, I am a systems programmer. YXOne of the problems with systems programming is explaining to YXnon-computer enthusiasts what that is. All of the terms I use to YXdescribe my job are totally meaningless to them. Usually my response YXto questions about my work is to say as little as possible. For YXinstance, if someone asks what happened at work this week, I say YX"Nothing much" and then I change the subject. YX YXWith the assistance of my brother, a mechanical engineer, I have devised YXan analogy that everyone can understand. The analogy describes the YX"Kingdom of Transformation" where travelers wander and are magically YXtransformed. This kingdom is the computer and the travelers are information. YXThe purpose of the computer is to change information to a more meaningful YXforma. The law of conservation applies here: The computer never creates YXand never intentionally destroys data. With no further ado, let us travel YXto the Kingdom of Transformation: YX YXIn a land far, far away, there is a magical kingdom called the Kingdom of YXTransformation. A king rules over this land and employs a Council of YXWizardry. The main purpose of this kingdom is to provide a way for YXneighboring kingdoms to transform citizens into more useful citizens. This YXis done by allowing the citizens to enter the kingdom at one of its ports YXand to travel any of the many routes in the kingdom. They are magically YXtransformed along the way. The income of the Kingdom of Transformation YXcomes from the many toll roads within its boundaries. YX YXThe Kingdom of Transformation was created when several kingdoms got YXtogether and discovered a mutual need for new talents and abilities for YXcitizens. They employed CTK, Inc. (Creators of Transformation, Inc.) to YXcreate this kingdom. CTK designed the country, its transportation routes, YXand its laws of transformation, and created the major highway system. YX YXHazards YX======= YX YXBecause magic is not truly controllable, CTK invariably, but unknowingly, YXcreates dragons. Dragons are huge fire-breathing beasts which sometimes YXinjure or kill travelers. Fortunately, they do not travel, but always YXremain near their den. YX YXOther hazards also exist which are potentially harmful. As the roads YXbecome older and more weatherbeaten, pot-holes will develop, trees will YXfall on travelers, etc. CTK maintenance men are called to fix these YXproblems. YX YXWizards YX======= YX YXThe wizards play a major role in creating and maintaining the kingdom but YXget little credit for their work because it is performed secretly. The YXwizards do not wan the workers or travelers to learn their incantations YXbecause many laws would be broken and chaos would result. YX YXCTK's grand design is always general enough to be applicable in many YXdifferent situations. As a result, it is often difficult to use. The YXfirst duty of the wizards is to tailor the transformation laws so as to be YXmore beneficial and easier to use in their particular environment. YX YXAfter creation of the kingdom, a major duty of the wizards is to search for YXand kill dragons. If travelers do not return on time or if they return YXinjured, the ruler of the country contacts the wizards. If the wizards YXdetermine that the injury or death occurred due to the traveler's YXnegligence, they provide the traveler's country with additional warnings. YXIf not, they must determine if the cause was a road hazard or a dragon. If YXthe suspect a road hazard, they call in a CTK maintenance man to locate the YXhazard and to eliminate it, as in repairing the pothole in the road. If YXthey think that cause was a dragon, then they must find and slay it. YX YXThe most difficult part of eliminating a dragon is finding it. Sometimes YXthe wizard magically knows where the dragon's lair it, but often the wizard YXmust send another traveler along the same route and watch to see where he YXdisappears. This sounds like a failsafe method for finding dragons (and a YXsuicide mission for thr traveler) but the second traveler does not always YXdisappear. Some dragons eat any traveler who comes too close; others are YXvery picky. YX YXThe wizards may call in CTK who designed the highway system and YXtransformation laws to help devise a way to locate the dragon. CTK also YXhelps provide the right spell or incantation to slay the dragon. (There is YXno general spell to slay dragons; each dragon must be eliminated with a YXdifferent spell.) YX YXBecause neither CTK nor wizards are perfect, spells to not always work YXcorrectly. At best, nothing happens when the wrong spell is uttered. At YXworst, the dragon becomes a much larger dragon or multiplies into several YXsmaller ones. In either case, new spells must be found. YX YXIf all existing dragons are quiet (i.e. have eaten sufficiently), wizards YXhave time to do other things. They hide in castles and practice spells and YXincatations. They also devise shortcuts for travelers and new laws of YXtransformation. YX YXChanges in the Kingdom YX====================== YX YXAs new transformation kingdoms are created and old ones are maintained, YXCTK, Inc. is constantly learning new things. It learns ways to avoid YXcreating some of the dragons that they have previously created. It also YXdiscovers new and better laws of transformation. As a result, CTK will YXperiodically create a new grand design which is far better than the old. YXThe wizards determine when is a good time to implement this new design. YXThis is when the tourist season is slow or when no important travelers YX(VIPs) are to arrive. The kingdom must be closed for the actual YXimplementation and is leter reopened as a new and better place to go. YX YXA final question you might ask is what happens when the number of tourists YXbecomes too great for the kingdom to handle in a reasonable period of time YX(i.e., the tourist lines at the ports are too long). The Kingdom of YXTransformation has three options: (1) shorten the paths that a tourist must YXtravel, or (2) convince CTK to develop a faster breed of horses so that the YXtravelers can finish sooner, or (3) annex more territories so that the YXkingdom can handle more travelers. YX YXThus ends the story of the Kingdom of Transformation. I hope this has YXexplained my job to you: I slay dragons for a living. YX YX# YX#should do an automatic undivert.. YX# YSHAR_EOF Ychmod 444 'test.m4' Yfi Yif test -f 'string.m4' Ythen Y echo shar: "will not over-write existing file 'string.m4'" Yelse Ysed 's/^X//' << \SHAR_EOF > 'string.m4' YX# YX# Copyright (c) 1989, 1993 YX# The Regents of the University of California. All rights reserved. YX# YX# This code is derived from software contributed to Berkeley by YX# Ozan Yigit. YX# YX# Redistribution and use in source and binary forms, with or without YX# modification, are permitted provided that the following conditions YX# are met: YX# 1. Redistributions of source code must retain the above copyright YX# notice, this list of conditions and the following disclaimer. YX# 2. Redistributions in binary form must reproduce the above copyright YX# notice, this list of conditions and the following disclaimer in the YX# documentation and/or other materials provided with the distribution. YX# 3. All advertising materials mentioning features or use of this software YX# must display the following acknowledgement: YX# This product includes software developed by the University of YX# California, Berkeley and its contributors. YX# 4. Neither the name of the University nor the names of its contributors YX# may be used to endorse or promote products derived from this software YX# without specific prior written permission. YX# YX# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND YX# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE YX# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE YX# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE YX# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL YX# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS YX# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) YX# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT YX# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY YX# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF YX# SUCH DAMAGE. YX# YX# @(#)string.m4 8.1 (Berkeley) 6/6/93 YX# YX YXdefine(string,`integer $1(len(substr($2,1))) YXstr($1,substr($2,1),0) YXdata $1(len(substr($2,1)))/EOS/ YX') YX YXdefine(str,`ifelse($2,",,data $1(incr($3))/`LET'substr($2,0,1)/ YX`str($1,substr($2,1),incr($3))')') YSHAR_EOF Ychmod 444 'string.m4' Yfi Yif test -f 'sqroot.m4' Ythen Y echo shar: "will not over-write existing file 'sqroot.m4'" Yelse Ysed 's/^X//' << \SHAR_EOF > 'sqroot.m4' YX# YX# Copyright (c) 1989, 1993 YX# The Regents of the University of California. All rights reserved. YX# YX# This code is derived from software contributed to Berkeley by YX# Ozan Yigit. YX# YX# Redistribution and use in source and binary forms, with or without YX# modification, are permitted provided that the following conditions YX# are met: YX# 1. Redistributions of source code must retain the above copyright YX# notice, this list of conditions and the following disclaimer. YX# 2. Redistributions in binary form must reproduce the above copyright YX# notice, this list of conditions and the following disclaimer in the YX# documentation and/or other materials provided with the distribution. YX# 3. All advertising materials mentioning features or use of this software YX# must display the following acknowledgement: YX# This product includes software developed by the University of YX# California, Berkeley and its contributors. YX# 4. Neither the name of the University nor the names of its contributors YX# may be used to endorse or promote products derived from this software YX# without specific prior written permission. YX# YX# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND YX# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE YX# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE YX# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE YX# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL YX# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS YX# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) YX# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT YX# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY YX# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF YX# SUCH DAMAGE. YX# YX# @(#)sqroot.m4 8.1 (Berkeley) 6/6/93 YX# YX YXdefine(square_root, YX `ifelse(eval($1<0),1,negative-square-root, YX `square_root_aux($1, 1, eval(($1+1)/2))')') YXdefine(square_root_aux, YX `ifelse($3, $2, $3, YX $3, eval($1/$2), $3, YX `square_root_aux($1, $3, eval(($3+($1/$3))/2))')') YSHAR_EOF Ychmod 444 'sqroot.m4' Yfi Yif test -f 'hash.m4' Ythen Y echo shar: "will not over-write existing file 'hash.m4'" Yelse Ysed 's/^X//' << \SHAR_EOF > 'hash.m4' YX# YX# Copyright (c) 1989, 1993 YX# The Regents of the University of California. All rights reserved. YX# YX# This code is derived from software contributed to Berkeley by YX# Ozan Yigit. YX# YX# Redistribution and use in source and binary forms, with or without YX# modification, are permitted provided that the following conditions YX# are met: YX# 1. Redistributions of source code must retain the above copyright YX# notice, this list of conditions and the following disclaimer. YX# 2. Redistributions in binary form must reproduce the above copyright YX# notice, this list of conditions and the following disclaimer in the YX# documentation and/or other materials provided with the distribution. YX# 3. All advertising materials mentioning features or use of this software YX# must display the following acknowledgement: YX# This product includes software developed by the University of YX# California, Berkeley and its contributors. YX# 4. Neither the name of the University nor the names of its contributors YX# may be used to endorse or promote products derived from this software YX# without specific prior written permission. YX# YX# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND YX# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE YX# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE YX# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE YX# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL YX# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS YX# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) YX# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT YX# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY YX# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF YX# SUCH DAMAGE. YX# YX# @(#)hash.m4 8.1 (Berkeley) 6/6/93 YX# YX YXdnl This probably will not run on any m4 that cannot YXdnl handle char constants in eval. YXdnl YXchangequote(<,>) define(HASHVAL,99) dnl YXdefine(hash,) dnl YXdefine(str, YX ,1),)>) YX >) dnl YXdefine(KEYWORD,<$1,hash($1),>) dnl YXdefine(TSTART, YX) dnl YXdefine(TEND,< "",0 YX};>) dnl YSHAR_EOF Ychmod 444 'hash.m4' Yfi Yif test -f 'hanoi.m4' Ythen Y echo shar: "will not over-write existing file 'hanoi.m4'" Yelse Ysed 's/^X//' << \SHAR_EOF > 'hanoi.m4' YX# YX# Copyright (c) 1989, 1993 YX# The Regents of the University of California. All rights reserved. YX# YX# This code is derived from software contributed to Berkeley by YX# Ozan Yigit. YX# YX# Redistribution and use in source and binary forms, with or without YX# modification, are permitted provided that the following conditions YX# are met: YX# 1. Redistributions of source code must retain the above copyright YX# notice, this list of conditions and the following disclaimer. YX# 2. Redistributions in binary form must reproduce the above copyright YX# notice, this list of conditions and the following disclaimer in the YX# documentation and/or other materials provided with the distribution. YX# 3. All advertising materials mentioning features or use of this software YX# must display the following acknowledgement: YX# This product includes software developed by the University of YX# California, Berkeley and its contributors. YX# 4. Neither the name of the University nor the names of its contributors YX# may be used to endorse or promote products derived from this software YX# without specific prior written permission. YX# YX# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND YX# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE YX# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE YX# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE YX# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL YX# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS YX# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) YX# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT YX# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY YX# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF YX# SUCH DAMAGE. YX# YX# @(#)hanoi.m4 8.1 (Berkeley) 6/6/93 YX# YX YXdefine(hanoi, `trans(A, B, C, $1)') YX YXdefine(moved,`move disk from $1 to $2 YX') YX YXdefine(trans, `ifelse($4,1,`moved($1,$2)', YX `trans($1,$3,$2,DECR($4))moved($1,$2)trans($3,$2,$1,DECR($4))')') YSHAR_EOF Ychmod 444 'hanoi.m4' Yfi Yif test -f 'ack.m4' Ythen Y echo shar: "will not over-write existing file 'ack.m4'" Yelse Ysed 's/^X//' << \SHAR_EOF > 'ack.m4' YX# YX# Copyright (c) 1989, 1993 YX# The Regents of the University of California. All rights reserved. YX# YX# This code is derived from software contributed to Berkeley by YX# Ozan Yigit. YX# YX# Redistribution and use in source and binary forms, with or without YX# modification, are permitted provided that the following conditions YX# are met: YX# 1. Redistributions of source code must retain the above copyright YX# notice, this list of conditions and the following disclaimer. YX# 2. Redistributions in binary form must reproduce the above copyright YX# notice, this list of conditions and the following disclaimer in the YX# documentation and/or other materials provided with the distribution. YX# 3. All advertising materials mentioning features or use of this software YX# must display the following acknowledgement: YX# This product includes software developed by the University of YX# California, Berkeley and its contributors. YX# 4. Neither the name of the University nor the names of its contributors YX# may be used to endorse or promote products derived from this software YX# without specific prior written permission. YX# YX# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND YX# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE YX# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE YX# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE YX# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL YX# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS YX# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) YX# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT YX# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY YX# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF YX# SUCH DAMAGE. YX# YX# @(#)ack.m4 8.1 (Berkeley) 6/6/93 YX# YX YXdefine(ack, `ifelse($1,0,incr($2),$2,0,`ack(DECR($1),1)', YX`ack(DECR($1), ack($1,DECR($2)))')') YSHAR_EOF Ychmod 444 'ack.m4' Yfi Ychmod 755 . Ycd .. Yif test -f 'eval.c' Ythen Y echo shar: "will not over-write existing file 'eval.c'" Yelse Ysed 's/^X//' << \SHAR_EOF > 'eval.c' YX/* YX * Copyright (c) 1989, 1993 YX * The Regents of the University of California. All rights reserved. YX * YX * This code is derived from software contributed to Berkeley by YX * Ozan Yigit at York University. YX * YX * Redistribution and use in source and binary forms, with or without YX * modification, are permitted provided that the following conditions YX * are met: YX * 1. Redistributions of source code must retain the above copyright YX * notice, this list of conditions and the following disclaimer. YX * 2. Redistributions in binary form must reproduce the above copyright YX * notice, this list of conditions and the following disclaimer in the YX * documentation and/or other materials provided with the distribution. YX * 3. All advertising materials mentioning features or use of this software YX * must display the following acknowledgement: YX * This product includes software developed by the University of YX * California, Berkeley and its contributors. YX * 4. Neither the name of the University nor the names of its contributors YX * may be used to endorse or promote products derived from this software YX * without specific prior written permission. YX * YX * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND YX * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE YX * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE YX * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE YX * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL YX * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS YX * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) YX * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT YX * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY YX * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF YX * SUCH DAMAGE. YX */ YX YX#if !defined(lint) && defined(DOSCCS) YXstatic char sccsid[] = "@(#)eval.c 8.1 (Berkeley) 6/6/93"; YX#endif YX YX/* YX * eval.c YX * Facility: m4 macro processor YX * by: oz YX */ YX YX#include YX#include YX#include YX#include YX#include "mdef.h" YX#include "stdd.h" YX#include "extern.h" YX#include "pathnames.h" YX YX/* YX * eval - evaluate built-in macros. YX * argc - number of elements in argv. YX * argv - element vector : YX * argv[0] = definition of a user YX * macro or nil if built-in. YX * argv[1] = name of the macro or YX * built-in. YX * argv[2] = parameters to user-defined YX * . macro or built-in. YX * . YX * YX * Note that the minimum value for argc is 3. A call in the form YX * of macro-or-builtin() will result in: YX * argv[0] = nullstr YX * argv[1] = macro-or-builtin YX * argv[2] = nullstr YX */ YX YXvoid YXeval(argv, argc, td) YXregister char *argv[]; YXregister int argc; YXregister int td; YX{ YX register int c, n; YX static int sysval = 0; YX YX#ifdef DEBUG YX printf("argc = %d\n", argc); YX for (n = 0; n < argc; n++) YX printf("argv[%d] = %s\n", n, argv[n]); YX#endif YX /* YX * if argc == 3 and argv[2] is null, then we YX * have macro-or-builtin() type call. We adjust YX * argc to avoid further checking.. YX */ YX if (argc == 3 && !*(argv[2])) YX argc--; YX YX switch (td & ~STATIC) { YX YX case DEFITYPE: YX if (argc > 2) YX dodefine(argv[2], (argc > 3) ? argv[3] : null); YX break; YX YX case PUSDTYPE: YX if (argc > 2) YX dopushdef(argv[2], (argc > 3) ? argv[3] : null); YX break; YX YX case DUMPTYPE: YX dodump(argv, argc); YX break; YX YX case EXPRTYPE: YX /* YX * doexpr - evaluate arithmetic YX * expression YX */ YX if (argc > 2) YX pbnum(expr(argv[2])); YX break; YX YX case IFELTYPE: YX if (argc > 4) YX doifelse(argv, argc); YX break; YX YX case IFDFTYPE: YX /* YX * doifdef - select one of two YX * alternatives based on the existence of YX * another definition YX */ YX if (argc > 3) { YX if (lookup(argv[2]) != nil) YX pbstr(argv[3]); YX else if (argc > 4) YX pbstr(argv[4]); YX } YX break; YX YX case LENGTYPE: YX /* YX * dolen - find the length of the YX * argument YX */ YX if (argc > 2) YX pbnum((argc > 2) ? strlen(argv[2]) : 0); YX break; YX YX case INCRTYPE: YX /* YX * doincr - increment the value of the YX * argument YX */ YX if (argc > 2) YX pbnum(atoi(argv[2]) + 1); YX break; YX YX case DECRTYPE: YX /* YX * dodecr - decrement the value of the YX * argument YX */ YX if (argc > 2) YX pbnum(atoi(argv[2]) - 1); YX break; YX YX case SYSCTYPE: YX /* YX * dosys - execute system command YX */ YX if (argc > 2) YX sysval = system(argv[2]); YX break; YX YX case SYSVTYPE: YX /* YX * dosysval - return value of the last YX * system call. YX * YX */ YX pbnum(sysval); YX break; YX YX case INCLTYPE: YX if (argc > 2) YX if (!doincl(argv[2])) YX oops("%s: %s", argv[2], strerror(errno)); YX break; YX YX case SINCTYPE: YX if (argc > 2) YX (void) doincl(argv[2]); YX break; YX#ifdef EXTENDED YX case PASTTYPE: YX if (argc > 2) YX if (!dopaste(argv[2])) YX oops("%s: %s", argv[2], strerror(errno)); YX break; YX YX case SPASTYPE: YX if (argc > 2) YX (void) dopaste(argv[2]); YX break; YX#endif YX case CHNQTYPE: YX dochq(argv, argc); YX break; YX YX case CHNCTYPE: YX dochc(argv, argc); YX break; YX YX case SUBSTYPE: YX /* YX * dosub - select substring YX * YX */ YX if (argc > 3) YX dosub(argv, argc); YX break; YX YX case SHIFTYPE: YX /* YX * doshift - push back all arguments YX * except the first one (i.e. skip YX * argv[2]) YX */ YX if (argc > 3) { YX for (n = argc - 1; n > 3; n--) { YX putback(rquote); YX pbstr(argv[n]); YX putback(lquote); YX putback(','); YX } YX putback(rquote); YX pbstr(argv[3]); YX putback(lquote); YX } YX break; YX YX case DIVRTYPE: YX if (argc > 2 && (n = atoi(argv[2])) != 0) YX dodiv(n); YX else { YX active = stdout; YX oindex = 0; YX } YX break; YX YX case UNDVTYPE: YX doundiv(argv, argc); YX break; YX YX case DIVNTYPE: YX /* YX * dodivnum - return the number of YX * current output diversion YX */ YX pbnum(oindex); YX break; YX YX case UNDFTYPE: YX /* YX * doundefine - undefine a previously YX * defined macro(s) or m4 keyword(s). YX */ YX if (argc > 2) YX for (n = 2; n < argc; n++) YX remhash(argv[n], ALL); YX break; YX YX case POPDTYPE: YX /* YX * dopopdef - remove the topmost YX * definitions of macro(s) or m4 YX * keyword(s). YX */ YX if (argc > 2) YX for (n = 2; n < argc; n++) YX remhash(argv[n], TOP); YX break; YX YX case MKTMTYPE: YX /* YX * dotemp - create a temporary file YX */ YX if (argc > 2) YX pbstr(mktemp(argv[2])); YX break; YX YX case TRNLTYPE: YX /* YX * dotranslit - replace all characters in YX * the source string that appears in the YX * "from" string with the corresponding YX * characters in the "to" string. YX */ YX if (argc > 3) { YX char temp[MAXTOK]; YX if (argc > 4) YX map(temp, argv[2], argv[3], argv[4]); YX else YX map(temp, argv[2], argv[3], null); YX pbstr(temp); YX } YX else if (argc > 2) YX pbstr(argv[2]); YX break; YX YX case INDXTYPE: YX /* YX * doindex - find the index of the second YX * argument string in the first argument YX * string. -1 if not present. YX */ YX pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1); YX break; YX YX case ERRPTYPE: YX /* YX * doerrp - print the arguments to stderr YX * file YX */ YX if (argc > 2) { YX for (n = 2; n < argc; n++) YX fprintf(stderr, "%s ", argv[n]); YX fprintf(stderr, "\n"); YX } YX break; YX YX case DNLNTYPE: YX /* YX * dodnl - eat-up-to and including YX * newline YX */ YX while ((c = gpbc()) != '\n' && c != EOF) YX ; YX break; YX YX case M4WRTYPE: YX /* YX * dom4wrap - set up for YX * wrap-up/wind-down activity YX */ YX m4wraps = (argc > 2) ? xstrdup(argv[2]) : null; YX break; YX YX case EXITTYPE: YX /* YX * doexit - immediate exit from m4. YX */ YX exit((argc > 2) ? atoi(argv[2]) : 0); YX break; YX YX case DEFNTYPE: YX if (argc > 2) YX for (n = 2; n < argc; n++) YX dodefn(argv[n]); YX break; YX YX default: YX oops("%s: major botch.", "eval"); YX break; YX } YX} YX YXchar *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef */ YX YX/* YX * expand - user-defined macro expansion YX */ YXvoid YXexpand(argv, argc) YXregister char *argv[]; YXregister int argc; YX{ YX register char *t; YX register char *p; YX register int n; YX register int argno; YX YX t = argv[0]; /* defn string as a whole */ YX p = t; YX while (*p) YX p++; YX p--; /* last character of defn */ YX while (p > t) { YX if (*(p - 1) != ARGFLAG) YX putback(*p); YX else { YX switch (*p) { YX YX case '#': YX pbnum(argc - 2); YX break; YX case '0': YX case '1': YX case '2': YX case '3': YX case '4': YX case '5': YX case '6': YX case '7': YX case '8': YX case '9': YX if ((argno = *p - '0') < argc - 1) YX pbstr(argv[argno + 1]); YX break; YX case '*': YX for (n = argc - 1; n > 2; n--) { YX pbstr(argv[n]); YX putback(','); YX } YX pbstr(argv[2]); YX break; YX default: YX putback(*p); YX putback('$'); YX break; YX } YX p--; YX } YX p--; YX } YX if (p == t) /* do last character */ YX putback(*p); YX} YX YX/* YX * dodefine - install definition in the table YX */ YXvoid YXdodefine(name, defn) YXregister char *name; YXregister char *defn; YX{ YX register ndptr p; YX YX if (!*name) YX oops("null definition."); YX if (STREQ(name, defn)) YX oops("%s: recursive definition.", name); YX if ((p = lookup(name)) == nil) YX p = addent(name); YX else if (p->defn != null) YX free((char *) p->defn); YX if (!*defn) YX p->defn = null; YX else YX p->defn = xstrdup(defn); YX p->type = MACRTYPE; YX} YX YX/* YX * dodefn - push back a quoted definition of YX * the given name. YX */ YXvoid YXdodefn(name) YXchar *name; YX{ YX register ndptr p; YX YX if ((p = lookup(name)) != nil && p->defn != null) { YX putback(rquote); YX pbstr(p->defn); YX putback(lquote); YX } YX} YX YX/* YX * dopushdef - install a definition in the hash table YX * without removing a previous definition. Since YX * each new entry is entered in *front* of the YX * hash bucket, it hides a previous definition from YX * lookup. YX */ YXvoid YXdopushdef(name, defn) YXregister char *name; YXregister char *defn; YX{ YX register ndptr p; YX YX if (!*name) YX oops("null definition"); YX if (STREQ(name, defn)) YX oops("%s: recursive definition.", name); YX p = addent(name); YX if (!*defn) YX p->defn = null; YX else YX p->defn = xstrdup(defn); YX p->type = MACRTYPE; YX} YX YX/* YX * dodumpdef - dump the specified definitions in the hash YX * table to stderr. If nothing is specified, the entire YX * hash table is dumped. YX */ YXvoid YXdodump(argv, argc) YXregister char *argv[]; YXregister int argc; YX{ YX register int n; YX ndptr p; YX YX if (argc > 2) { YX for (n = 2; n < argc; n++) YX if ((p = lookup(argv[n])) != nil) YX fprintf(stderr, dumpfmt, p->name, YX p->defn); YX } YX else { YX for (n = 0; n < HASHSIZE; n++) YX for (p = hashtab[n]; p != nil; p = p->nxtptr) YX fprintf(stderr, dumpfmt, p->name, YX p->defn); YX } YX} YX YX/* YX * doifelse - select one of two alternatives - loop. YX */ YXvoid YXdoifelse(argv, argc) YXregister char *argv[]; YXregister int argc; YX{ YX cycle { YX if (STREQ(argv[2], argv[3])) YX pbstr(argv[4]); YX else if (argc == 6) YX pbstr(argv[5]); YX else if (argc > 6) { YX argv += 3; YX argc -= 3; YX continue; YX } YX break; YX } YX} YX YX/* YX * doinclude - include a given file. YX */ YXint YXdoincl(ifile) YXchar *ifile; YX{ YX if (ilevel + 1 == MAXINP) YX oops("too many include files."); YX if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) { YX ilevel++; YX bbase[ilevel] = bufbase = bp; YX return (1); YX } YX else YX return (0); YX} YX YX#ifdef EXTENDED YX/* YX * dopaste - include a given file without any YX * macro processing. YX */ YXint YXdopaste(pfile) YXchar *pfile; YX{ YX FILE *pf; YX register int c; YX YX if ((pf = fopen(pfile, "r")) != NULL) { YX while ((c = getc(pf)) != EOF) YX putc(c, active); YX (void) fclose(pf); YX return (1); YX } YX else YX return (0); YX} YX#endif YX YX/* YX * dochq - change quote characters YX */ YXvoid YXdochq(argv, argc) YXregister char *argv[]; YXregister int argc; YX{ YX if (argc > 2) { YX if (*argv[2]) YX lquote = *argv[2]; YX if (argc > 3) { YX if (*argv[3]) YX rquote = *argv[3]; YX } YX else YX rquote = lquote; YX } YX else { YX lquote = LQUOTE; YX rquote = RQUOTE; YX } YX} YX YX/* YX * dochc - change comment characters YX */ YXvoid YXdochc(argv, argc) YXregister char *argv[]; YXregister int argc; YX{ YX if (argc > 2) { YX if (*argv[2]) YX scommt = *argv[2]; YX if (argc > 3) { YX if (*argv[3]) YX ecommt = *argv[3]; YX } YX else YX ecommt = ECOMMT; YX } YX else { YX scommt = SCOMMT; YX ecommt = ECOMMT; YX } YX} YX YX/* YX * dodivert - divert the output to a temporary file YX */ YXvoid YXdodiv(n) YXregister int n; YX{ YX if (n < 0 || n >= MAXOUT) YX n = 0; /* bitbucket */ YX if (outfile[n] == NULL) { YX m4temp[UNIQUE] = n + '0'; YX if ((outfile[n] = fopen(m4temp, "w")) == NULL) YX oops("%s: cannot divert.", m4temp); YX } YX oindex = n; YX active = outfile[n]; YX} YX YX/* YX * doundivert - undivert a specified output, or all YX * other outputs, in numerical order. YX */ YXvoid YXdoundiv(argv, argc) YXregister char *argv[]; YXregister int argc; YX{ YX register int ind; YX register int n; YX YX if (argc > 2) { YX for (ind = 2; ind < argc; ind++) { YX n = atoi(argv[ind]); YX if (n > 0 && n < MAXOUT && outfile[n] != NULL) YX getdiv(n); YX YX } YX } YX else YX for (n = 1; n < MAXOUT; n++) YX if (outfile[n] != NULL) YX getdiv(n); YX} YX YX/* YX * dosub - select substring YX */ YXvoid YXdosub(argv, argc) YXregister char *argv[]; YXregister int argc; YX{ YX register char *ap, *fc, *k; YX register int nc; YX YX if (argc < 5) YX nc = MAXTOK; YX else YX#ifdef EXPR YX nc = expr(argv[4]); YX#else YX nc = atoi(argv[4]); YX#endif YX ap = argv[2]; /* target string */ YX#ifdef EXPR YX fc = ap + expr(argv[3]); /* first char */ YX#else YX fc = ap + atoi(argv[3]); /* first char */ YX#endif YX if (fc >= ap && fc < ap + strlen(ap)) YX for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--) YX putback(*k); YX} YX YX/* YX * map: YX * map every character of s1 that is specified in from YX * into s3 and replace in s. (source s1 remains untouched) YX * YX * This is a standard implementation of map(s,from,to) function of ICON YX * language. Within mapvec, we replace every character of "from" with YX * the corresponding character in "to". If "to" is shorter than "from", YX * than the corresponding entries are null, which means that those YX * characters dissapear altogether. Furthermore, imagine YX * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case, YX * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s' YX * ultimately maps to `*'. In order to achieve this effect in an efficient YX * manner (i.e. without multiple passes over the destination string), we YX * loop over mapvec, starting with the initial source character. if the YX * character value (dch) in this location is different than the source YX * character (sch), sch becomes dch, once again to index into mapvec, until YX * the character value stabilizes (i.e. sch = dch, in other words YX * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary YX * character, it will stabilize, since mapvec[0] == 0 at all times. At the YX * end, we restore mapvec* back to normal where mapvec[n] == n for YX * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is YX * about 5 times faster than any algorithm that makes multiple passes over YX * destination string. YX */ YXvoid YXmap(dest, src, from, to) YXregister char *dest; YXregister char *src; YXregister char *from; YXregister char *to; YX{ YX register char *tmp; YX register char sch, dch; YX static char mapvec[128] = { YX 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, YX 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, YX 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, YX 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, YX 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, YX 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, YX 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, YX 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, YX 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, YX 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, YX 120, 121, 122, 123, 124, 125, 126, 127 YX }; YX YX if (*src) { YX tmp = from; YX /* YX * create a mapping between "from" and YX * "to" YX */ YX while (*from) YX mapvec[*from++] = (*to) ? *to++ : (char) 0; YX YX while (*src) { YX sch = *src++; YX dch = mapvec[sch]; YX while (dch != sch) { YX sch = dch; YX dch = mapvec[sch]; YX } YX if (*dest = dch) YX dest++; YX } YX /* YX * restore all the changed characters YX */ YX while (*tmp) { YX mapvec[*tmp] = *tmp; YX tmp++; YX } YX } YX *dest = (char) 0; YX} YSHAR_EOF Ychmod 644 'eval.c' Yfi Yif test -f 'Makefile' Ythen Y echo shar: "will not over-write existing file 'Makefile'" Yelse Ysed 's/^X//' << \SHAR_EOF > 'Makefile' YX# @(#)Makefile 1.0 (2.11BSD GTE) 4/5/94 YX YXDEFS= -DEXTENDED -I. YXCFLAGS= -O ${DEFS} YXDESTDIR= YXSEPFLAG= -i YXSRCS= eval.c expr.c look.c main.c misc.c YXOBJS= eval.o expr.o look.o main.o misc.o YX YXall: m4 tags YX YXm4: ${OBJS} YX cc ${SEPFLAG} -o m4 ${OBJS} YX YXinstall: all YX install -s -m 755 m4 ${DESTDIR}/usr/bin/m4 YX YXlint: YX lint -hax ${DEFS} ${SRCS} YX YXtags: YX ctags -t *.h ${SRCS} YX YXclean: YX -rm -f *.o m4 core YX YXdepend: ${SRCS} YX mkdep -p ${CFLAGS} ${SRCS} YSHAR_EOF Ychmod 644 'Makefile' Yfi Yif test -f 'stdd.h' Ythen Y echo shar: "will not over-write existing file 'stdd.h'" Yelse Ysed 's/^X//' << \SHAR_EOF > 'stdd.h' YX/*- YX * Copyright (c) 1991, 1993 YX * The Regents of the University of California. All rights reserved. YX * YX * This code is derived from software contributed to Berkeley by YX * Ozan Yigit at York University. YX * YX * Redistribution and use in source and binary forms, with or without YX * modification, are permitted provided that the following conditions YX * are met: YX * 1. Redistributions of source code must retain the above copyright YX * notice, this list of conditions and the following disclaimer. YX * 2. Redistributions in binary form must reproduce the above copyright YX * notice, this list of conditions and the following disclaimer in the YX * documentation and/or other materials provided with the distribution. YX * 3. All advertising materials mentioning features or use of this software YX * must display the following acknowledgement: YX * This product includes software developed by the University of YX * California, Berkeley and its contributors. YX * 4. Neither the name of the University nor the names of its contributors YX * may be used to endorse or promote products derived from this software YX * without specific prior written permission. YX * YX * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND YX * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE YX * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE YX * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE YX * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL YX * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS YX * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) YX * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT YX * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY YX * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF YX * SUCH DAMAGE. YX * YX * @(#)stdd.h 8.1 (Berkeley) 6/6/93 YX */ YX YX/* YX * standard defines YX */ YX YX#define max(a,b) ((a) > (b)? (a): (b)) YX#define min(a,b) ((a) < (b)? (a): (b)) YX YX#define iswhite(c) ((c) == ' ' || (c) == '\t') YX YX/* YX * STREQ is an optimised strcmp(a,b)==0 YX * STREQN is an optimised strncmp(a,b,n)==0; assumes n > 0 YX */ YX#define STREQ(a, b) ((a)[0] == (b)[0] && strcmp(a, b) == 0) YX#define STREQN(a, b, n) ((a)[0] == (b)[0] && strncmp(a, b, n) == 0) YX YX#define YES 1 YX#define NO 0 YX YX#define __P(protos) () YX YXextern int errno; YSHAR_EOF Ychmod 644 'stdd.h' Yfi Yif test -f 'pathnames.h' Ythen Y echo shar: "will not over-write existing file 'pathnames.h'" Yelse Ysed 's/^X//' << \SHAR_EOF > 'pathnames.h' YX/* YX * Copyright (c) 1989, 1993 YX * The Regents of the University of California. All rights reserved. YX * YX * This code is derived from software contributed to Berkeley by YX * Ozan Yigit at York University. YX * YX * Redistribution and use in source and binary forms, with or without YX * modification, are permitted provided that the following conditions YX * are met: YX * 1. Redistributions of source code must retain the above copyright YX * notice, this list of conditions and the following disclaimer. YX * 2. Redistributions in binary form must reproduce the above copyright YX * notice, this list of conditions and the following disclaimer in the YX * documentation and/or other materials provided with the distribution. YX * 3. All advertising materials mentioning features or use of this software YX * must display the following acknowledgement: YX * This product includes software developed by the University of YX * California, Berkeley and its contributors. YX * 4. Neither the name of the University nor the names of its contributors YX * may be used to endorse or promote products derived from this software YX * without specific prior written permission. YX * YX * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND YX * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE YX * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE YX * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE YX * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL YX * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS YX * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) YX * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT YX * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY YX * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF YX * SUCH DAMAGE. YX * YX * @(#)pathnames.h 8.1 (Berkeley) 6/6/93 YX */ YX YX/* YX * Definitions of diversion files. If the name of the file is changed, YX * adjust UNIQUE to point to the wildcard (*) character in the filename. YX */ YX YX#ifdef msdos YX#define _PATH_DIVNAME "\\M4*XXXXXX" /* msdos diversion files */ YX#define UNIQUE 3 /* unique char location */ YX#endif YX YX#ifdef unix YX#define _PATH_DIVNAME "/tmp/m4.0XXXXXX" /* unix diversion files */ YX#define UNIQUE 8 /* unique char location */ YX#endif YX YX#ifdef vms YX#define _PATH_DIVNAME "sys$login:m4*XXXXXX" /* vms diversion files */ YX#define UNIQUE 12 /* unique char location */ YX#endif YSHAR_EOF Ychmod 644 'pathnames.h' Yfi Yif test -f 'misc.c' Ythen Y echo shar: "will not over-write existing file 'misc.c'" Yelse Ysed 's/^X//' << \SHAR_EOF > 'misc.c' YX/* YX * Copyright (c) 1989, 1993 YX * The Regents of the University of California. All rights reserved. YX * YX * This code is derived from software contributed to Berkeley by YX * Ozan Yigit at York University. YX * YX * Redistribution and use in source and binary forms, with or without YX * modification, are permitted provided that the following conditions YX * are met: YX * 1. Redistributions of source code must retain the above copyright YX * notice, this list of conditions and the following disclaimer. YX * 2. Redistributions in binary form must reproduce the above copyright YX * notice, this list of conditions and the following disclaimer in the YX * documentation and/or other materials provided with the distribution. YX * 3. All advertising materials mentioning features or use of this software YX * must display the following acknowledgement: YX * This product includes software developed by the University of YX * California, Berkeley and its contributors. YX * 4. Neither the name of the University nor the names of its contributors YX * may be used to endorse or promote products derived from this software YX * without specific prior written permission. YX * YX * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND YX * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE YX * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE YX * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE YX * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL YX * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS YX * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) YX * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT YX * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY YX * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF YX * SUCH DAMAGE. YX */ YX YX#if !defined(lint) && defined(DOSCCS) YXstatic char sccsid[] = "@(#)misc.c 8.1 (Berkeley) 6/6/93"; YX#endif YX YX#include YX#include YX#include YX#include YX#include "mdef.h" YX#include "stdd.h" YX#include "extern.h" YX#include "pathnames.h" YX YX/* YX * find the index of second str in the first str. YX */ YXint YXindx(s1, s2) YXchar *s1; YXchar *s2; YX{ YX register char *t; YX register char *p; YX register char *m; YX YX for (p = s1; *p; p++) { YX for (t = p, m = s2; *m && *m == *t; m++, t++); YX if (!*m) YX return (p - s1); YX } YX return (-1); YX} YX/* YX * putback - push character back onto input YX */ YXvoid YXputback(c) YXchar c; YX{ YX if (bp < endpbb) YX *bp++ = c; YX else YX oops("too many characters pushed back"); YX} YX YX/* YX * pbstr - push string back onto input YX * putback is replicated to improve YX * performance. YX */ YXvoid YXpbstr(s) YXregister char *s; YX{ YX register char *es; YX register char *zp; YX YX es = s; YX zp = bp; YX YX while (*es) YX es++; YX es--; YX while (es >= s) YX if (zp < endpbb) YX *zp++ = *es--; YX if ((bp = zp) == endpbb) YX oops("too many characters pushed back"); YX} YX YX/* YX * pbnum - convert number to string, push back on input. YX */ YXvoid YXpbnum(n) YXint n; YX{ YX register int num; YX YX num = (n < 0) ? -n : n; YX do { YX putback(num % 10 + '0'); YX } YX while ((num /= 10) > 0); YX YX if (n < 0) YX putback('-'); YX} YX YX/* YX * chrsave - put single char on string space YX */ YXvoid YXchrsave(c) YXchar c; YX{ YX if (ep < endest) YX *ep++ = c; YX else YX oops("string space overflow"); YX} YX YX/* YX * read in a diversion file, and dispose it. YX */ YXvoid YXgetdiv(n) YXint n; YX{ YX register int c; YX register FILE *dfil; YX YX if (active == outfile[n]) YX oops("%s: diversion still active.", "undivert"); YX (void) fclose(outfile[n]); YX outfile[n] = NULL; YX m4temp[UNIQUE] = n + '0'; YX if ((dfil = fopen(m4temp, "r")) == NULL) YX oops("%s: cannot undivert.", m4temp); YX else YX while ((c = getc(dfil)) != EOF) YX putc(c, active); YX (void) fclose(dfil); YX YX#ifdef vms YX if (remove(m4temp)) YX#else YX if (unlink(m4temp) == -1) YX#endif YX oops("%s: cannot unlink.", m4temp); YX} YX YXint YXonintr() YX{ YX oops("interrupted."); YX} YX YXchar * YXxalloc(n) YXunsigned n; YX{ YX register char *p = malloc(n); YX YX if (p == NULL) YX oops("malloc: %s", strerror(errno)); YX return p; YX} YX YXchar * YXxstrdup(s) YXchar *s; YX{ YX register char *p = strdup(s); YX if (p == NULL) YX oops("strdup: %s", strerror(errno)); YX return p; YX} YX YXchar * YXbasename(s) YXregister char *s; YX{ YX register char *p; YX extern char *strrchr(); YX YX if ((p = strrchr(s, '/')) == NULL) YX return s; YX YX return ++p; YX} YX YXvoid YXusage() YX{ YX fprintf(stderr, "usage: m4 [-Dname[=val]] [-Uname]\n"); YX exit(1); YX} YX YX#if __STDC__ YX#include YX#else YX#include YX#endif YX YXvoid YX#if __STDC__ YXoops(const char *fmt, ...) YX#else YX/* VARARGS1 */ YXoops(fmt, va_alist) YX char *fmt; YX va_dcl YX#endif YX{ YX va_list ap; YX#if __STDC__ YX va_start(ap, fmt); YX#else YX va_start(ap); YX#endif YX (void)fprintf(stderr, "%s: ", progname); YX (void)vfprintf(stderr, fmt, ap); YX va_end(ap); YX (void)fprintf(stderr, "\n"); YX exit(1); YX /* NOTREACHED */ YX} YSHAR_EOF Ychmod 644 'misc.c' Yfi Yif test -f 'mdef.h' Ythen Y echo shar: "will not over-write existing file 'mdef.h'" Yelse Ysed 's/^X//' << \SHAR_EOF > 'mdef.h' YX/* YX * Copyright (c) 1989, 1993 YX * The Regents of the University of California. All rights reserved. YX * YX * This code is derived from software contributed to Berkeley by YX * Ozan Yigit at York University. YX * YX * Redistribution and use in source and binary forms, with or without YX * modification, are permitted provided that the following conditions YX * are met: YX * 1. Redistributions of source code must retain the above copyright YX * notice, this list of conditions and the following disclaimer. YX * 2. Redistributions in binary form must reproduce the above copyright YX * notice, this list of conditions and the following disclaimer in the YX * documentation and/or other materials provided with the distribution. YX * 3. All advertising materials mentioning features or use of this software YX * must display the following acknowledgement: YX * This product includes software developed by the University of YX * California, Berkeley and its contributors. YX * 4. Neither the name of the University nor the names of its contributors YX * may be used to endorse or promote products derived from this software YX * without specific prior written permission. YX * YX * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND YX * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE YX * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE YX * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE YX * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL YX * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS YX * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) YX * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT YX * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY YX * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF YX * SUCH DAMAGE. YX * YX * @(#)mdef.h 8.1 (Berkeley) 6/6/93 YX */ YX YX#define MACRTYPE 1 YX#define DEFITYPE 2 YX#define EXPRTYPE 3 YX#define SUBSTYPE 4 YX#define IFELTYPE 5 YX#define LENGTYPE 6 YX#define CHNQTYPE 7 YX#define SYSCTYPE 8 YX#define UNDFTYPE 9 YX#define INCLTYPE 10 YX#define SINCTYPE 11 YX#define PASTTYPE 12 YX#define SPASTYPE 13 YX#define INCRTYPE 14 YX#define IFDFTYPE 15 YX#define PUSDTYPE 16 YX#define POPDTYPE 17 YX#define SHIFTYPE 18 YX#define DECRTYPE 19 YX#define DIVRTYPE 20 YX#define UNDVTYPE 21 YX#define DIVNTYPE 22 YX#define MKTMTYPE 23 YX#define ERRPTYPE 24 YX#define M4WRTYPE 25 YX#define TRNLTYPE 26 YX#define DNLNTYPE 27 YX#define DUMPTYPE 28 YX#define CHNCTYPE 29 YX#define INDXTYPE 30 YX#define SYSVTYPE 31 YX#define EXITTYPE 32 YX#define DEFNTYPE 33 YX YX#define STATIC 128 YX YX/* YX * m4 special characters YX */ YX YX#define ARGFLAG '$' YX#define LPAREN '(' YX#define RPAREN ')' YX#define LQUOTE '`' YX#define RQUOTE '\'' YX#define COMMA ',' YX#define SCOMMT '#' YX#define ECOMMT '\n' YX YX#ifdef msdos YX#define system(str) (-1) YX#endif YX YX/* YX * other important constants YX */ YX YX#define EOS (char) 0 YX#define MAXINP 10 /* maximum include files */ YX#define MAXOUT 10 /* maximum # of diversions */ YX#define MAXSTR 512 /* maximum size of string */ YX#define BUFSIZE 4096 /* size of pushback buffer */ YX#define STACKMAX 1024 /* size of call stack */ YX#define STRSPMAX 4096 /* size of string space */ YX#define MAXTOK MAXSTR /* maximum chars in a tokn */ YX#define HASHSIZE 199 /* maximum size of hashtab */ YX YX#define ALL 1 YX#define TOP 0 YX YX#define TRUE 1 YX#define FALSE 0 YX#define cycle for(;;) YX YX/* YX * m4 data structures YX */ YX YXtypedef struct ndblock *ndptr; YX YXstruct ndblock { /* hastable structure */ YX char *name; /* entry name.. */ YX char *defn; /* definition.. */ YX int type; /* type of the entry.. */ YX ndptr nxtptr; /* link to next entry.. */ YX}; YX YX#define nil ((ndptr) 0) YX YXstruct keyblk { YX char *knam; /* keyword name */ YX int ktyp; /* keyword type */ YX}; YX YXtypedef union { /* stack structure */ YX int sfra; /* frame entry */ YX char *sstr; /* string entry */ YX} stae; YX YX/* YX * macros for readibility and/or speed YX * YX * gpbc() - get a possibly pushed-back character YX * pushf() - push a call frame entry onto stack YX * pushs() - push a string pointer onto stack YX */ YX#define gpbc() (bp > bufbase) ? *--bp : getc(infile[ilevel]) YX#define pushf(x) if (sp < STACKMAX) mstack[++sp].sfra = (x) YX#define pushs(x) if (sp < STACKMAX) mstack[++sp].sstr = (x) YX YX/* YX * . . YX * | . | <-- sp | . | YX * +-------+ +-----+ YX * | arg 3 ----------------------->| str | YX * +-------+ | . | YX * | arg 2 ---PREVEP-----+ . YX * +-------+ | YX * . | | | YX * +-------+ | +-----+ YX * | plev | PARLEV +-------->| str | YX * +-------+ | . | YX * | type | CALTYP . YX * +-------+ YX * | prcf ---PREVFP--+ YX * +-------+ | YX * | . | PREVSP | YX * . | YX * +-------+ | YX * | <----------+ YX * +-------+ YX * YX */ YX#define PARLEV (mstack[fp].sfra) YX#define CALTYP (mstack[fp-1].sfra) YX#define PREVEP (mstack[fp+3].sstr) YX#define PREVSP (fp-3) YX#define PREVFP (mstack[fp-2].sfra) YSHAR_EOF Ychmod 644 'mdef.h' Yfi Yif test -f 'main.c' Ythen Y echo shar: "will not over-write existing file 'main.c'" Yelse Ysed 's/^X//' << \SHAR_EOF > 'main.c' YX/*- YX * Copyright (c) 1989, 1993 YX * The Regents of the University of California. All rights reserved. YX * YX * This code is derived from software contributed to Berkeley by YX * Ozan Yigit at York University. YX * YX * Redistribution and use in source and binary forms, with or without YX * modification, are permitted provided that the following conditions YX * are met: YX * 1. Redistributions of source code must retain the above copyright YX * notice, this list of conditions and the following disclaimer. YX * 2. Redistributions in binary form must reproduce the above copyright YX * notice, this list of conditions and the following disclaimer in the YX * documentation and/or other materials provided with the distribution. YX * 3. All advertising materials mentioning features or use of this software YX * must display the following acknowledgement: YX * This product includes software developed by the University of YX * California, Berkeley and its contributors. YX * 4. Neither the name of the University nor the names of its contributors YX * may be used to endorse or promote products derived from this software YX * without specific prior written permission. YX * YX * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND YX * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE YX * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE YX * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE YX * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL YX * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS YX * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) YX * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT YX * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY YX * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF YX * SUCH DAMAGE. YX */ YX YX#if !defined(lint) && defined(DOSCCS) YXstatic char copyright[] = YX"@(#) Copyright (c) 1989, 1993\n\ YX The Regents of the University of California. All rights reserved.\n"; YX YXstatic char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; YX#endif YX YX/* YX * main.c YX * Facility: m4 macro processor YX * by: oz YX */ YX YX#include YX#include YX#include YX#include YX#include YX#include YX#include "mdef.h" YX#include "stdd.h" YX#include "extern.h" YX#include "pathnames.h" YX YXndptr hashtab[HASHSIZE]; /* hash table for macros etc. */ YXchar buf[BUFSIZE]; /* push-back buffer */ YXchar *bufbase = buf; /* the base for current ilevel */ YXchar *bbase[MAXINP]; /* the base for each ilevel */ YXchar *bp = buf; /* first available character */ YXchar *endpbb = buf+BUFSIZE; /* end of push-back buffer */ YXstae mstack[STACKMAX+1]; /* stack of m4 machine */ YXchar strspace[STRSPMAX+1]; /* string space for evaluation */ YXchar *ep = strspace; /* first free char in strspace */ YXchar *endest= strspace+STRSPMAX;/* end of string space */ YXint sp; /* current m4 stack pointer */ YXint fp; /* m4 call frame pointer */ YXFILE *infile[MAXINP]; /* input file stack (0=stdin) */ YXFILE *outfile[MAXOUT]; /* diversion array(0=bitbucket)*/ YXFILE *active; /* active output file pointer */ YXchar *m4temp; /* filename for diversions */ YXint ilevel = 0; /* input file stack pointer */ YXint oindex = 0; /* diversion index.. */ YXchar *null = ""; /* as it says.. just a null.. */ YXchar *m4wraps = ""; /* m4wrap string default.. */ YXchar *progname; /* name of this program */ YXchar lquote = LQUOTE; /* left quote character (`) */ YXchar rquote = RQUOTE; /* right quote character (') */ YXchar scommt = SCOMMT; /* start character for comment */ YXchar ecommt = ECOMMT; /* end character for comment */ YX YXstruct keyblk keywrds[] = { /* m4 keywords to be installed */ YX "include", INCLTYPE, YX "sinclude", SINCTYPE, YX "define", DEFITYPE, YX "defn", DEFNTYPE, YX "divert", DIVRTYPE, YX "expr", EXPRTYPE, YX "eval", EXPRTYPE, YX "substr", SUBSTYPE, YX "ifelse", IFELTYPE, YX "ifdef", IFDFTYPE, YX "len", LENGTYPE, YX "incr", INCRTYPE, YX "decr", DECRTYPE, YX "dnl", DNLNTYPE, YX "changequote", CHNQTYPE, YX "changecom", CHNCTYPE, YX "index", INDXTYPE, YX#ifdef EXTENDED YX "paste", PASTTYPE, YX "spaste", SPASTYPE, YX#endif YX "popdef", POPDTYPE, YX "pushdef", PUSDTYPE, YX "dumpdef", DUMPTYPE, YX "shift", SHIFTYPE, YX "translit", TRNLTYPE, YX "undefine", UNDFTYPE, YX "undivert", UNDVTYPE, YX "divnum", DIVNTYPE, YX "maketemp", MKTMTYPE, YX "errprint", ERRPTYPE, YX "m4wrap", M4WRTYPE, YX "m4exit", EXITTYPE, YX "syscmd", SYSCTYPE, YX "sysval", SYSVTYPE, YX YX#ifdef unix YX "unix", MACRTYPE, YX#else YX#ifdef vms YX "vms", MACRTYPE, YX#endif YX#endif YX}; YX YX#define MAXKEYS (sizeof(keywrds)/sizeof(struct keyblk)) YX YXextern int optind; YXextern char *optarg; YX YXvoid macro(); YXvoid initkwds(); YXextern int getopt(); YX YXint YXmain(argc,argv) YX int argc; YX char *argv[]; YX{ YX register int c; YX register int n; YX char *p; YX register FILE *ifp; YX YX progname = basename(argv[0]); YX YX if (signal(SIGINT, SIG_IGN) != SIG_IGN) YX signal(SIGINT, onintr); YX YX initkwds(); YX YX while ((c = getopt(argc, argv, "tD:U:o:")) != EOF) YX switch(c) { YX YX case 'D': /* define something..*/ YX for (p = optarg; *p; p++) YX if (*p == '=') YX break; YX if (*p) YX *p++ = EOS; YX dodefine(optarg, p); YX break; YX case 'U': /* undefine... */ YX remhash(optarg, TOP); YX break; YX case 'o': /* specific output */ YX case '?': YX usage(); YX } YX YX argc -= optind; YX argv += optind; YX YX active = stdout; /* default active output */ YX /* filename for diversions */ YX m4temp = mktemp(xstrdup(_PATH_DIVNAME)); YX YX bbase[0] = bufbase; YX if (!argc) { YX sp = -1; /* stack pointer initialized */ YX fp = 0; /* frame pointer initialized */ YX infile[0] = stdin; /* default input (naturally) */ YX macro(); YX } else YX for (; argc--; ++argv) { YX p = *argv; YX if (p[0] == '-' && p[1] == '\0') YX ifp = stdin; YX else if ((ifp = fopen(p, "r")) == NULL) YX oops("%s: %s", p, strerror(errno)); YX sp = -1; YX fp = 0; YX infile[0] = ifp; YX macro(); YX if (ifp != stdin) YX (void)fclose(ifp); YX } YX YX if (*m4wraps) { /* anything for rundown ?? */ YX ilevel = 0; /* in case m4wrap includes.. */ YX bufbase = bp = buf; /* use the entire buffer */ YX putback(EOF); /* eof is a must !! */ YX pbstr(m4wraps); /* user-defined wrapup act */ YX macro(); /* last will and testament */ YX } YX YX if (active != stdout) YX active = stdout; /* reset output just in case */ YX for (n = 1; n < MAXOUT; n++) /* default wrap-up: undivert */ YX if (outfile[n] != NULL) YX getdiv(n); YX /* remove bitbucket if used */ YX if (outfile[0] != NULL) { YX (void) fclose(outfile[0]); YX m4temp[UNIQUE] = '0'; YX#ifdef vms YX (void) remove(m4temp); YX#else YX (void) unlink(m4temp); YX#endif YX } YX YX return 0; YX} YX YXndptr inspect(); YX YX/* YX * macro - the work horse.. YX */ YXvoid YXmacro() { YX char token[MAXTOK]; YX register char *s; YX register int t, l; YX register ndptr p; YX register int nlpar; YX YX cycle { YX if ((t = gpbc()) == '_' || isalpha(t)) { YX putback(t); YX if ((p = inspect(s = token)) == nil) { YX if (sp < 0) YX while (*s) YX putc(*s++, active); YX else YX while (*s) YX chrsave(*s++); YX } YX else { YX /* YX * real thing.. First build a call frame: YX */ YX pushf(fp); /* previous call frm */ YX pushf(p->type); /* type of the call */ YX pushf(0); /* parenthesis level */ YX fp = sp; /* new frame pointer */ YX /* YX * now push the string arguments: YX */ YX pushs(p->defn); /* defn string */ YX pushs(p->name); /* macro name */ YX pushs(ep); /* start next..*/ YX YX putback(l = gpbc()); YX if (l != LPAREN) { /* add bracks */ YX putback(RPAREN); YX putback(LPAREN); YX } YX } YX } YX else if (t == EOF) { YX if (sp > -1) YX oops("unexpected end of input", ""); YX if (ilevel <= 0) YX break; /* all done thanks.. */ YX --ilevel; YX (void) fclose(infile[ilevel+1]); YX bufbase = bbase[ilevel]; YX continue; YX } YX /* YX * non-alpha single-char token seen.. YX * [the order of else if .. stmts is important.] YX */ YX else if (t == lquote) { /* strip quotes */ YX nlpar = 1; YX do { YX if ((l = gpbc()) == rquote) YX nlpar--; YX else if (l == lquote) YX nlpar++; YX else if (l == EOF) YX oops("missing right quote", ""); YX if (nlpar > 0) { YX if (sp < 0) YX putc(l, active); YX else YX chrsave(l); YX } YX } YX while (nlpar != 0); YX } YX YX else if (sp < 0) { /* not in a macro at all */ YX if (t == scommt) { /* comment handling here */ YX putc(t, active); YX while ((t = gpbc()) != ecommt) YX putc(t, active); YX } YX putc(t, active); /* output directly.. */ YX } YX YX else switch(t) { YX YX case LPAREN: YX if (PARLEV > 0) YX chrsave(t); YX while (isspace(l = gpbc())) YX ; /* skip blank, tab, nl.. */ YX putback(l); YX PARLEV++; YX break; YX YX case RPAREN: YX if (--PARLEV > 0) YX chrsave(t); YX else { /* end of argument list */ YX chrsave(EOS); YX YX if (sp == STACKMAX) YX oops("internal stack overflow", ""); YX YX if (CALTYP == MACRTYPE) YX expand((char **) mstack+fp+1, sp-fp); YX else YX eval((char **) mstack+fp+1, sp-fp, CALTYP); YX YX ep = PREVEP; /* flush strspace */ YX sp = PREVSP; /* previous sp.. */ YX fp = PREVFP; /* rewind stack...*/ YX } YX break; YX YX case COMMA: YX if (PARLEV == 1) { YX chrsave(EOS); /* new argument */ YX while (isspace(l = gpbc())) YX ; YX putback(l); YX pushs(ep); YX } else YX chrsave(t); YX break; YX YX default: YX chrsave(t); /* stack the char */ YX break; YX } YX } YX} YX YX/* YX * build an input token.. YX * consider only those starting with _ or A-Za-z. This is a YX * combo with lookup to speed things up. YX */ YXndptr YXinspect(tp) YXregister char *tp; YX{ YX register char c; YX register char *name = tp; YX register char *etp = tp+MAXTOK; YX register ndptr p; YX register unsigned long h = 0; YX YX while ((isalnum(c = gpbc()) || c == '_') && tp < etp) YX h = (h << 5) + h + (*tp++ = c); YX putback(c); YX if (tp == etp) YX oops("token too long", ""); YX YX *tp = EOS; YX YX for (p = hashtab[h%HASHSIZE]; p != nil; p = p->nxtptr) YX if (STREQ(name, p->name)) YX break; YX return p; YX} YX YX/* YX * initkwds - initialise m4 keywords as fast as possible. YX * This very similar to install, but without certain overheads, YX * such as calling lookup. Malloc is not used for storing the YX * keyword strings, since we simply use the static pointers YX * within keywrds block. YX */ YXvoid YXinitkwds() { YX register int i; YX register int h; YX register ndptr p; YX YX for (i = 0; i < MAXKEYS; i++) { YX h = hash(keywrds[i].knam); YX p = (ndptr) xalloc(sizeof(struct ndblock)); YX p->nxtptr = hashtab[h]; YX hashtab[h] = p; YX p->name = keywrds[i].knam; YX p->defn = null; YX p->type = keywrds[i].ktyp | STATIC; YX } YX} YSHAR_EOF Ychmod 644 'main.c' Yfi Yif test -f 'look.c' Ythen Y echo shar: "will not over-write existing file 'look.c'" Yelse Ysed 's/^X//' << \SHAR_EOF > 'look.c' YX/* YX * Copyright (c) 1989, 1993 YX * The Regents of the University of California. All rights reserved. YX * YX * This code is derived from software contributed to Berkeley by YX * Ozan Yigit at York University. YX * YX * Redistribution and use in source and binary forms, with or without YX * modification, are permitted provided that the following conditions YX * are met: YX * 1. Redistributions of source code must retain the above copyright YX * notice, this list of conditions and the following disclaimer. YX * 2. Redistributions in binary form must reproduce the above copyright YX * notice, this list of conditions and the following disclaimer in the YX * documentation and/or other materials provided with the distribution. YX * 3. All advertising materials mentioning features or use of this software YX * must display the following acknowledgement: YX * This product includes software developed by the University of YX * California, Berkeley and its contributors. YX * 4. Neither the name of the University nor the names of its contributors YX * may be used to endorse or promote products derived from this software YX * without specific prior written permission. YX * YX * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND YX * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE YX * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE YX * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE YX * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL YX * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS YX * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) YX * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT YX * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY YX * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF YX * SUCH DAMAGE. YX */ YX YX#if !defined(lint) && defined(DOSCCS) YXstatic char sccsid[] = "@(#)look.c 8.1 (Berkeley) 6/6/93"; YX#endif YX YX/* YX * look.c YX * Facility: m4 macro processor YX * by: oz YX */ YX YX#include YX#include YX#include YX#include "mdef.h" YX#include "stdd.h" YX#include "extern.h" YX YXint YXhash(name) YXregister char *name; YX{ YX register unsigned long h = 0; YX while (*name) YX h = (h << 5) + h + *name++; YX return (h % HASHSIZE); YX} YX YX/* YX * find name in the hash table YX */ YXndptr YXlookup(name) YXchar *name; YX{ YX register ndptr p; YX YX for (p = hashtab[hash(name)]; p != nil; p = p->nxtptr) YX if (STREQ(name, p->name)) YX break; YX return (p); YX} YX YX/* YX * hash and create an entry in the hash table. YX * The new entry is added in front of a hash bucket. YX */ YXndptr YXaddent(name) YXchar *name; YX{ YX register int h; YX ndptr p; YX YX h = hash(name); YX p = (ndptr) xalloc(sizeof(struct ndblock)); YX p->nxtptr = hashtab[h]; YX hashtab[h] = p; YX p->name = xstrdup(name); YX return p; YX} YX YXstatic void YXfreent(p) YXndptr p; YX{ YX if (!(p->type & STATIC)) { YX free((char *) p->name); YX if (p->defn != null) YX free((char *) p->defn); YX } YX free((char *) p); YX} YX YX/* YX * remove an entry from the hashtable YX */ YXvoid YXremhash(name, all) YXchar *name; YXint all; YX{ YX register int h; YX register ndptr xp, tp, mp; YX YX h = hash(name); YX mp = hashtab[h]; YX tp = nil; YX while (mp != nil) { YX if (STREQ(mp->name, name)) { YX mp = mp->nxtptr; YX if (tp == nil) { YX freent(hashtab[h]); YX hashtab[h] = mp; YX } YX else { YX xp = tp->nxtptr; YX tp->nxtptr = mp; YX freent(xp); YX } YX if (!all) YX break; YX } YX else { YX tp = mp; YX mp = mp->nxtptr; YX } YX } YX} YSHAR_EOF Ychmod 644 'look.c' Yfi Yif test -f 'extern.h' Ythen Y echo shar: "will not over-write existing file 'extern.h'" Yelse Ysed 's/^X//' << \SHAR_EOF > 'extern.h' YX/*- YX * Copyright (c) 1991, 1993 YX * The Regents of the University of California. All rights reserved. YX * YX * This code is derived from software contributed to Berkeley by YX * Ozan Yigit at York University. YX * YX * Redistribution and use in source and binary forms, with or without YX * modification, are permitted provided that the following conditions YX * are met: YX * 1. Redistributions of source code must retain the above copyright YX * notice, this list of conditions and the following disclaimer. YX * 2. Redistributions in binary form must reproduce the above copyright YX * notice, this list of conditions and the following disclaimer in the YX * documentation and/or other materials provided with the distribution. YX * 3. All advertising materials mentioning features or use of this software YX * must display the following acknowledgement: YX * This product includes software developed by the University of YX * California, Berkeley and its contributors. YX * 4. Neither the name of the University nor the names of its contributors YX * may be used to endorse or promote products derived from this software YX * without specific prior written permission. YX * YX * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND YX * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE YX * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE YX * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE YX * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL YX * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS YX * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) YX * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT YX * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY YX * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF YX * SUCH DAMAGE. YX * YX * @(#)extern.h 8.1 (Berkeley) 6/6/93 YX */ YX YXchar *basename __P((char *)); YXchar *xalloc __P((unsigned int)); YXint expr __P((char *)); YXndptr addent __P((char *)); YXvoid chrsave __P((int)); YXvoid dochc __P((char *[], int)); YXvoid dochq __P((char *[], int)); YXvoid dodefine __P((char *, char *)); YXvoid dodefn __P((char *)); YXvoid dodiv __P((int)); YXvoid dodump __P((char *[], int)); YXvoid doifelse __P((char *[], int)); YXint doincl __P((char *)); YXint dopaste __P((char *)); YXvoid dopushdef __P((char *, char *)); YXvoid dosub __P((char *[], int)); YXvoid doundiv __P((char *[], int)); YXvoid eval __P((char *[], int, int)); YXvoid expand __P((char *[], int)); YXvoid getdiv __P((int)); YXchar *xstrdup __P((const char *)); YXint hash __P((char *)); YXint indx __P((char *, char *)); YXndptr lookup __P((char *)); YXvoid map __P((char *, char *, char *, char *)); YXint onintr __P((int)); YXvoid oops __P((const char *, ...)); YXvoid pbnum __P((int)); YXvoid pbstr __P((char *)); YXvoid putback __P((int)); YXvoid remhash __P((char *, int)); YXvoid usage __P((void)); YX YXextern ndptr hashtab[]; /* hash table for macros etc. */ YXextern stae mstack[]; /* stack of m4 machine */ YXextern FILE *active; /* active output file pointer */ YXextern FILE *infile[]; /* input file stack (0=stdin) */ YXextern FILE *outfile[]; /* diversion array(0=bitbucket) */ YXextern int fp; /* m4 call frame pointer */ YXextern int ilevel; /* input file stack pointer */ YXextern int oindex; /* diversion index. */ YXextern int sp; /* current m4 stack pointer */ YXextern char *bp; /* first available character */ YXextern char buf[]; /* push-back buffer */ YXextern char *bufbase; /* buffer base for this ilevel */ YXextern char *bbase[]; /* buffer base per ilevel */ YXextern char ecommt; /* end character for comment */ YXextern char *endest; /* end of string space */ YXextern char *endpbb; /* end of push-back buffer */ YXextern char *ep; /* first free char in strspace */ YXextern char lquote; /* left quote character (`) */ YXextern char *m4temp; /* filename for diversions */ YXextern char *m4wraps; /* m4wrap string default. */ YXextern char *null; /* as it says.. just a null. */ YXextern char *progname; /* program name */ YXextern char rquote; /* right quote character (') */ YXextern char scommt; /* start character for comment */ YX YXextern char *mktemp(); YXextern char *malloc(); YSHAR_EOF Ychmod 644 'extern.h' Yfi Yif test -f 'expr.c' Ythen Y echo shar: "will not over-write existing file 'expr.c'" Yelse Ysed 's/^X//' << \SHAR_EOF > 'expr.c' YX/* YX * Copyright (c) 1989, 1993 YX * The Regents of the University of California. All rights reserved. YX * YX * This code is derived from software contributed to Berkeley by YX * Ozan Yigit at York University. YX * YX * Redistribution and use in source and binary forms, with or without YX * modification, are permitted provided that the following conditions YX * are met: YX * 1. Redistributions of source code must retain the above copyright YX * notice, this list of conditions and the following disclaimer. YX * 2. Redistributions in binary form must reproduce the above copyright YX * notice, this list of conditions and the following disclaimer in the YX * documentation and/or other materials provided with the distribution. YX * 3. All advertising materials mentioning features or use of this software YX * must display the following acknowledgement: YX * This product includes software developed by the University of YX * California, Berkeley and its contributors. YX * 4. Neither the name of the University nor the names of its contributors YX * may be used to endorse or promote products derived from this software YX * without specific prior written permission. YX * YX * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND YX * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE YX * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE YX * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE YX * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL YX * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS YX * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) YX * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT YX * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY YX * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF YX * SUCH DAMAGE. YX */ YX YX#if !defined(lint) && defined(DOSCCS) YXstatic char sccsid[] = "@(#)expr.c 8.1 (Berkeley) 6/6/93"; YX#endif YX YX#include YX#include "stdd.h" YX YX/* YX * expression evaluator: performs a standard recursive YX * descent parse to evaluate any expression permissible YX * within the following grammar: YX * YX * expr : query EOS YX * query : lor YX * | lor "?" query ":" query YX * lor : land { "||" land } YX * land : bor { "&&" bor } YX * bor : bxor { "|" bxor } YX * bxor : band { "^" band } YX * band : eql { "&" eql } YX * eql : relat { eqrel relat } YX * relat : shift { rel shift } YX * shift : primary { shop primary } YX * primary : term { addop term } YX * term : unary { mulop unary } YX * unary : factor YX * | unop unary YX * factor : constant YX * | "(" query ")" YX * constant: num YX * | "'" CHAR "'" YX * num : DIGIT YX * | DIGIT num YX * shop : "<<" YX * | ">>" YX * eqlrel : "=" YX * | "==" YX * | "!=" YX * rel : "<" YX * | ">" YX * | "<=" YX * | ">=" YX * YX * YX * This expression evaluator is lifted from a public-domain YX * C Pre-Processor included with the DECUS C Compiler distribution. YX * It is hacked somewhat to be suitable for m4. YX * YX * Originally by: Mike Lutz YX * Bob Harper YX */ YX YX#define TRUE 1 YX#define FALSE 0 YX#define EOS (char) 0 YX#define EQL 0 YX#define NEQ 1 YX#define LSS 2 YX#define LEQ 3 YX#define GTR 4 YX#define GEQ 5 YX#define OCTAL 8 YX#define DECIMAL 10 YX YXstatic char *nxtch; /* Parser scan pointer */ YX YXstatic int query __P((void)); YXstatic int lor __P((void)); YXstatic int land __P((void)); YXstatic int bor __P((void)); YXstatic int bxor __P((void)); YXstatic int band __P((void)); YXstatic int eql __P((void)); YXstatic int relat __P((void)); YXstatic int shift __P((void)); YXstatic int primary __P((void)); YXstatic int term __P((void)); YXstatic int unary __P((void)); YXstatic int factor __P((void)); YXstatic int constant __P((void)); YXstatic int num __P((void)); YXstatic int geteql __P((void)); YXstatic int getrel __P((void)); YXstatic int skipws __P((void)); YXstatic void experr __P((char *)); YX YX/* YX * For longjmp YX */ YX#include YXstatic jmp_buf expjump; YX YX/* YX * macros: YX * ungetch - Put back the last character examined. YX * getch - return the next character from expr string. YX */ YX#define ungetch() nxtch-- YX#define getch() *nxtch++ YX YXint YXexpr(expbuf) YXchar *expbuf; YX{ YX register int rval; YX YX nxtch = expbuf; YX if (setjmp(expjump) != 0) YX return FALSE; YX YX rval = query(); YX if (skipws() == EOS) YX return rval; YX YX printf("m4: ill-formed expression.\n"); YX return FALSE; YX} YX YX/* YX * query : lor | lor '?' query ':' query YX */ YXstatic int YXquery() YX{ YX register int bool, true_val, false_val; YX YX bool = lor(); YX if (skipws() != '?') { YX ungetch(); YX return bool; YX } YX YX true_val = query(); YX if (skipws() != ':') YX experr("bad query"); YX YX false_val = query(); YX return bool ? true_val : false_val; YX} YX YX/* YX * lor : land { '||' land } YX */ YXstatic int YXlor() YX{ YX register int c, vl, vr; YX YX vl = land(); YX while ((c = skipws()) == '|' && getch() == '|') { YX vr = land(); YX vl = vl || vr; YX } YX YX if (c == '|') YX ungetch(); YX ungetch(); YX return vl; YX} YX YX/* YX * land : bor { '&&' bor } YX */ YXstatic int YXland() YX{ YX register int c, vl, vr; YX YX vl = bor(); YX while ((c = skipws()) == '&' && getch() == '&') { YX vr = bor(); YX vl = vl && vr; YX } YX YX if (c == '&') YX ungetch(); YX ungetch(); YX return vl; YX} YX YX/* YX * bor : bxor { '|' bxor } YX */ YXstatic int YXbor() YX{ YX register int vl, vr, c; YX YX vl = bxor(); YX while ((c = skipws()) == '|' && getch() != '|') { YX ungetch(); YX vr = bxor(); YX vl |= vr; YX } YX YX if (c == '|') YX ungetch(); YX ungetch(); YX return vl; YX} YX YX/* YX * bxor : band { '^' band } YX */ YXstatic int YXbxor() YX{ YX register int vl, vr; YX YX vl = band(); YX while (skipws() == '^') { YX vr = band(); YX vl ^= vr; YX } YX YX ungetch(); YX return vl; YX} YX YX/* YX * band : eql { '&' eql } YX */ YXstatic int YXband() YX{ YX register int vl, vr, c; YX YX vl = eql(); YX while ((c = skipws()) == '&' && getch() != '&') { YX ungetch(); YX vr = eql(); YX vl &= vr; YX } YX YX if (c == '&') YX ungetch(); YX ungetch(); YX return vl; YX} YX YX/* YX * eql : relat { eqrel relat } YX */ YXstatic int YXeql() YX{ YX register int vl, vr, rel; YX YX vl = relat(); YX while ((rel = geteql()) != -1) { YX vr = relat(); YX YX switch (rel) { YX YX case EQL: YX vl = (vl == vr); YX break; YX case NEQ: YX vl = (vl != vr); YX break; YX } YX } YX return vl; YX} YX YX/* YX * relat : shift { rel shift } YX */ YXstatic int YXrelat() YX{ YX register int vl, vr, rel; YX YX vl = shift(); YX while ((rel = getrel()) != -1) { YX YX vr = shift(); YX switch (rel) { YX YX case LEQ: YX vl = (vl <= vr); YX break; YX case LSS: YX vl = (vl < vr); YX break; YX case GTR: YX vl = (vl > vr); YX break; YX case GEQ: YX vl = (vl >= vr); YX break; YX } YX } YX return vl; YX} YX YX/* YX * shift : primary { shop primary } YX */ YXstatic int YXshift() YX{ YX register int vl, vr, c; YX YX vl = primary(); YX while (((c = skipws()) == '<' || c == '>') && c == getch()) { YX vr = primary(); YX YX if (c == '<') YX vl <<= vr; YX else YX vl >>= vr; YX } YX YX if (c == '<' || c == '>') YX ungetch(); YX ungetch(); YX return vl; YX} YX YX/* YX * primary : term { addop term } YX */ YXstatic int YXprimary() YX{ YX register int c, vl, vr; YX YX vl = term(); YX while ((c = skipws()) == '+' || c == '-') { YX vr = term(); YX if (c == '+') YX vl += vr; YX else YX vl -= vr; YX } YX YX ungetch(); YX return vl; YX} YX YX/* YX * := { } YX */ YXstatic int YXterm() YX{ YX register int c, vl, vr; YX YX vl = unary(); YX while ((c = skipws()) == '*' || c == '/' || c == '%') { YX vr = unary(); YX YX switch (c) { YX case '*': YX vl *= vr; YX break; YX case '/': YX vl /= vr; YX break; YX case '%': YX vl %= vr; YX break; YX } YX } YX ungetch(); YX return vl; YX} YX YX/* YX * unary : factor | unop unary YX */ YXstatic int YXunary() YX{ YX register int val, c; YX YX if ((c = skipws()) == '!' || c == '~' || c == '-') { YX val = unary(); YX YX switch (c) { YX case '!': YX return !val; YX case '~': YX return ~val; YX case '-': YX return -val; YX } YX } YX YX ungetch(); YX return factor(); YX} YX YX/* YX * factor : constant | '(' query ')' YX */ YXstatic int YXfactor() YX{ YX register int val; YX YX if (skipws() == '(') { YX val = query(); YX if (skipws() != ')') YX experr("bad factor"); YX return val; YX } YX YX ungetch(); YX return constant(); YX} YX YX/* YX * constant: num | 'char' YX * Note: constant() handles multi-byte constants YX */ YXstatic int YXconstant() YX{ YX register int i; YX register int value; YX register char c; YX int v[sizeof(int)]; YX YX if (skipws() != '\'') { YX ungetch(); YX return num(); YX } YX for (i = 0; i < sizeof(int); i++) { YX if ((c = getch()) == '\'') { YX ungetch(); YX break; YX } YX if (c == '\\') { YX switch (c = getch()) { YX case '0': YX case '1': YX case '2': YX case '3': YX case '4': YX case '5': YX case '6': YX case '7': YX ungetch(); YX c = num(); YX break; YX case 'n': YX c = 012; YX break; YX case 'r': YX c = 015; YX break; YX case 't': YX c = 011; YX break; YX case 'b': YX c = 010; YX break; YX case 'f': YX c = 014; YX break; YX } YX } YX v[i] = c; YX } YX if (i == 0 || getch() != '\'') YX experr("illegal character constant"); YX for (value = 0; --i >= 0;) { YX value <<= 8; YX value += v[i]; YX } YX return value; YX} YX YX/* YX * num : digit | num digit YX */ YXstatic int YXnum() YX{ YX register int rval, c, base; YX int ndig; YX YX base = ((c = skipws()) == '0') ? OCTAL : DECIMAL; YX rval = 0; YX ndig = 0; YX while (c >= '0' && c <= (base == OCTAL ? '7' : '9')) { YX rval *= base; YX rval += (c - '0'); YX c = getch(); YX ndig++; YX } YX ungetch(); YX YX if (ndig == 0) YX experr("bad constant"); YX YX return rval; YX YX} YX YX/* YX * eqlrel : '=' | '==' | '!=' YX */ YXstatic int YXgeteql() YX{ YX register int c1, c2; YX YX c1 = skipws(); YX c2 = getch(); YX YX switch (c1) { YX YX case '=': YX if (c2 != '=') YX ungetch(); YX return EQL; YX YX case '!': YX if (c2 == '=') YX return NEQ; YX ungetch(); YX ungetch(); YX return -1; YX YX default: YX ungetch(); YX ungetch(); YX return -1; YX } YX} YX YX/* YX * rel : '<' | '>' | '<=' | '>=' YX */ YXstatic int YXgetrel() YX{ YX register int c1, c2; YX YX c1 = skipws(); YX c2 = getch(); YX YX switch (c1) { YX YX case '<': YX if (c2 == '=') YX return LEQ; YX ungetch(); YX return LSS; YX YX case '>': YX if (c2 == '=') YX return GEQ; YX ungetch(); YX return GTR; YX YX default: YX ungetch(); YX ungetch(); YX return -1; YX } YX} YX YX/* YX * Skip over any white space and return terminating char. YX */ YXstatic int YXskipws() YX{ YX register char c; YX YX while ((c = getch()) <= ' ' && c > EOS) YX ; YX return c; YX} YX YX/* YX * resets environment to eval(), prints an error YX * and forces eval to return FALSE. YX */ YXstatic void YXexperr(msg) YXchar *msg; YX{ YX printf("m4: %s in expr.\n", msg); YX longjmp(expjump, -1); YX} YSHAR_EOF Ychmod 644 'expr.c' Yfi Yif test -f 'NOTES' Ythen Y echo shar: "will not over-write existing file 'NOTES'" Yelse Ysed 's/^X//' << \SHAR_EOF > 'NOTES' YXm4 - macro processor YX YXPD m4 is based on the macro tool distributed with the software YXtools (VOS) package, and described in the "SOFTWARE TOOLS" and YX"SOFTWARE TOOLS IN PASCAL" books. It has been expanded to include YXmost of the command set of SysV m4, the standard UN*X macro processor. YX YXSince both PD m4 and UN*X m4 are based on SOFTWARE TOOLS macro, YXthere may be certain implementation similarities between YXthe two. The PD m4 was produced without ANY references to m4 YXsources. YX YXwritten by: Ozan S. Yigit YX YXReferences: YX YX Software Tools distribution: macro YX YX Kernighan, Brian W. and P. J. Plauger, SOFTWARE YX TOOLS IN PASCAL, Addison-Wesley, Mass. 1981 YX YX Kernighan, Brian W. and P. J. Plauger, SOFTWARE YX TOOLS, Addison-Wesley, Mass. 1976 YX YX Kernighan, Brian W. and Dennis M. Ritchie, YX THE M4 MACRO PROCESSOR, Unix Programmer's Manual, YX Seventh Edition, Vol. 2, Bell Telephone Labs, 1979 YX YX System V man page for M4 YX YX YXImplementation Notes: YX YX[1] PD m4 uses a different (and simpler) stack mechanism than the one YX described in Software Tools and Software Tools in Pascal books. YX The triple stack thing is replaced with a single stack containing YX the call frames and the arguments. Each frame is back-linked to a YX previous stack frame, which enables us to rewind the stack after YX each nested call is completed. Each argument is a character pointer YX to the beginning of the argument string within the string space. YX The only exceptions to this are (*) arg 0 and arg 1, which are YX the macro definition and macro name strings, stored dynamically YX for the hash table. YX YX . . YX | . | <-- sp | . | YX +-------+ +-----+ YX | arg 3 ------------------------------->| str | YX +-------+ | . | YX | arg 2 --------------+ . YX +-------+ | YX * | | | YX +-------+ | +-----+ YX | plev | <-- fp +---------------->| str | YX +-------+ | . | YX | type | . YX +-------+ YX | prcf -----------+ plev: paren level YX +-------+ | type: call type YX | . | | prcf: prev. call frame YX . | YX +-------+ | YX | <----------+ YX +-------+ YSHAR_EOF Ychmod 644 'NOTES' Yfi Ychmod 751 . Ycd .. Yexit 0 Y# End of shell archive SHAR_EOF fi exit 0 # End of shell archive