summaryrefslogtreecommitdiff
path: root/systems/doc/etex/webmerge.tex
diff options
context:
space:
mode:
Diffstat (limited to 'systems/doc/etex/webmerge.tex')
-rw-r--r--systems/doc/etex/webmerge.tex392
1 files changed, 392 insertions, 0 deletions
diff --git a/systems/doc/etex/webmerge.tex b/systems/doc/etex/webmerge.tex
new file mode 100644
index 0000000000..a55ac3e930
--- /dev/null
+++ b/systems/doc/etex/webmerge.tex
@@ -0,0 +1,392 @@
+% This is webmerge.tex
+% Copyright (C) 1995,96 by the NTS team; all rights are reserved.
+%
+\def\fileversion{V 1.1}
+\def\filedate{29 Mar 96}
+%
+% In order to generate e-TeX several change files have to be applied
+% (one after the other) to tex.web. This can be done efficiently with
+% programs such as PATCHWEB or TIE. If neither of these is available
+% the present program WEBMERGE can be used to merge several change
+% files into one change file that can then be used with TANGLE.
+%
+% If the web file or one of the change files contains tab of form feed
+% characters there is, however, a problem that can't be solved in a
+% satisfactory way. This should not be a real problem since the
+% original tex.web and etex.ch don't contain these characters and there
+% is no real good reason why the system-dependent change files should
+% (except may be that some editors insist on converting sequences of
+% space characters into tabs).
+%
+% The problem is due to the fact that (an unmodified) TeX cannot write
+% tabs or form feeds to the output file. Therefore WEBMERGE offers two
+% alternatives: if \ifallowtabs is false (by default) then tab and form
+% feed characters are invalid and lead to error messages; if this
+% happens one may use the command
+% \allowtabstrue
+% to allow tab and form feed as valid input characters. If they are
+% written to the output file they will appear as '^^I' and '^^L'. This
+% must then be changed manually with a suitable editor before the output
+% from WEBMERGE can be used as input for TANGLE.
+%
+% Typically three change files are required to generate e-TeX, e.g.,
+% 1. etex.ch (system independent changes for e-TeX)
+% 2. tex.ch (system dependent changes for TeX)
+% 3. tex.ech (additional system dependent changes for e-TeX)
+% The sequence commands (to be used with plain TeX)
+% \input webmerge
+% \webfile{tex.web} % web file
+% \changefile{etex.ch} % 1. change file
+% \changefile{tex.ch} % 2. change file
+% \changefile{tex.ech} % 3. change file
+% \outfile{etex.ch} % output file, start processing
+% creates a combined change file `etex.ch'.
+% Webmerge uses a temporary file with default name `tmp.tmp',
+% the command
+% \tempfile{<temp name>}
+% can be used to change that name.
+%
+% Webmerge is slow, therefore PATCHWEB or TIE should be used whenever
+% possible. The program checks for correct change files and gives error
+% messages similar to those of TANGLE and WEAVE. The error recovery is,
+% however, rather limited.
+%
+% In case of problems please contact:
+% Peter Breitenlohner peb@mppmu.mpg.de
+
+% We make @ signs act like letters, temporarily.
+\catcode`\@=11
+
+\newif\ifallowtabs % initially false
+\def\allowtabs{\catcode`\^^I=12 \catcode`\^^L=12 }
+\def\forbidtabs{\catcode`\^^I=15 \catcode`\^^L=15 }
+
+\toksdef\toks@ii=2
+
+% First we redefine plain.tex's \loop to allow the construction
+% \loop ... \if... \else ... \repeat
+%
+\def\@iterate{\@body \expandafter\@iterate\fi}
+%
+% and to allow nested loops such as
+% \loop{... \loop ... \if... \repeat ... \if...}\repeat
+% where the braces do not imply grouping
+%
+\def\loop#1\repeat{%
+ \toks@\expandafter{\@body}%
+ \toks@ii\expandafter{\@@body}%
+ \edef\@@body{\def\noexpand\@body{\the\toks@}%
+ \def\noexpand\@@body{\the\toks@ii}}%
+ \def\@body{#1}\@iterate \@@body}
+\let\@body=\empty
+\let\@@body=\empty
+
+%
+\def\@msg{\immediate\write\sixt@@n}
+\@msg{*** webmerge \fileversion\space <\filedate> ***}
+%
+% Conceptually the web file (web_0) is combined with the first change
+% file, ch_1, in order to produce a ficticious web file web_1. Then
+% web_1 is combined with ch_2 in order to produce web_2 etc.
+
+% The logic of merging is that of TANGLE and WEAVE.
+% With several change files there may, however, be changes on top of
+% changes, i.e., a line changed by one change file may be changed again
+% by another change file.
+
+% The program below uses quite a few control sequences, many of them
+% constructed dynamically.
+% The most important ones are \<i>read (<i>=0,1,...) used to obtain the
+% next line from web_<i>. For reasons of efficiency they are \let to
+% either \<i>w (changing=false), \<i>c (changing=true), of \<i>e (file
+% has ended).
+% \<i>g is used to obtain the next line from ch_<i> and test for
+% @x/@y/@z,
+% \<i>prime (prime the change buffer) scans for the next @x from ch_<i>,
+% and \<i>match discards matching lines from web_<i-1> and ch_<i> until
+% an @y is found.
+
+\def\tempfile#1{\def\t@n{#1}}
+\def\t@n{tmp.tmp} % default tempfile name
+\newread\t@r % read tempfile
+\newwrite\t@w % write tempfile
+\def\t@o{\immediate\write\t@w} % write to tempfile
+\newwrite\o@w % write output file
+\def\o@o{\immediate\write\o@w} % write to outfile
+
+\newcount\@nch % number of change files
+\newcount\@num % number of active changes
+\newcount\@res % result from @x/@y/@z test
+\begingroup % \@pct expands to `% '
+ \lccode`\1=`\%
+ \lowercase{\endgroup \def\@pct{1 }}
+%
+
+% We need macros to define read streams, count registers, and control
+% sequences dynamically (inside \edef)
+
+\def\@nrd#1{\ifx#1\relax \csname newread\endcsname#1\fi}
+\def\@nct#1{\ifx#1\relax \csname newcount\endcsname#1\else #1\z@ \fi}
+\def\@cs#1{\csname#1\endcsname}
+\def\@csi#1{\csname\@i#1\endcsname}
+\def\@dcs#1{\expandafter\def\csname#1\endcsname}
+\def\@ecsi#1{\expandafter\edef\csname\@i#1\endcsname}
+\def\@ncsi#1{\expandafter\noexpand\csname\@i#1\endcsname}
+\def\@read{\expandafter\noexpand\csname\@ii read\endcsname}
+\def\@ifx{\noexpand\ifx}
+\def\@ifnum{\noexpand\ifnum}
+\def\@ifeof{\noexpand\ifeof\@csi r}
+\def\@else{\noexpand\else}
+\def\@fi{\noexpand\fi}
+\def\@loop{\noexpand\loop}
+\def\@repeat{\noexpand\repeat}
+\def\@expa{\noexpand\expandafter\noexpand}
+\def\@expai#1{\expandafter\@expa\csname\@i#1\endcsname}
+
+\def\webfile#1{% define webfile
+ \ifnum\@nch=\m@ne \@nch\z@ \@dcs{0n}{#1}%
+ \else \@msg{\string\webfile{#1} ignored (out of order)}%
+ \fi}
+\def\changefile#1{% define a changefile
+ \ifnum\@nch<\z@
+ \@msg{\string\changefile{#1} ignored (missing \string\webfile)}%
+ \else \ifnum\@nch>8 \@msg{\string\changefile{#1} ignored (too many)}%
+ \else \advance\@nch\@ne \@dcs{\number\@nch n}{#1}%
+ \fi \fi}
+\def\outfile#1{% define outfile and process
+ \ifnum\@nch<\@ne
+ \@msg{\string\outfile{#1} ignored (missing \string\changefile)}%
+ \else \def\o@n{#1}\@init \@merge \@done
+ \fi}
+\def\@init{% initialize
+ \@msg{}\@msg{webmerge \fileversion\space <\filedate>}%
+ \immediate\openout\o@w=\o@n
+ \o@o{\@pct This is \o@n, a WEB change file produced by webmerge.tex}%
+ \begingroup
+ \def\do##1{\catcode`##1=12 }\dospecials
+ \ifallowtabs \allowtabs \else \forbidtabs \fi
+ \endlinechar=\m@ne
+ \count@\z@
+ \loop \edef\@i{\number\count@}\@@init
+ \ifnum\count@<\@nch \advance\count@\@ne \let\@ii\@i
+ \repeat
+ \o@o{}%
+ \@msg{out=\o@n, merging ...}}
+%
+% Here now is the quite complicated macro \@@init
+% its main purpose is to dynamically construct
+% the macro \<i>read that returns the next line of web_<i> in \@web
+% as well as various auxiliary macros \<i>...
+%
+\def\@@init{% initialize input file <i>
+ \edef\x{% define \read streams and \count registers
+ \noexpand\@nrd\@ncsi r% \newread\<i>r
+ \noexpand\@nct\@ncsi l% \newcount\<i>l (line number)
+ \noexpand\@nct\@ncsi s% \newcount\<i>s (status)
+ }\x \@csi l\z@ \@csi s\z@ % \<i>l=0 \<i>s=0
+ \openin\@csi r\@csi n % \openin\<i>r=\<i>n
+ \@msg{\ifeof\@csi runable to open input file
+ \else \ifnum\@i=\z@ web\else change \@i\fi =\fi \@csi n}%
+ \ifnum\count@=\z@ % <i>=0 for web file
+ \let\@web\relax
+%%
+%% \def\0w{% return web_0 line (file not yet ended)
+%% \read\0r to\@web \0s=0 % read from web_0, mark as unchanged
+%% \ifeof\0r \0e \else \advance\0l by 1 \fi}
+%%
+ \@ecsi w{% return web_0 line (file not yet ended)
+ \read\@csi rto\@web \@csi s\z@
+ \@ifeof \@ncsi e\@else \advance\@csi l\@ne \@fi}%
+%%
+%% \def\0e{% return web_0 line (file has ended)
+%% \let\0read=\0e \let\@web=\relax}
+%%
+ \@ecsi e{% return web_0 line (file has ended)
+ \let\@ncsi{read}\@ncsi e\let\@web\relax}%
+%%
+%% \ifeof\0r \0e \else \let\0read=\0w
+%%
+ \ifeof\@csi r\@csi e%
+ \else \edef\x{\let\@ncsi{read}\@ncsi w}\x
+ \fi
+ \o@o{\@pct to be applied to \@csi n}%
+ \o@o{\@pct combining the changes (one after the other) from}%
+ \else % <i>=1,2,3,... for change files
+ \o@o{\@pct \@i. \@csi n}%
+%%
+%% \def\<i>g#1{% read change file and test for @x/@y/@z
+%% \ifeof\<i>r \let\<i>x=\relax \@res=#1
+%% \else \@res=0 \read\<i>r to\<i>x
+%% \advance\<i>l by 1 \expandafter\@test\<i>x ab\@#1<i>
+%% \fi}
+%%
+ \@ecsi g##1{% read change file and test for @x/@y/@z
+ \@ifeof \let\@ncsi x\relax \@res##1%
+ \@else \@res\z@ \read\@csi rto\@ncsi x%
+ \advance\@csi l\@ne \@expa\@test\@ncsi xab\noexpand\@##1\@i
+ \@fi}%
+%%
+%% \def\<i>w{% return web_i line (changing is false)
+%% \<i-1>read % get web_<i-1> line
+%% \ifx\@web\<i>x % test for match
+%% \expandafter\<i>match % match lines from web_i-i and ch_i
+%% \fi} % else return web_<i-1> line
+%%
+ \@ecsi w{% return web_i line (changing is false)
+ \@read \@ifx\@web\@ncsi x\@expai{match}\@fi}%
+%%
+%% \def\<i>c{% return web_i line (changing is true)
+%% \<i>g 3 % get ch_i line and test for @z
+%% \ifnum\@res=3 % @z found
+%% \@echg <i> % deactivate a change
+%% \<i>prime % prime the change buffer
+%% \expandafter\<i>read % read again, now from web_<i-1>
+%% \else \@mod\<i>x % return ch_i line, mark as changed (\0s=1)
+%% \fi}
+%%
+ \@ecsi c{% return web_i line (changing is true)
+ \@ncsi g\thr@@
+ \@ifnum\@res=\thr@@
+ \noexpand\@echg\@i \@ncsi{prime}\@expai{read}%
+ \@else \noexpand\@mod\@ncsi x%
+ \@fi}%
+%%
+%% \def\<i>e{% return web_i line (change file has ended)
+%% \<i-1>read} % return web_<i-1> line
+%%
+ \@ecsi e{% return web_i line (change file has ended)
+ \@read}%
+%%
+%% \def\<i>prime{% prime the change buffer
+%% \loop
+%% \<i>g 1 % get ch_i line and test for @x
+%% \ifnum\@res=1 \else \repeat % repeat until found
+%% \loop
+%% \<i>g 0 % get ch_i line
+%% \ifx\<i>x\empty \repeat % repeat until not blank line
+%% \ifx\<x>\relax \let\<i>read=\<i>e % change file has ended
+%% \else \let\<i>read=\<i>w %
+%%
+ \@ecsi{prime}{% prime the change buffer
+ \@loop \@ncsi g\@ne \@ifnum\@res=\@ne \@else \@repeat
+ \@loop \@ncsi g\z@ \@ifx\@ncsi x\noexpand\empty \@repeat
+ \@ifx\@ncsi x\relax \let\@ncsi{read}\@ncsi e%
+ \@else \let\@ncsi{read}\@ncsi w%
+ \@fi}%
+%%
+%% \def\<i>match{% match lines from web_<i-1> and ch_<i>
+%% \ifx\@web\relax % web_<i-1> and ch_<i> have ended
+%% \let\<i>read=\<i>e \<i> % indicate web_<i> has ended
+%% \else \@bchg % activate a change
+%% \loop \@chg % write a matching line to output (maybe)
+%% \<i>g 2 % get ch_i line and test for @y
+%% \ifnum\@res=2 \@endm <i> % end of match found
+%% \else \<i-1>read % get web_<i-1> line
+%% \ifx\@web\relax % test for end of web file
+%% \@err <i>{Web file ended during change}
+%% \fi
+%% \ifx\@web\<i>x % test for matching lines
+%% \else \advance\<i>s by 1 \fi % count mismatches
+%% \repeat
+%% \let\<i>read=\<i>c % now changing is true
+%% \fi
+%% \<i>read} % get next web_<i> line again
+%%
+ \@ecsi{match}{% match lines from web_<i-1> and ch_<i>
+ \@ifx\@web\relax
+ \let\@ncsi{read}\@ncsi e%
+ \@else \noexpand\@bchg
+ \@loop \noexpand\@chg \@ncsi g\tw@
+ \@ifnum\@res=\tw@ \noexpand\@endm\@i%
+ \@else \@read
+ \@ifx\@web\relax
+ \noexpand\@err\@i{Web file ended during change}%
+ \@fi
+ \@ifx\@web\@ncsi x\@else \advance\@csi s\@ne \@fi
+ \@repeat
+ \let\@ncsi{read}\@ncsi c%
+ \@fi
+ \@ncsi{read}}%
+%%
+%% \<i>prime % prime the change buffer
+%%
+ \@csi{prime}% prime the change buffer
+ \fi}
+\def\@done{%terminate
+ \count@\z@
+ \loop \edef\@i{\number\count@}%
+ \ifnum\count@=\z@ \else % change file
+ \ifeof\@csi r\else \@@err{Change file entry didn't match}\fi
+ \fi
+ \closein\@csi r% close input file <i>
+ \ifnum\count@<\@nch \advance\count@\@ne
+ \repeat
+ \endgroup
+ \immediate\closeout\o@w
+ \@nch\m@ne % prepare for next \webfile
+ \@msg{... done}\@msg{}}
+
+\catcode`\0=11 % for \0s
+\def\@merge{% process
+ \@num\z@
+ \expandafter\loop\csname\number\@nch read\endcsname % read web_<n>
+ \ifnum\0s=\@ne \t@o{\@web}\fi
+ \ifx\@web\relax
+ \else
+ \repeat}
+\def\@chg{\ifnum\0s=\z@ \o@o{\@web}\fi}
+\def\@mod{\0s\@ne \let\@web}
+\catcode`\0=12
+
+\def\@err#1{\def\@i{#1}\@@err}
+\def\@@err#1{\@msg{! #1}%
+ \@msg{ ... change file \@i\space (\@csi n) line \the\@csi l}}
+
+\def\@test#1#2#3\@{\if#1@ \csname set@#2\endcsname \fi \@eat}
+\def\@eat#1#2{}
+\def\set@x{\@res\@ne \expandafter\@xyz}
+\def\set@y{\@res\tw@ \expandafter\@xyz}
+\def\set@z{\@res\thr@@ \expandafter\@xyz}
+\let\set@X=\set@x
+\let\set@Y=\set@y
+\let\set@Z=\set@z
+\def\@xyz\@eat#1#2{%
+ \ifnum#1=\@res
+ \else \@err#2{Extra \@@xyz{\@res} ignored (expecting \@@xyz#1)}%
+ \@res\z@
+ \fi}
+\def\@@xyz#1{@\ifcase#1\or x\or y\or z\fi}
+
+\def\@endm#1{%
+ \ifnum\csname#1s\endcsname>\z@
+ \@err#1{Hmm... \the\@csi s of the preceding lines failed to match}%
+ \fi
+ \csname#1s\endcsname\z@}
+
+\def\@bchg{% activate a change
+ \ifnum\@num=\z@ % first change activated, start writing to temp
+ \immediate\openout\t@w=\t@n\space
+ \o@o{@x l.\number\csname 0l\endcsname}
+ \fi
+ \advance\@num\@ne}
+\def\@echg#1{% deactivate a change
+ \expandafter\ifx\csname#1x\endcsname\relax
+ \@err#1{Change file ended during change}%
+ \fi
+ \advance\@num\m@ne
+ \ifnum\@num=\z@ % last change deactivated
+ \t@o{@z}%
+ \immediate\closeout\t@w % close temp file
+ \openin\t@r=\t@n\space
+ \o@o{@y}
+ \loop \read\t@r to\t@x \o@o{\t@x}% copy temp to output
+ \ifeof\t@r \closein\t@r
+ \else
+ \repeat
+ \fi}
+
+\@nch=\m@ne
+
+\catcode`\@=12 % at signs are no longer letters
+
+\endinput