summaryrefslogtreecommitdiff
path: root/support/makeprog
diff options
context:
space:
mode:
Diffstat (limited to 'support/makeprog')
-rw-r--r--support/makeprog/copying249
-rw-r--r--support/makeprog/docu/mkprgdoc.bbl38
-rw-r--r--support/makeprog/docu/mkprgdoc.tex408
-rw-r--r--support/makeprog/docu/primes.web414
-rw-r--r--support/makeprog/docu/web.tex1482
-rw-r--r--support/makeprog/docu/webmac.tex200
-rw-r--r--support/makeprog/dos/makeprog.cf158
-rw-r--r--support/makeprog/dos/makeprog.cf2140
-rw-r--r--support/makeprog/dos/makeprog.cf3230
-rw-r--r--support/makeprog/dos/makeprog.chf349
-rw-r--r--support/makeprog/filelist29
-rw-r--r--support/makeprog/history14
-rw-r--r--support/makeprog/readme44
-rw-r--r--support/makeprog/src/doc2tex.l122
-rw-r--r--support/makeprog/src/makeprog.web1171
-rw-r--r--support/makeprog/src/progdoc.doc668
-rw-r--r--support/makeprog/src/progdoc.tex217
-rw-r--r--support/makeprog/src/progltx.doc739
-rw-r--r--support/makeprog/src/progltx.sty194
-rw-r--r--support/makeprog/src/tex2doc.l12
-rw-r--r--support/makeprog/webtoc/convert6
-rw-r--r--support/makeprog/webtoc/makefile49
-rw-r--r--support/makeprog/webtoc/makepext.c91
-rw-r--r--support/makeprog/webtoc/makeprog.c675
-rw-r--r--support/makeprog/webtoc/makeprog.ch475
-rw-r--r--support/makeprog/webtoc/makeprog.h3
-rw-r--r--support/makeprog/webtoc/web2c.def100
-rw-r--r--support/makeprog/webtoc/web2c.h52
28 files changed, 8229 insertions, 0 deletions
diff --git a/support/makeprog/copying b/support/makeprog/copying
new file mode 100644
index 0000000000..9a17037581
--- /dev/null
+++ b/support/makeprog/copying
@@ -0,0 +1,249 @@
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 1, February 1989
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The license agreements of most software companies try to keep users
+at the mercy of those companies. By contrast, our General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. The
+General Public License applies to the Free Software Foundation's
+software and to any other program whose authors commit to using it.
+You can use it for your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Specifically, the General Public License is designed to make
+sure that you have the freedom to give away or sell copies of free
+software, that you receive source code or can get it if you want it,
+that you can change the software or use pieces of it in new free
+programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of a such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must tell them their rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any program or other work which
+contains a notice placed by the copyright holder saying it may be
+distributed under the terms of this General Public License. The
+"Program", below, refers to any such program or work, and a "work based
+on the Program" means either the Program or any work containing the
+Program or a portion of it, either verbatim or with modifications. Each
+licensee is addressed as "you".
+
+ 1. You may copy and distribute verbatim copies of the Program's source
+code as you receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice and
+disclaimer of warranty; keep intact all the notices that refer to this
+General Public License and to the absence of any warranty; and give any
+other recipients of the Program a copy of this General Public License
+along with the Program. You may charge a fee for the physical act of
+transferring a copy.
+
+ 2. You may modify your copy or copies of the Program or any portion of
+it, and copy and distribute such modifications under the terms of Paragraph
+1 above, provided that you also do the following:
+
+ a) cause the modified files to carry prominent notices stating that
+ you changed the files and the date of any change; and
+
+ b) cause the whole of any work that you distribute or publish, that
+ in whole or in part contains the Program or any part thereof, either
+ with or without modifications, to be licensed at no charge to all
+ third parties under the terms of this General Public License (except
+ that you may choose to grant warranty protection to some or all
+ third parties, at your option).
+
+ c) If the modified program normally reads commands interactively when
+ run, you must cause it, when started running for such interactive use
+ in the simplest and most usual way, to print or display an
+ announcement including an appropriate copyright notice and a notice
+ that there is no warranty (or else, saying that you provide a
+ warranty) and that users may redistribute the program under these
+ conditions, and telling the user how to view a copy of this General
+ Public License.
+
+ d) You may charge a fee for the physical act of transferring a
+ copy, and you may at your option offer warranty protection in
+ exchange for a fee.
+
+Mere aggregation of another independent work with the Program (or its
+derivative) on a volume of a storage or distribution medium does not bring
+the other work under the scope of these terms.
+
+ 3. You may copy and distribute the Program (or a portion or derivative of
+it, under Paragraph 2) in object code or executable form under the terms of
+Paragraphs 1 and 2 above provided that you also do one of the following:
+
+ a) accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of
+ Paragraphs 1 and 2 above; or,
+
+ b) accompany it with a written offer, valid for at least three
+ years, to give any third party free (except for a nominal charge
+ for the cost of distribution) a complete machine-readable copy of the
+ corresponding source code, to be distributed under the terms of
+ Paragraphs 1 and 2 above; or,
+
+ c) accompany it with the information you received as to where the
+ corresponding source code may be obtained. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form alone.)
+
+Source code for a work means the preferred form of the work for making
+modifications to it. For an executable file, complete source code means
+all the source code for all modules it contains; but, as a special
+exception, it need not include source code for modules which are standard
+libraries that accompany the operating system on which the executable
+file runs, or for standard header files or definitions files that
+accompany that operating system.
+
+ 4. You may not copy, modify, sublicense, distribute or transfer the
+Program except as expressly provided under this General Public License.
+Any attempt otherwise to copy, modify, sublicense, distribute or transfer
+the Program is void, and will automatically terminate your rights to use
+the Program under this License. However, parties who have received
+copies, or rights to use copies, from you under this General Public
+License will not have their licenses terminated so long as such parties
+remain in full compliance.
+
+ 5. By copying, distributing or modifying the Program (or any work based
+on the Program) you indicate your acceptance of this license to do so,
+and all its terms and conditions.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the original
+licensor to copy, distribute or modify the Program subject to these
+terms and conditions. You may not impose any further restrictions on the
+recipients' exercise of the rights granted herein.
+
+ 7. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of the license which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+the license, you may choose any version ever published by the Free Software
+Foundation.
+
+ 8. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to humanity, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these
+terms.
+
+ To do so, attach the following notices to the program. It is safest to
+attach them to the start of each source file to most effectively convey
+the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19xx name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the
+appropriate parts of the General Public License. Of course, the
+commands you use may be called something other than `show w' and `show
+c'; they could even be mouse-clicks or menu items--whatever suits your
+program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ program `Gnomovision' (a program to direct compilers to make passes
+ at assemblers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/support/makeprog/docu/mkprgdoc.bbl b/support/makeprog/docu/mkprgdoc.bbl
new file mode 100644
index 0000000000..b7715448b2
--- /dev/null
+++ b/support/makeprog/docu/mkprgdoc.bbl
@@ -0,0 +1,38 @@
+\begin{thebibliography}{1}
+
+\bibitem{gnu:license}
+Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+\newblock {\em {GNU} General Public License}, February 1989.
+\newblock Version 1.
+
+\bibitem{kg-wr:tie}
+Klaus Guntermann and Wolfgang R{\"u}lling.
+\newblock Another approach to multiple changefiles.
+\newblock {\em TUGboat}, 7(3):134, 1986.
+
+\bibitem{kg-js:cweb}
+Klaus Guntermann and Joachim Schrod.
+\newblock {\WEB} adapted to {C}.
+\newblock {\em TUGboat}, 7(3):134--137, 1986.
+
+\bibitem{knuth:web}
+Donald~E. Knuth.
+\newblock The {\WEB} system of structured documentation.
+\newblock Computer Science Report CS980, Stanford University, 1983.
+
+\bibitem{knuth:literate}
+Donald~E. Knuth.
+\newblock Literate programming.
+\newblock {\em The Computer Journal}, 27(1):97--111, 1984.
+
+\bibitem{mittelbach:doc}
+Frank Mittelbach.
+\newblock The {\tt doc\/} style option.
+\newblock {\em TUGboat}, 10(2):245--273, 1989.
+
+\bibitem{ramsey:spider}
+Norman Ramsey.
+\newblock Weaving a language-independent {\WEB}.
+\newblock {\em Communications of the ACM}, 32(9):1051--1055, 1989.
+
+\end{thebibliography}
diff --git a/support/makeprog/docu/mkprgdoc.tex b/support/makeprog/docu/mkprgdoc.tex
new file mode 100644
index 0000000000..83ef7852e3
--- /dev/null
+++ b/support/makeprog/docu/mkprgdoc.tex
@@ -0,0 +1,408 @@
+% mkprgdoc.tex 06 Oct 90
+%------------------------------------------------------------
+% (c) 1988-1990 by J.Schrod.
+
+%
+% documentation for the MAKEPROG system
+% LaTeX
+%
+
+%
+% VERSION HISTORY
+%
+% DATE WHO REMARK
+% 90-10-06 js added hint to doc2tex and tex2doc.
+% MAKEPROG will be available at tuglib.
+% 90-09-21 js new progdoc, progltx mentioned everywhere.
+% 90-06-11 js rewritten in LaTeX.
+% 89-02-01 js updated with comments of Klaus Guntermann.
+% 88-12-05 js first version (for ftp/Bitnet).
+
+% author:
+% js: Joachim Schrod <xitijsch@ddathd21.bitnet>
+% contributors:
+% (-: place enough for your name! :-)
+
+
+
+
+\documentstyle{article}
+
+
+%\advance\textheight by \baselineskip
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% local macros
+%
+
+\makeatletter
+
+
+% fonts
+
+\let\mc=\small % medium caps for acronyms
+\font\tentex=cmtex10 % typewriter extended ASCII 10pt
+\let\ttex=\tentex
+
+
+% short hands
+
+\def\MAKEPROG{{\mc MAKEPROG}}
+\def\CWEB{{\mc CWEB\/}}
+\def\WEB{{\tt WEB\/}}
+\def\TANGLE{{\tt TANGLE\/}}
+\def\WEAVE{{\tt WEAVE\/}}
+\def\TIE{{\tt TIE\/}}
+\def\DVI{{\tt DVI\/}}
+\def\spider{{\tt SpiderWEB\/}}
+
+
+% footnotes on the titlepage without any marker
+
+\def\titlenote#1{%
+ \begingroup
+ \def\@makefntext##1{\noindent ##1}%
+ \footnotetext{%
+ \interlinepenalty\@M
+ \ignorespaces #1%
+ }%
+ \endgroup
+ }
+
+
+% |...| verbatim from progdoc.doc. look there for the explanations.
+
+\catcode`\|=\active
+\def|{%
+ \leavevmode
+ \hbox\bgroup
+ \let\par\space \setupverb@tim
+ \let|\egroup
+ }
+\def\setupverb@tim{%
+ \let\do\@makeother \dospecials
+ \parskip\z@skip \parindent\z@
+ \obeylines \obeyspaces \frenchspacing
+ \ttex
+ }
+
+% an inch symbol
+
+\def\inch{{\tt "\/}}
+
+
+
+\makeatother
+
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+
+\begin{document}
+
+
+
+\title{The MAKEPROG System of Documentation}
+\author{Joachim Schrod}
+
+\date{October 1990}
+
+%%%%% moved below after footnotes -- the titlenote should be on the
+%%%%% bottom of the page
+%
+%\titlenote{
+% \copyright{} Copyright 1988--1990 by Joachim Schrod.
+% All rights reserved.
+% }
+
+\maketitle
+
+
+
+\section{Introduction}
+
+In his article \cite{knuth:literate} {\sc D.~Knuth} has introduced
+the concept of {\it Literate Programming}. This concept focused on
+the following statement: ``Instead of imagining that our main task is
+to instruct a {\sl computer\/} what to do, let us concentrate rather
+on explaining to {\sl human beings\/} what we want a computer to
+do.'' To support this for Pascal programs he has created the {\sl
+\WEB{} system of structured documentation} \cite{knuth:web}, an
+extension of Pascal. In \WEB{} a program is splitted into sections,
+each section contains a documentation and a program part (both parts
+can be empty).%
+ \footnote{%
+ In fact there is a third part, the macro part, which is not
+ important in this context.
+ }
+ Such a \WEB{} program is transformed by the \TANGLE{} processor into
+a program source for the compiler and the \WEAVE{} processor produces
+an output which can be fed into \TeX{} to get a fine looking
+document. Both \TANGLE{} and \WEAVE{} support the inclusion of
+changefiles, with these files lines of text can be replaced by other
+lines.
+
+At the Technichal University of Darmstadt we have used this
+concept---with \CWEB{} \cite{kg-js:cweb}---in many of our projects,
+e.g.\ for our portable \DVI{} driver family. With the introduction of
+\spider{} made by {\sc N.~Ramsey} \cite{ramsey:spider} a \WEB{}
+generator became available which allows the generation of a new
+\WEB{} system for a specific language. But even with \spider{} not
+all languages may be supported because the lexical analysis is fixed
+to languages with tokens separated by white space. E.g.,
+prettyprinting \TeX{} macros is a non-trivial task due to \TeX's
+dynamic lexical analysis. Furthermore \spider{} does not run on as
+many computer systems as \WEB{} does because it is implemented in
+{\tt awk\/} that is not as widespread.%
+ \footnote{%
+ But please note that there exists {\tt gawk}, the {\tt awk\/}
+ implementation of the GNU project, which is free software and
+ may be ported to more systems.
+ }
+ (In my opinion this is one of the strongest drawbacks of \spider{},
+it should be rewritten in \WEB{} urgently.) Or people do not have
+enough time to generate a \WEB{} system even if they should do so if
+they plan to work longer with this specific formal language.
+
+\titlenote{\strut}
+\titlenote{
+ \copyright{} Copyright 1988--1990 by Joachim Schrod.
+ All rights reserved.
+ }
+
+To close this gap I have developed the \MAKEPROG{} system. It allows
+to document programs with \TeX{} in a \WEB{} like fashion, the
+program parts of the documentation file can be extracted to yield the
+program file. During the extraction process the documentation file
+can be altered with a changefile. Multiple changefiles may be used
+with the help of \TIE{}~\cite{kg-wr:tie}.
+
+The \MAKEPROG{} system consists of two parts: (1)~the \MAKEPROG{}
+processor which does the extraction and (2)~the macro files |progdoc|
+(for usage with Plain \TeX{}) or |progltx| (as an article style
+option with \LaTeX{}) which make formatting facilities available.
+The \MAKEPROG{} processor is derived from \TANGLE{}, therefore there
+should be no difficulties for any site running \WEB{} to install
+\MAKEPROG{}. The macros are implemented with \MAKEPROG{}, the files
+|progdoc.doc| resp.\ |progltx.doc| are the ultimate sources.
+|progdoc.tex| or |progltx.sty| is only delivered to allow the
+printing of |progdoc.doc|.
+
+
+
+\section{Distribution}
+
+\MAKEPROG{} is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published
+by the Free Software Foundation; either version~1, or (at your
+option) any later version.
+
+\MAKEPROG{} is distributed in the hope that it will be useful, but
+{\bf without any warranty\/}; without even the implied warranty of
+{\bf merchantability\/} or {\bf fitness for a particular purpose}. See
+the GNU General Public License~\cite{gnu:license} for more details.
+
+At the moment \MAKEPROG{} may be obtained from {\tt
+LISTSERV@DHDURZ1\/} (filelist {\tt WEBWARE\/}) for the Bitnet folks,
+from {\tt tuglib@science.utah.edu}, and it is included in the
+BSD/UNIX distribution of Pierre MacKay (so it may be available via
+anonymous ftp from {\tt june.cs.washington.edu}, too).
+
+If you want to get a floppy (DOS format, 5.25\inch{}~HD, 3.5\inch{}
+HD or~DD) with the \MAKEPROG{} system you may contact me. But please
+note that you will have to pay a handling charge of DM~40. (``When we
+speak of free software, we are referring to freedom, not
+price.''~\cite{gnu:license}) On my distribution disk is \MAKEPROG{},
+\TIE{}, and \WEB{}.
+
+
+
+\section{How to Use MAKEPROG}
+
+If you use \LaTeX{} you must include |progltx| as a document style
+option, if you use Plain \TeX{} you must include the macro file with
+|\input progdoc|. Afterwards you can structure your document into
+sections and the sections into groups. The first section of a group
+starts with |\chap|, it corresponds to the starred section (`|@*|')
+of a \WEB{} program. |\chap| has one parameter, the title of the
+section group. The parameter is ended by a dot. The dot is printed
+by the macro. Every other section starts with |\sect|. These macros
+produce a number in front of each section; this number is incremented
+with each new section. Of course, in \LaTeX{} you may use the normal
+\LaTeX{} sectioning markup if you prefer that one.
+
+Within a section one or more program part(s) can be specified with the
+macros |\beginprog| and |\endprog|. Both macros must start at the
+beginning of a line. If |\beginprog| does not start at the beginning
+of a line verbatim typesetting will be switched on but no extraction
+to the program file will result afterwards. After |\beginprog| the
+rest of the line is ignored. If |\endprog| does not start at the
+beginning of a line or if it is not followed by white space (blanks,
+tabs, or end of line) neither verbatim typesetting nor extracting will
+stop.
+
+Please note that even with \LaTeX{} |\beginprog| and |\endprog| must
+be used for the markup of the program parts, instead of
+|\begin{prog}| or |\end{prog}| which would be more ``\LaTeX{}-like.''
+The reason behind this is that I didn't want to maintain two versions
+of the \MAKEPROG{} processor---but \MAKEPROG{} wants to see the
+non-\LaTeX{}-like macros. But everybody is encouraged to change it by
+himself.
+
+Outside of the program part---in the so called documentation
+part---you can use the vertical bar to print small texts verbatim,
+e.g.\ identifiers, macro names, etc. A vertical bar starts the
+verbatim mode, the next vertical bar stops it.
+
+After you have finished writing your document you can print it with
+\TeX{} and you can run the \MAKEPROG{} processor to extract all
+program parts into a program file. During the extraction \MAKEPROG{}
+will recognize change files like \TANGLE{} does.
+
+
+
+\section{Bells and Whistles}
+
+Within the documentation part you can use |\origvert| to get an
+original vertical bar. |\vbar| is the character with the {\mc ASCII}
+representation of a vertical bar in the actual font.
+
+If you use Plain \TeX{} and |progdoc| you may change the appearance
+of the title page with the table of contents. This page is output as
+the last page and it's layout is like in \WEB{}. Before the table of
+contents the macro |\topofcontents| is executed. The default
+definition of this macro supplies the title and glue on the top. The
+header line above the table is typeset by |\HeaderToc|, each contents
+line is typeset by |\tocline|. You can change the definitions within
+|\topofcontents|. After the table the macro |\botofcontents| is
+executed which usually just supplies glue, but may be redefined to
+incorporate copyright notices etc.
+
+\smallskip
+
+If you document \TeX{} macros with \MAKEPROG{} and send them to
+people who don't have \MAKEPROG{} and if you have {\mc LEX\/}
+available, you may use |doc2tex| to transform the \MAKEPROG{} source
+into a \TeX{} source. All documentation parts are turned into \TeX{}
+comments and a paragraph is added which includes a hint to
+\MAKEPROG{}. |tex2doc| converts such a file back to a \MAKEPROG{}
+source.
+
+
+
+\section{Problems and Errors}
+
+The following deficiencies are known to me (some are not inherent
+but there wasn't the time to do it until now):
+ %
+ \begin{itemize}
+
+\item \MAKEPROG{} does not rearrange the code as \TANGLE{} does.
+This is the most important drawback. The support of stepwise
+refinement is one of \WEB{}'s main advantages.
+
+\item \MAKEPROG{} does not prettyprint the program part because it
+does not know anything about the target language and therefore
+nothing about the lexical and syntactical structure of the program.
+Instead it just prints the program part verbatim. But compared to
+wide spread macros which set text verbatim it has the advantage
+that you can print your program part if you have embedded tabs in it.
+The macros will replace every tab with one to eight spaces according
+to the current column.
+
+\item \MAKEPROG{} does not produce any index. This is impossible
+because it does not know what an identifier looks like. (This can
+even change inmidst a program, cf.~\TeX!)
+
+\item Because the documentation file is a \TeX{} file and \TeX{} does
+not recognize change files the complete documentation (with a change
+file) cannot be printed. \TIE{} must be used to create a new master
+file which can be printed afterwards.
+
+\item The page breaking is not satisfying in all cases. I still have
+to fiddle with the penalties.
+
+\item \MAKEPROG{} should insert the current date as a comment line in
+front of the produced program file. The syntax of the comment line
+(start and end of a comment) must be specifiable.
+
+\end{itemize}
+
+If you have found an error or if you have some remarks please contact
+me. I~prefer electronic mail and I will acknowledge your mail within
+a week. Send bug reports to:
+%
+ \begin{quote}
+ Detig$\,\cdot\,$Schrod \TeX{}sys\\
+ Joachim Schrod\\
+ Kranichweg 1\\[.5\baselineskip]
+ D-6074 R\"odermark-Urberach\\
+ FR Germany\\[.5\baselineskip]
+ Email: {\tt xitijsch@ddathd21.bitnet}
+ \end{quote}
+
+
+
+\section{Related Work}
+
+Frank Mittelbach and Rainer Sch\"opf have presented |doc|
+\cite{mittelbach:doc}, a \LaTeX{} style option for documenting
+\LaTeX{} styles. An accompanying \LaTeX{} input file (|docstrip|)
+strips these documents. Although their approach seems to be similar
+to the one presented here, it should be noticed that there are
+several important differences.
+
+At first |doc| was created for documenting \LaTeX{} macros, while
+\MAKEPROG{} was created to support the documentation of {\it formal
+representations which are processed by a computer}, e.g.\ programs.
+Therefore |doc| was able to supply specific (semantic dependent) help
+for automatic creation of an index and of marginal notes whereas
+\MAKEPROG{} must refer the user to the standard features available in
+\LaTeX{} or Plain \TeX{} because it has no knowledge about the
+semantic structure of the program.
+
+Furthermore \MAKEPROG{} supports the changefile mechanism which is
+rarely needed for the documentation of \TeX{} macros because \TeX{}
+is (almost) the same on all computer systems but programs in general
+must be adapted to local circumstances, i.e., system dependent stuff
+must be included.
+
+
+
+
+\appendix
+
+
+
+\section{Installation}
+
+The first step is to install the \MAKEPROG{} processor. Because it
+is derived from \TANGLE{} this should be rather easy. Just take your
+local \TANGLE{} change file and you should have very few alterations
+(perhaps much to delete). You will need to put the \MAKEPROG{}
+processor somewhere where your local command processor will find
+it---perhaps you will even need a command script around it. But this
+will be the same as it was with \TANGLE{}. (To ease the installation
+for many sites I have included changefiles for {\tt WEBtoC\/} and for
+Turbo Pascal.)
+
+You can test your new program by feeding |progdoc.doc| resp.\
+|progltx.doc| through it. The output must be identical to
+|progdoc.tex| resp.\ |progltx.sty|. Well, the main work is now done.
+You still have to put |progdoc.tex| and |progltx.sty| in directories
+where \TeX{} will find them and then have much fun. (Don't
+worry---be happy$\,\ldots$)
+
+
+
+
+\bibliographystyle{plain}
+\bibliography{web,gnu,tug}
+
+
+
+
+\end{document}
diff --git a/support/makeprog/docu/primes.web b/support/makeprog/docu/primes.web
new file mode 100644
index 0000000000..07554b0ef3
--- /dev/null
+++ b/support/makeprog/docu/primes.web
@@ -0,0 +1,414 @@
+% limbo material
+\font\ninerm=amr9
+\let\mc=\ninerm % medium caps for names like PASCAL
+\def\WEB{{\tt WEB}}
+\def\PASCAL{{\mc PASCAL}}
+\def\[{\ifhmode\ \fi$[\![$}
+\def\]{$]\!]$\ }
+\def\<{$\langle\,$}
+\def\>{$\,\rangle$}
+\def\Dijk{{2}} % unnecessary when combined with text of paper
+\def\goto{{3}} % ditto
+\hyphenation{Dijk-stra} % ditto
+\def\sec{{\tensy x}}
+\hsize=84mm
+
+@* Printing primes: An example of \WEB.
+The following program is essentially the same as Edsger Dijkstra's
+@^Dijkstra, Edsger@> ``first example of step-wise program composition,''
+found on pages 26--39 of his {\sl Notes on Structured Programming},$^{\Dijk}$
+but it has been translated into the \WEB\ language. @.WEB@>
+
+\[Double brackets will be used in what follows to enclose comments
+relating to \WEB\ itself, because the chief purpose of this program
+is to introduce the reader to the \WEB\ style of documentation.
+\WEB\ programs are always broken into small sections, each
+of which has a serial number; the present section is number~1.\]
+
+Dijkstra's program prints a table of the first thousand prime numbers. We
+shall begin as he did, by reducing the entire program to its top-level
+description. \[Every section in a \WEB\ program begins with optional {\it
+commentary\/} about that section, and ends with optional {\it program
+text\/} for the section. For example, you are now reading part of the
+commentary in \sec1, and the program text for \sec1 immediately follows
+the present paragraph. Program texts are specifications of \PASCAL\
+programs; they either use \PASCAL\ language directly, or they use angle
+brackets to represent \PASCAL\ code that appears in other sections. For
+example, the angle-bracket notation `\X2:Program to print $\ldots$
+numbers\X' is \WEB's way of saying the following: ``The \PASCAL\ text to
+be inserted here is called `Program to print $\ldots$ numbers', and you
+can find out all about it by looking at section~2.'' One of the main
+characteristics of \WEB\ is that different parts of the program are
+usually abbreviated, by giving them such an informal top-level
+description.\]
+
+@p @<Program to print the first thousand prime numbers@>
+
+@ This program has no input, because we want to keep it rather simple.
+The result of the program will be to produce a list of the first
+thousand prime numbers, and this list will appear on the |output| file.
+
+Since there is no input, we declare the value |m=1000| as a compile-time
+constant. The program itself is capable of generating the first
+|m| prime numbers for any positive |m|, as long as the computer's
+finite limitations are not exceeded.
+
+\[The program text below specifies the ``expanded meaning'' of `\X2:Program
+to print $\ldots$ numbers\X'; notice that it involves the top-level
+descriptions of three other sections. When those top-level descriptions
+are replaced by their expanded meanings, a syntactically correct \PASCAL\
+program will be obtained.\]
+
+@<Program to print...@>=
+program print_primes(output);
+const @!m=1000; @<Other constants of the program@>@;
+var @<Variables of the program@>@;
+begin @<Print the first |m| prime numbers@>;
+end.
+
+@* Plan of the program.
+We shall proceed to fill out the rest of the program by making whatever
+decisions seem easiest at each step; the idea will be to strive for
+simplicity first and efficiency later, in order to see where this leads us.
+The final program may not be optimum, but we want it to be reliable,
+well motivated, and reasonably fast.
+
+Let us decide at this point to maintain a table that includes all of the
+prime numbers that will be generated, and to separate the generation
+problem from the printing problem.
+
+\[The \WEB\ description you are reading once again follows a pattern that
+will soon be familiar: A typical section begins with comments and
+ends with program text. The comments motivate and explain noteworthy
+features of the program text.\]
+
+@<Print the first...@>=
+@<Fill table |p| with the first |m| prime numbers@>;
+@<Print table |p|@>
+
+@ How should table |p| be represented? Two possibilities suggest
+themselves: We could construct a sufficiently large array
+of boolean values in which the $k$th entry is |true| if and only if the
+number~|k| is prime; or we could build an array of integers in which
+the |k|th entry is the |k|th prime number. Let us choose the latter
+alternative, by introducing an integer array called |p[1..m]|.
+
+In the documentation below, the notation `|p[k]|' will refer to the
+|k|th element of array~|p|, while `$p_k$' will refer to the $k$th
+prime number. If the program is correct, |p[k]| will either be
+equal to $p_k$ or it will not yet have been assigned any value.
+
+\[Incidentally, our program will eventually make use of several
+more variables as we refine the data structures. All of the sections
+where variables are declared will be called `\X4:Variables of the
+program\X'; the number `{\eightrm4}' in this name refers to the
+present section, which is the first section to specify the
+expanded meaning of `\<Variables of the program\>'.
+The note `{\eightrm See also $\ldots$}' refers to all of the other
+sections that have the same top-level description. The expanded meaning of
+`\X4:Variables of the program\X' consists of all the program texts
+for this name, not just the text found in~\sec4.\]
+
+@<Variables...@>=@!p:array[1..m] of integer;
+ {the first |m| prime numbers, in increasing order}
+
+@* The output phase.
+Let's work on the second part of the program first. It's not as interesting
+as the problem of computing prime numbers; but the job of printing must be
+done sooner or later, and we might as well do it sooner, since it will
+be good to have it done. \[And it is easier to learn \WEB\ when reading a
+program that has comparatively few distracting complications.\]
+
+Since |p| is simply an array of integers, there is little difficulty
+in printing the output, except that we need to decide upon a suitable
+output format. Let us print the table on separate pages, with |rr| rows
+and |cc| columns per page, where every column is |ww| character positions
+wide. In this case we shall choose |rr=50|, |cc=4|, and |ww=10|, so that
+the first 1000 primes will appear on five pages. The program will
+not assume that |m| is an exact multiple of $|rr|\cdot|cc|$.
+@^output format@>
+
+@<Other constants...@>=
+@!rr=50; {this many rows will be on each page in the output}
+@!cc=4; {this many columns will be on each page in the output}
+@!ww=10; {this many character positions will be used in each column}
+
+@ In order to keep this program reasonably free of notations that
+are uniquely \PASCAL esque, \[and in order to illustrate more of the
+facilities of \WEB,\] a few macro definitions for low-level output
+instructions are introduced here. All of the output-oriented commands
+in the remainder of the program will be stated in terms of five
+simple primitives called |print_string|, |print_integer|, |print_entry|,
+|new_line|, and |new_page|.
+
+\[Sections of a \WEB\ program are allowed to contain {\it macro definitions\/}
+between the opening comments and the closing program text. The
+general format for each section is actually tripartite: commentary,
+then definitions, then program. Any of the three parts may be absent;
+for example, the present section contains no program text.\]
+
+\[Simple macros simply substitute a bit of \PASCAL\ code for an
+identifier. Parametric macros are similar, but they also substitute
+an argument wherever `\#' occurs in the macro definition. The first three
+macro definitions here are parametric; the other two are simple.\]
+
+@d print_string(#)==write(#) {put a given string into the |output| file}
+@d print_integer(#)==write(#:1) {put a given integer into the |output|
+ file, in decimal notation, using only as many digit positions as necessary}
+@d print_entry(#)==write(#:ww) {like |print_integer|, but |ww| character
+ positions are filled, inserting blanks at the left}
+@d new_line==write_ln {advance to a new line in the |output| file}
+@d new_page==page {advance to a new page in the |output| file}
+
+@ Several variables are needed to govern the output process. When we begin
+to print a new page, the variable |page_number| will be the ordinal number
+of that page, and |page_offset| will be such that |p[page_offset]| is the
+first prime to be printed. Similarly, |p[row_offset]| will be the first
+prime in a given row.
+
+\[Notice the notation `$+\S$' below; this indicates that the present
+section has the same name as a previous section, so the program text
+will be appended to some text that was previously specified.\]
+
+@<Variables...@>=
+@!page_number:integer; {one more than the number of pages printed so far}
+@!page_offset:integer; {index into |p| for the first entry on the current page}
+@!row_offset:integer; {index into |p| for the first entry in the current row}
+@!c:0..cc; {runs through the columns in a row}
+
+@ Now that appropriate auxiliary variables have been introduced, the process
+of outputting table~|p| almost writes itself.
+
+@<Print table |p|@>=
+begin page_number:=1; page_offset:=1;
+while page_offset<=m do
+ begin @<Output a page of answers@>;
+ page_number:=page_number+1;
+ page_offset:=page_offset+rr*cc;
+ end;
+end
+
+@ A simple heading is printed at the top of each page.
+@^output format@> @^page headings@>
+
+@<Output a page of answers@>=
+begin print_string('The First ');
+print_integer(m);@/
+print_string(' Prime Numbers --- Page ');
+print_integer(page_number);
+new_line; new_line; {there's a blank line after the heading}
+for row_offset:=page_offset to page_offset+rr-1 do
+ @<Output a line of answers@>;
+new_page;
+end
+
+@ The first row will contain
+$$\hbox{|p[1]|, |p[1+rr]|, |p[1+2*rr]|, \dots;}$$
+a similar pattern holds for each value of the |row_offset|.
+
+@<Output a line of answers@>=
+begin for c:=0 to cc-1 do
+ if row_offset+c*rr<=m then print_entry(p[row_offset+c*rr]);
+new_line;
+end
+
+@* Generating the primes.
+The remaining task is to fill table~|p| with the correct numbers.
+Let us do this by generating its entries one at a time: Assuming that
+we have computed all primes that are |j|~or less, we will advance |j|
+to the next suitable value, and continue doing this until the
+table is completely full.
+
+The program includes a provision to initialize the variables in certain
+data structures that will be introduced later.
+
+@<Fill table |p|...@>=
+@<Initialize the data structures@>;
+while k<m do
+ begin @<Increase |j| until it is the next prime number@>;
+ k:=k+1; p[k]:=j;
+ end
+
+@ We need to declare the two variables |j| and~|k| that were just
+introduced.
+
+@<Variables...@>=
+@!j:integer; {all primes |<=j| are in table |p|}
+@!k:0..m; {this many primes are in table |p|}
+
+@ So far we haven't needed to confront the issue of what a prime number
+is. But everything else has been taken care of, so we must delve into
+a bit of number theory now.
+
+By definition, a number is called prime if it is an integer greater
+than~1 that is not evenly divisible by any smaller prime number. Stating
+this another way, the integer |j>1| is not prime if and only if there
+exists a prime number $p_n<j$ such that |j| is a multiple of~$p_n$.
+@^prime number, definition of@>
+
+Therefore the section of the program that is called `\<Increase |j| until
+it is the next prime number\>' could be coded very simply:
+`\ignorespaces|repeat j:=j+1;|\unskip\
+\<Give to~|j_prime| the meaning: |j|~is a prime number\>;
+\ignorespaces|until j_prime|\unskip'.
+And to compute the boolean value |j_prime|, the following
+would suffice: `\ignorespaces|j_prime:=true; for n:=1 to k do|\unskip\
+\<If |p[n]| divides |j|, set |j_prime:=false|\>'.
+
+@ However, it is possible to obtain a much more efficient algorithm by
+using more facts of number theory. In the first place, we can speed
+things up a bit by recognizing that $p_1=2$ and that all subsequent
+primes are odd; therefore we can let |j| run through odd values only.
+Our program now takes the following form:
+
+@<Increase |j| until...@>=
+repeat j:=j+2; @<Update variables that depend on~|j|@>;
+@<Give to |j_prime| the meaning: |j|~is a prime number@>;
+until j_prime
+
+@ The |repeat| loop in the previous section introduces a boolean
+variable |j_prime|, so that it will not be necessary to resort to
+a |goto| statement. (We are following Dijkstra,$^\Dijk$ not Knuth.$^\goto$)
+@^Dijkstra, Edsger@> @^Knuth, Donald E.@>
+
+@<Variables...@>=
+@!j_prime:boolean; {is |j| a prime number?}
+
+@ In order to make the odd-even trick work, we must of course initialize
+the variables |j|, |k|, and |p[1]| as follows.
+
+@<Init...@>=
+j:=1; k:=1; p[1]:=2;
+
+@ Now we can apply more number theory in order to obtain further
+economies. If |j| is not prime, its smallest prime factor $p_n$ will
+be $\sqrt j$ or less. Thus if we know a number |ord| such that
+$$p[|ord|]^2>j,$$ and if |j| is odd, we need only test for divisors
+in the set $\{p[2], \ldots, p[|ord|-1]\}$. This is much faster than
+testing divisibility by $\{p[2],\ldots,p[k]\}$, since |ord| tends
+to be much smaller than~|k|. \ (Indeed, when |k| is large, the
+celebrated ``prime number theorem'' implies that the value of |ord|
+will be approximately $2\sqrt{k/\!\ln k}$.)
+
+Let us therefore introduce |ord| into the data structure. A moment's
+thought makes it clear that |ord| changes in a simple way when |j|
+increases, and that another variable |square| facilitates the
+updating process.
+
+@<Variables...@>=
+@!ord:2..ord_max; {the smallest index |>=2| such that $p_{ord}^2>j$}
+@!square:integer; {$|square|=p_{ord}^2$}
+
+@ @<Init...@>=
+ord:=2; square:=9;
+
+@ The value of |ord| will never get larger than a certain value
+|ord_max|, which must be chosen sufficiently large. It turns out that
+|ord| never exceeds~30 when |m=1000|.
+
+@<Other const...@>=
+@!ord_max=30; {$p_{ord\_max}^2$ must exceed $p_m$}
+
+@ When |j| has been increased by~2, we must increase |ord| by unity
+when $j=p_{ord}^2$, i.e., when |j=square|.
+
+@<Update variables that depend on~|j|@>=
+if j=square then
+ begin ord:=ord+1;
+ @<Update variables that depend on~|ord|@>;
+ end
+
+@ At this point in the program, |ord| has just been increased by unity,
+and we want to set $|square|:=p_{ord}^2$. A surprisingly subtle point
+arises here: How do we know that $p_{ord}$ has already been computed,
+i.e., that |ord<=k|? If there were a gap in the sequence of prime numbers,
+such that $p_{k+1}>p_k^2$ for some~$k$, then this part of the program would
+refer to the yet-uncomputed value |p[k+1]| unless some special test were
+made.
+
+Fortunately, there are no such gaps. But no simple proof of this fact is
+known. For example, Euclid's famous demonstration that there are
+infinitely many prime numbers is strong enough to prove only that
+$p_{k+1}<=p_1\ldots p_k+1$. Advanced books on number theory come to our
+rescue by showing that much more is true; for example, ``Bertrand's
+postulate'' @^Bertrand, Joseph, postulate@> states that $p_{k+1}<2p_k$
+for all~$k$.
+
+@<Update variables that depend on~|ord|@>=
+square:=p[ord]*p[ord]; {at this point |ord<=k|}
+
+@* The inner loop.
+Our remaining task is to determine whether or not a given integer~|j| is prime.
+The general outline of this part of the program is quite simple,
+using the value of |ord| as described above.
+
+@<Give to |j_prime|...@>=
+n:=2; j_prime:=true;
+while (n<ord) and j_prime do
+ begin @<If |p[n]| is a factor of~|j|, set |j_prime:=false|@>;
+ n:=n+1;
+ end
+
+@ @<Var...@>=
+@!n:2..ord_max; {runs from 2 to |ord| when testing divisibility}
+
+@ Let's suppose that division is very slow or nonexistent on our
+machine. We want to detect nonprime odd numbers, which are odd multiples
+of the set of primes $\{p_2,\ldots,p_{ord}\}$.
+
+Since |ord_max| is small, it is reasonable to maintain an auxiliary table of
+the smallest odd multiples that haven't already been used to show that
+some~|j| is nonprime. In other words, our goal is to ``knock out'' all
+of the odd multiples of each $p_n$ in the set $\{p_2,\ldots,p_{ord}\}$,
+and one way to do this is to introduce an auxiliary table that serves as
+a control structure for a set of knock-out procedures that are being
+simulated in parallel. (The so-called ``sieve of Eratosthenes''
+@^Eratosthenes, sieve of@> generates primes by a similar method, but
+it knocks out the multiples of each prime serially.)
+
+The auxiliary table suggested by these considerations is a |mult|
+array that satisfies the following invariant condition: For |2<=n<ord|,
+|mult[n]| is an odd multiple of $p_n$ such that $|mult|[n]<j+2p_n$.
+
+@<Var...@>=
+@!mult:array[2..ord_max] of integer; {runs through multiples of primes}
+
+@ When |ord| has been increased, we need to initialize a new element of
+the |mult| array. At this point $j=p[|ord|-1]^2$, so there is no
+need for an elaborate computation.
+
+@<Update variables that depend on~|ord|@>=
+mult[ord-1]:=j;
+
+@ The remaining task is straightforward, given the data structures
+already prepared. Let us recapitulate the current situation: The
+goal is to test whether or not |j|~is divisible by~$p_n$, without
+actually performing a division. We know that $j$~is odd, and that
+|mult[n]| is an odd multiple of~$p_n$ such that $|mult|[n]<j+2p_n$.
+If |mult[n]<j|, we can increase |mult[n]| by $2p_n$ and the same
+conditions will hold. On the other hand if |mult[n]>=j|, the
+conditions imply that |j|~is divisible by~$p_n$ if and only if
+|j=mult[n]|.
+
+@<If...@>=
+while mult[n]<j do mult[n]:=mult[n]+p[n]+p[n];
+if mult[n]=j then j_prime:=false
+
+@* Index.
+Every identifier used in this program is shown here together with a list
+of the section numbers where that identifier appears. The section number
+is underlined if the identifier was defined in that section. However,
+one-letter identifiers are indexed only at their point of definition,
+since such identifiers tend to appear almost everywhere. \[An index like
+this is prepared automatically by the \WEB\ software, and it is appended
+to the final section of the program. However, underlining of section
+numbers is not automatic; the user is supposed to mark identifiers
+at their point of definition in the \WEB\ source file.\]
+
+This index also refers to some of the places where key elements of the
+program are treated. For example, the entries for `Output format' and
+`Page headings' indicate where details of the output format are
+discussed. Several other topics that appear in the documentation
+(e.g., `Bertrand's postulate') have also been indexed. \[Special
+instructions within a \WEB\ source file can be used to insert
+essentially anything into the index.\]
diff --git a/support/makeprog/docu/web.tex b/support/makeprog/docu/web.tex
new file mode 100644
index 0000000000..aba26ddcb8
--- /dev/null
+++ b/support/makeprog/docu/web.tex
@@ -0,0 +1,1482 @@
+% Page layout
+\input webmac
+\output{\setbox0=\box255}\eject % get rid of spurious WEBMAC page
+
+\font\man=manfnt scaled \magstep3
+\font\CompJtitle=cmbx10 scaled\magstep4
+\font\CompJabstract=cmb10
+\font\tenssb=cmssdc10
+\font\tenss=cmss10
+\font\tenssi=cmssi10
+\font\eightss=cmss8
+\font\eightssi=cmssi8
+\font\eightssb=cmssbx10 scaled 800
+\font\eighttt=cmtt8
+\font\ninerm=cmr9
+\let\mc=\ninerm % medium caps for names like PASCAL
+
+\newdimen\pagewidth \newdimen\pageheight \newdimen\ruleht
+\hsize=177mm \vsize=249mm
+\parindent=1em % this is needed for WEB output
+\pagewidth=\hsize \pageheight=\vsize \ruleht=1pt
+\abovedisplayskip=11pt plus 3pt minus 8pt
+\abovedisplayshortskip=0pt plus 3pt
+\belowdisplayskip=11pt plus 3pt minus 8pt
+\belowdisplayshortskip=6pt plus 3pt minus 3pt
+
+\newif\iftitle
+\def\titlepage{\global\titletrue} % for pages without headlines
+
+\def\leftheadline{\hbox to \pagewidth{%
+ \vbox to 8pt{}\hss \eightrm D. E. KNUTH\hss}}
+\def\rightheadline{\hbox to \pagewidth{%
+ \vbox to 8pt{}\hss \eightrm LITERATE PROGRAMMING\hss}}
+\hoffset=-.25in \voffset=-.6in
+
+\newinsert\lefttop \newinsert\righttop
+\count\lefttop=1000 \count\righttop=1000
+\dimen\lefttop=\maxdimen \dimen\righttop=\maxdimen
+\skip\lefttop=25pt plus 3pt minus 3pt
+\skip\righttop=\skip\lefttop
+\def\leftfloat{\insert\lefttop\bgroup
+ \floatingpenalty=0
+ \penalty0
+ \vbox\bgroup}
+\def\rightfloat{\insert\righttop\bgroup
+ \floatingpenalty=0
+ \penalty0
+ \vbox\bgroup}
+\def\endfloat{\egroup\egroup}
+
+\def\onepageout#1{\shipout\vbox{ % here we define one page of output
+ \offinterlineskip % butt the boxes together
+ \vbox to 9mm{ % this part goes on top of the regular pages
+ \iftitle % the next is used for title pages
+ \global\titlefalse % reset the titlepage switch
+ \hbox to\pagewidth{\leaders\CJrule\hfill}
+ \else\ifodd\pageno \rightheadline\else\leftheadline\fi\fi
+ \vfill} % this completes the \vbox to 9mm
+ \vbox to \pageheight{
+ #1 % now insert the main information
+ \boxmaxdepth=\maxdepth
+ } % this completes the \vbox to \pageheight
+ \baselineskip=7mm \lineskiplimit=0pt
+ \hbox to\pagewidth{%
+ \ifodd\pageno\hfil\tenss submitted to THE COMPUTER JOURNAL%
+ \tenssb\quad\folio
+ \else\tenssb\folio\quad
+ \tenss submitted to THE COMPUTER JOURNAL\hfil\fi}
+ }
+ \advancepageno}
+
+\output{\onepageout{\unvbox255}}
+
+\newbox\partialpage
+\def\begindoublecolumns{\begingroup
+ \output={\global\setbox\partialpage=\vbox{\unvbox255}}\eject
+ \output={\doublecolumnout} \hsize=84mm \vsize=510mm}
+\def\enddoublecolumns{\output={\balancecolumns}\eject
+ \endgroup \pagegoal=\vsize}
+
+\def\doublecolumnout{\dimen0=\pageheight
+ \advance\dimen0 by-\ht\partialpage \splittopskip=\topskip
+ \ifdim\ht\lefttop>0pt \setbox255=\vbox{\unvbox\lefttop
+ \setbox0=\lastbox\unvbox0\vskip\skip\lefttop\unvbox255}\fi
+ \setbox0=\vsplit255 to\dimen0
+ \ifdim\ht\righttop>0pt \setbox255=\vbox{\unvbox\righttop
+ \setbox0=\lastbox\unvbox0\vskip\skip\righttop\unvbox255}\fi
+ \setbox2=\vsplit255 to\dimen0
+ \onepageout\pagesofar
+ \unvbox255 \penalty\outputpenalty}
+\def\pagesofar{\unvbox\partialpage
+ \wd0=\hsize \wd2=\hsize \hbox to\pagewidth{\box0\hfil\box2}}
+\def\balancecolumns{\setbox0=\vbox{\unvbox255} \dimen0=\ht0
+ \advance\dimen0 by\topskip \advance\dimen0 by-\baselineskip
+ \divide\dimen0 by2 \splittopskip=\topskip
+ {\vbadness=10000 \loop \global\setbox3=\copy0
+ \global\setbox1=\vsplit3 to\dimen0
+ \ifdim\ht3>\dimen0 \global\advance\dimen0 by1pt \repeat}
+ \setbox0=\vbox to\dimen0{\unvbox1}
+ \setbox2=\vbox to\dimen0{\unvbox3}
+ \pagesofar}
+
+\def\CJrule{\hrule height\ruleht}
+\baselineskip=11pt
+\parskip=0pt plus 1pt
+\def\beginsection #1\par{\goodbreak\vskip9mm plus4mm minus 2mm
+ \vbox{\CJrule width \hsize \kern5pt}
+ \kern-3pt
+ \nointerlineskip
+ \leftline{\strut\bf#1}
+ \CJrule
+ \kern12pt\nobreak\noindent\ignorespaces}
+\def\caption #1. #2.{\leftline{\def\TeX{T\kern-.2em\lower.5ex\hbox{E}X}%
+ \tenssb Figure #1.\enspace\tenss#2.}}
+
+\def\WEB{{\tt WEB}}
+\def\PASCAL{{\mc PASCAL}}
+\def\sec{{\tensy x}}
+\def\<{$\langle\,$}
+\def\>{$\,\rangle$}
+\newbox\circlebox
+\setbox\circlebox=\hbox{\man Y}
+\def\encircle#1{\kern6pt\hbox to\wd\circlebox{\hss\tt#1\hss}\kern-\wd\circlebox
+ \raise10pt\copy\circlebox\kern6pt}
+
+\def\ttverbatim{\begingroup \tt \parindent=0pt \obeylines
+ \uncatcodespecials \catcode`/=0 \obeyspaces}
+\let\endverbatim=\endgroup
+{\obeyspaces\global\let =\ } % let active space = control space
+\def\uncatcodespecials{\def\do##1{\catcode`##1=12 }\dospecials}
+\def\cvdots{\kern3pt\qquad\smash\vdots}
+
+\newcount\refno \newif\ifshowit
+\def\ref{\showittrue\makeref}
+\def\silentref{\showitfalse\makeref}
+\def\references{} % this will grow until it holds all the references
+\def\makeref#1#2{\advance\refno by1 \edef#1{{\the\refno}}%
+ \toks0=\expandafter{\references}%
+ {\def\rm{\eightss}\def\sl{\eightssi}\def\bf{\eightssb}\def\tt{\eighttt}%
+ \def\TeX{T\kern-.2em\lower.5ex\hbox{E}\kern-.000em X}%
+ \xdef\references{\the\toks0 \noexpand\item{\the\refno.}#2\par}}%
+ \ifshowit\edef\next{\spacefactor=\the\spacefactor\space}%
+ $^{\the\refno}$\next\fi}
+\hyphenation{Dijk-stra}
+\hyphenchar\tentt=-1 % no hyphenation in the typewriter font
+
+\titlepage
+\leftline{\kern13mm\CompJtitle Literate Programming}
+\kern6mm
+\CJrule
+\kern4.5mm
+\leftline{\kern13mm\bf Donald E. Knuth}
+\kern2pt
+\leftline{\kern13mm\eightrm Computer Science Department, Stanford University,
+ Stanford, CA 94305, USA}
+\kern4mm
+\CJrule
+\kern6mm
+\leftline{\kern13mm\vbox{\hsize=151mm\CompJabstract\noindent
+The author and his associates have been experimenting for the past several
+years with a programming language and documentation system called \WEB.
+This paper presents \WEB\ by example, and discusses why the new
+system appears to be an improvement over previous ones.}}
+\bigskip\bigskip
+\begindoublecolumns
+
+\beginsection A. INTRODUCTION
+
+The past ten years have witnessed substantial improvements in programming
+methodology. This advance, carried out under the banner of ``structured
+programming,'' has led to programs that are more reliable and easier to
+comprehend; yet the results are not entirely satisfactory. My purpose
+in the present paper is to propose another motto that may be appropriate
+for the next decade, as we attempt to make further progress in the
+state of the art. I believe that the time is ripe for significantly
+better documentation of programs, and that we can best achieve this by
+considering programs to be {\it works of literature}. Hence, my title:
+``Literate Programming.''
+
+Let us change our traditional attitude to the construction of programs:
+Instead of imagining that our main task is to instruct a {\it computer\/}
+what to do, let us concentrate rather on explaining to {\it human beings\/}
+what we want a computer to do.
+
+The practitioner of literate programming can be regarded as an essayist, whose
+main concern is with exposition and excellence of style. Such an author,
+with thesaurus in hand, chooses the names of variables carefully and explains
+what each variable means. He or she strives for a program that is
+comprehensible because its concepts have been introduced in an order that
+is best for human understanding, using a mixture of formal and informal
+methods that re\"\i nforce each other.
+
+I dare to suggest that such advances in documentation are possible because
+of the experiences I've had during the past several years while working
+intensively on software development. By making use of several ideas that
+have existed for a long time, and by applying them systematically in a
+slightly new way, I've stumbled across a method of composing programs
+that excites me very much. In fact, my enthusiasm is so great that I must warn
+the reader to discount much of what I shall say as the ravings of a fanatic
+who thinks he has just seen a great light.
+
+Programming is a very personal activity, so I can't be certain that what has
+worked for me will work for everybody. Yet the impact of this new approach on
+my own style has been profound, and my excitement has continued unabated
+for more than two years. I~enjoy the new methodology so much that it is hard
+for me to refrain from going back to every program that I've ever written
+and recasting it in ``literate'' form. I~find myself unable to resist working
+on programming tasks that I would ordinarily have assigned to student
+research assistants; and why? Because it seems to me that at last I'm able
+to write programs as they should be written. My programs are not only
+explained better than ever before; they also are better programs,
+because the new methodology encourages me to do a better job. For these
+reasons I am compelled to write this paper, in hopes that my experiences
+will prove to be relevant to others.
+
+I must confess that there may also be a bit of malice in my choice of
+a title. During the 1970s I was coerced like everybody else into adopting
+the ideas of structured programming, because I couldn't bear to be found
+guilty of writing {\it unstructured\/} programs. Now I have a chance
+to get even. By coining the phrase ``literate programming,'' I am imposing
+a moral commitment on everyone who hears the term; surely nobody wants
+to admit writing an {\it il{}literate\/} program.
+
+\beginsection B. THE \WEB\ SYSTEM
+
+I hope, however, to demonstrate in this paper that the title is not merely
+wordplay. The ideas of literate programming have been embodied in a language
+and a suite of computer programs that have been developed at Stanford
+University during the past few years as part of my research on algorithms
+and on digital typography. This language and its associated programs
+have come to be known as the \WEB\ system. My goal in what follows is
+to describe the philosophy that underlies \WEB, to present examples
+of programs in the \WEB\ language, and to discuss what may be the future
+implications of this work.
+
+I chose the name \WEB\ partly because it was one of the few three-letter
+words of English that hadn't already been applied to computers. But as time
+went on, I've become extremely pleased with the name, because I~think
+that a complex piece of software is, indeed, best regarded as a {\it web\/}
+that has been delicately pieced together from simple materials. We
+understand a complicated system by understanding its simple parts, and by
+understanding the simple relations between those parts and their immediate
+neighbors. If we express a program as a web of ideas, we can emphasize
+its structural properties in a natural and satisfying way.
+
+\WEB\ itself is chiefly a combination of two other languages:
+(1)~a document formatting language and (2)~a programming language.
+My prototype \WEB\ system uses \TeX\ as the document formatting
+language and \PASCAL\ as the programming language, but the same
+principles would apply equally well if other languages were
+substituted. Instead of \TeX, one could use a language like Scribe
+or Troff; instead of \PASCAL, one could use {\mc ADA}, {\mc ALGOL},
+{\mc LISP}, {\mc COBOL}, {\mc FORTRAN}, {\mc APL}, {\mc C}, etc., or
+even assembly language. The main point is that \WEB\ is inherently
+bilingual, and that such a combination of languages proves to be much
+more powerful than either single language by itself. \WEB\ does not
+make the other languages obsolete; on the contrary, it enhances them.
+
+I naturally chose \TeX\ to be the document formatting language, in the
+first \WEB\ system, because \TeX\ is my own creation;\ref\TeXbook{D. E. Knuth,
+{\sl The \TeX book}. Addison-Wesley, Reading, Mass., U.S.A. (1983).}
+I wanted to acquire a lot of experience in harnessing \TeX\ to a variety
+of different tasks. I~chose \PASCAL\ as the programming language because
+it has received such widespread support from educational institutions all
+over the world; it is not my favorite language for system programming, but
+it has become a ``second language'' for so many programmers that it
+provides an exceptionally effective medium of communication. Furthermore
+\WEB\ itself has a macro-processing ability that makes \PASCAL's
+limitations largely irrelevant.
+
+Document formatting languages are newcomers to the computing scene, but
+their use is spreading rapidly. Therefore I'm confident that we will be
+able to expect each member of the next generation of programmers to be
+familiar with a document language as well as a programming language,
+as part of their basic education. Once a person knows both of the
+underlying languages, there's no trick at all to learning \WEB, because
+the \WEB\ user's manual is fewer than ten pages long.
+
+A \WEB\ user writes a program that serves
+as the source language for two different system routines. (See Figure~1.)
+One line of processing is called {\it weaving\/} the web; it produces
+a document that describes the program clearly and that facilitates program
+maintenance. The other line of processing is called {\it tangling\/} the
+web; it produces a machine-executable program. The program and its
+documentation are both generated from the same source, so they are
+consistent with each other.
+
+\bigskip
+\centerline{\vbox{
+ \halign{&\hss#\hss\cr
+ &&&\TeX\cr
+ \noalign{\vskip-4pt}
+ &&\encircle{TEX}&\enspace\rightarrowfill\enspace&\encircle{DVI}\cr
+ \multispan2\hfil\smash{\raise4pt\hbox{\tt WEAVE}\kern-1pt}$\nearrow$ \cr
+ \noalign{\vskip6pt}
+ \encircle{WEB}\cr
+ \noalign{\vskip6pt}
+ \multispan2\hfil\smash{\lower6pt\hbox{\tt TANGLE}\kern-1pt}$\searrow$ \cr
+ &&\encircle{PAS}&\enspace\rightarrowfill\enspace&\encircle{REL}\cr
+ \noalign{\vskip-2pt}
+ &&&\mc\ PASCAL\ \cr}
+ }}
+\nobreak\medskip
+\caption 1. Dual usage of a {\tt WEB} file.
+\bigbreak
+
+Let's look at this process in slightly more detail. Suppose you have
+written a \WEB\ program and put it into a computer text file called
+{\tt COB.WEB} (say). To generate hardcopy documentation for your program,
+you can run the {\tt WEAVE} processor; this is a system program that takes
+the file {\tt COB.WEB} as input and produces another file {\tt COB.TEX}
+as output. Then you run the \TeX\ processor, which takes {\tt COB.TEX}
+as input and produces {\tt COB.DVI} as output. The latter file,
+{\tt COB.DVI}, is a ``device-in\-de\-pen\-dent'' binary description of how
+to typeset the documentation, so you can get printed output by applying
+one more system routine to this file.
+
+You can also follow the other branch of Figure~1, by running the
+{\tt TANGLE} processor; this is a system program that takes the file
+{\tt COB.WEB} as input and produces a new file {\tt COB.PAS} as output.
+Then you run the \PASCAL\ compiler, which converts {\tt COB.PAS} to
+a binary file {\tt COB.REL} (say). Finally, you can run your program
+by loading and executing {\tt COB.REL}. The process of ``compile, load,
+and go'' has been slightly lengthened to ``tangle, compile, load, and go.''
+
+\beginsection C. A COMPLETE EXAMPLE
+
+Now it's time for me to stop presenting general platitudes and to move on
+to something tangible. Let us look at a real program that has been written
+in \WEB. The numbered paragraphs that follow are the actual output of a
+\WEB\ file that has been ``woven'' into a document; a computer has also
+generated the indexes that appear at the program's end. If my claims for
+the advantages of literate programming have any merit, you should be able
+to understand the following description more easily than you could
+have understood the same program when presented in a more conventional
+way. However, I am trying here to explain the format of \WEB\ documentation
+at the same time as I am discussing the details of a nontrivial algorithm,
+so the description below is slightly longer than it would be if it were
+written for people who already have been introduced to \WEB.
+
+\silentref\Dijk{O.-J.~Dahl, E.~W. Dijkstra, and C.~A.~R. Hoare,
+{\sl Structured Programming}. Academic Press, London and New York (1972).}
+\silentref\goto{D. E. Knuth, Structured programming with {\bf go to}
+statements. {\sl Computing Surveys\/ \bf6}, 261--301 (1974).}
+
+Here, then, is the computer-generated output:
+
+\bigskip
+\CJrule
+\medskip
+\begingroup
+\def\prune\input webmac{\input primes.contents}
+\def\Z#1#2#3{\line{\ignorespaces#1\ \dotfill\ {\tensy x}#2}}
+\def\M#1.{\MN#1.\iftrue\medbreak\startsection\ignorespaces}
+\def\firstmod{1}
+\def\N#1.#2.{\MN#1.\iftrue\nobreak
+ \ifx\modno\firstmod\medskip\else\bigskip\fi
+ \CJrule\medbreak\startsection
+ {\bf\ignorespaces#2.\quad}\ignorespaces}
+\def\inx{\par\medbreak
+ \def\:##1, {\par\hangindent2em\noindent##1:\kern1em}
+ \def\[##1]{$\underline{##1}$}
+ \rm \rightskip0pt plus2.5em \tolerance10000 \let\*=\lapstar
+ \hyphenpenalty10000 \parindent0pt}
+\def\fin{\par\bigskip\CJrule\medbreak
+ \parfillskip0pt plus1fil
+ \def\note##1##2.{\hfil\penalty-1\hfilneg\quad{\eightrm##1 ##2.}}
+ \def\U{\note{Used in}}
+ \def\:{\par\hangindent 2em}\let\*=*}
+\let\con=\par
+\parskip=0pt
+\expandafter\prune\input primes
+\endgroup
+
+\beginsection D. HOW THE EXAMPLE WAS SPECIFIED
+
+Everything reproduced above, from the table of contents preceding the
+program to the indexes of identifiers and section names at the end,
+was generated by applying the program {\tt WEAVE} to a source file
+{\tt PRIMES.WEB} written in the \WEB\ language. Let us now look at that
+file {\tt PRIMES.WEB}, in order to get an idea of what a \WEB\ user
+actually types.
+
+There's no need to show very much of {\tt PRIMES.WEB}, however, because
+that file is reflected quite faithfully by the formatted output. Figure~2
+contains enough of the \WEB\ source to indicate the general flavor;
+a reader who is familiar with the rudiments of \TeX\ will be able to
+reconstruct all of {\tt PRIMES.WEB} by looking only at the formatted
+output and Figure~2.
+
+\leftfloat
+\ttverbatim
+/hrule
+/medskip
+\font\ninerm=cmr9
+\let\mc=\ninerm % medium caps
+\def\WEB{{\tt WEB}}
+\def\PASCAL{{\mc PASCAL}}
+\def\[{\ifhmode\ \fi$[\mkern-2mu[$}
+\def\]{$]\mkern-2mu]$\ }
+/cvdots
+\hyphenation{Dijk-stra}
+/medskip
+@* Printing primes: An example of \WEB.
+The following program is essentially the same
+as Edsger Dijkstra's @^Dijkstra, Edsger@>
+``first example of step-wise program
+composition,'' found on pages 26--39
+of his {\sl Notes on Structured
+Programming},$^\Dijk$ but it has been
+translated into the \WEB\ language. @.WEB@>
+/medskip
+\[Double brackets will be used in what
+follows to enclose comments relating to \WEB\
+/cvdots
+an informal top-level description.\]
+/medskip
+@p @<Program to print the first thousand
+prime numbers@>
+/endverbatim
+\medskip
+\caption 2a. The beginning of {\tt PRIMES.WEB}.
+\medskip
+\hrule
+\endfloat
+
+Figure 2a starts with \TeX\ commands (not shown in full) that make it
+convenient to typeset double brackets $[\mkern-2mu[\ldots]\mkern-2mu]$
+and to give special typographic treatment to names like `\WEB' and `\PASCAL'.
+A \WEB\ user generally begins by declaring such special aspects of the
+document format; for example, if nonstandard fonts of type are needed,
+they are usually stated first. It may also be necessary to specify the
+correct hyphenation of non-English words that appear in the document.
+
+Then comes `{\tt@*}', which starts the program proper. \WEB\ uses the
+symbol `{\tt@}' as an escape character for special instructions to the
+{\tt WEAVE} and {\tt TANGLE} processors. Everything between such special
+commands is either expressed in \TeX\ language or in \PASCAL\ language,
+depending on the context.
+
+Each section of the program begins either with `{\tt@ }' (i.e., at-sign
+and space) or `{\tt@*}' (i.e., at-sign and asterisk); \WEB\ supplies the
+section numbers automatically. The latter case, `{\tt@*}', denotes a
+{\it major section\/} of the program, for which a special title is given.
+This title will appear in boldface type, and it will also appear in the
+table of contents, and as a running headline on all pages of the
+woven documentation until another major section begins. Each major section
+starts at the top of a page. (Such page beginnings have been indicated
+by horizontal lines in our example, because \WEB's normal output format
+has been adapted to the format of this journal. The output of {\tt WEAVE}
+usually has a lot more white space, and the individual lines of text
+are usually quite a bit wider.)
+
+The lines that follow in Figure~2a show a few more \WEB\ instructions:
+`{\tt@\char`^}' marks the beginning of an index entry to be set in roman
+type; `{\tt@>}' marks the end of an argument to a \WEB\ command;
+`{\tt@.}'\ marks the beginning of an index entry to be set in typewriter
+type; `{\tt@p}' marks the beginning of the \PASCAL\ program; and `{\tt@<}'
+marks the beginning of a top-level description, i.e., of a section
+name in the \WEB\ program.
+
+\rightfloat
+\ttverbatim
+/hrule
+/medskip
+@ This program has no input, because we want
+to keep it rather simple. The result of the
+program will be to produce a list of the
+first thousand prime numbers, and this list
+will appear on the |output| file.
+/medskip
+Since there is no input, we declare the value
+|m=1000| as a compile-time constant. The
+program itself is capable of generating the
+first |m| prime numbers for any positive |m|,
+as long as the computer's finite limitations
+are not exceeded.
+/medskip
+\[The program text below specifies the
+``expanded meaning'' of `\X2:Program to print
+$\ldots$ numbers\X'; notice that it involves
+the top-level descriptions of three other
+sections. When those top-level descriptions
+are replaced by their expanded meanings, a
+syntactically correct \PASCAL\ program will
+be obtained.\]
+/medskip
+@<Program to print...@>=
+program print_primes(output);
+const @!m=1000;
+@<Other constants of the program@>@;
+var @<Variables of the program@>@;
+begin @<Print the first |m| prime numbers@>;
+end.
+/endverbatim
+\medskip
+\caption 2b. The \WEB\ code that generated \sec2.
+\ttverbatim
+/bigskip
+/hrule
+/medskip
+@ In order to keep this program reasonably
+free of notations that are uniquely
+\PASCAL esque, \[and in order to illustrate
+/cvdots
+The first three macro definitions here are
+parametric; the other two are simple.\]
+/medskip
+@d print_string(#)==write(#)
+ {put a given string into the |output| file}
+@d print_integer(#)==write(#:1)
+ {put a given integer into the |output|
+ file, in decimal notation, using only as
+ many digit positions as necessary}
+@d print_entry(#)==write(#:ww)
+ {like |print_integer|, but
+ |ww| character positions are filled,
+ inserting blanks at the left}
+@d new_line==write_ln
+ {advance to a new line in the |output| file}
+@d new_page==page
+ {advance to a new page in the |output| file}
+/endverbatim
+\medskip
+\caption 2c. The \WEB\ code that generated \sec6.
+\medskip
+\hrule
+\endfloat
+
+Figure 2b immediately follows Figure~2a in the \WEB\ file. This material
+is what generated \sec2 of the documentation, and it illustrates the
+bilingual nature of \WEB: The commentary at the beginning of each section
+is typed in \TeX\ language, and the program text at the end is typed
+in \PASCAL\ language.
+
+Language-switching between \TeX\ and \PASCAL\ is occasionally desirable.
+For example, when you refer to technical details about the program, you
+usually want to describe them in \PASCAL, hence you want {\tt WEAVE} to format
+them with the typographic conventions it uses for \PASCAL\ programs.
+Conversely, when you put comments in a \PASCAL\ program, you want
+the text of those comments to be formatted by \TeX\ in the normal way.
+\WEB\ files use vertical bars to introduce \PASCAL\ formatting in the
+midst of \TeX\ formatting; for example, Figure~2b says `{\tt the
+|output| file}' in order to typeset `the \\{output} file'.
+
+The program text in Figure~2b begins with `{\tt@<}' instead of with the
+`{\tt@p}' command used in Figure~2a, because the program text in~\sec2
+is the expansion of a specific top-level description. Notice that the
+top-level description has been abbreviated to `{\tt@<Program to print...@>}'.
+Since the names of sections tend to be rather long, it is a nuisance to
+type them in full each time; \WEB\ allows you to type `{\tt...}'\ after you
+have given enough text to identify the remainder uniquely.
+
+The `{\tt@!}'\ operation in the program text of Figure~2b governs the
+underlining of index entries. The `{\tt@;}'\ specifies an invisible symbol
+that has the effect of a semicolon in \PASCAL\ syntax. Commands such as these
+are comparatively unimportant, but they are available for polishing up
+the final documentation when you want to maintain fine control.
+
+Figure 2c shows key portions of the \WEB\ text that generated \sec6.
+Notice that the command `{\tt@d}' introduces a macro definition.
+All features of \WEB\ that appear in our example program are illustrated
+in Figures 2a, 2b, and~2c; the remainder of {\tt PRIMES.WEB} simply
+uses the same conventions again and again. In fact, most of the \WEB\
+file is much simpler than the examples shown here; Figure~2 has
+illustrated only the difficult parts.
+
+\beginsection E. THE TANGLED OUTPUT
+
+Figure 3 shows the \PASCAL\ program {\tt PRIMES.PAS} that results when
+{\tt TANGLE} is applied to {\tt PRIMES.WEB}. This program is not intended
+for human consumption---it's only supposed to be readable by a \PASCAL\
+compiler---so {\tt TANGLE} does not go to great pains to produce a
+beautiful format. Notice that underlines have been removed from the
+identifier names, and that all of the letters have been converted to
+uppercase (except in strings); {\tt TANGLE} tries to produce a format
+that will be acceptable to a standard \PASCAL\ compiler.
+
+{\tt TANGLE} removes all of the commentary in the \WEB\ file, but it
+inserts new comments of its own. If for some reason you need
+to correlate the tangled \PASCAL\ code with the woven documentation,
+you can find the program text for, say, \sec8 by looking between
+the comments `{\tt\char`\{8:\char`\}}' and `{\tt\char`\{:8\char`\}}'.
+
+A comparison of Figure~3 to Figure~2 should make it clear why the
+{\tt TANGLE} processor has acquired its name.
+
+\rightfloat
+\ttverbatim
+/hrule
+/medskip
+{1:}{2:}PROGRAM PRINTPRIMES(OUTPUT);
+CONST M=1000;{5:}RR=50;CC=4;WW=10;{:5}{19:}
+ORDMAX=30;{:19}VAR{4:}
+P:ARRAY[1..M]OF INTEGER;{:4}{7:}
+PAGENUMBER:INTEGER;PAGEOFFSET:INTEGER;
+ROWOFFSET:INTEGER;C:0..CC;{:7}{12:}J:INTEGER;
+K:0..M;{:12}{15:}JPRIME:BOOLEAN;{:15}{17:}
+ORD:2..ORDMAX;SQUARE:INTEGER;{:17}{23:}
+N:2..ORDMAX;{:23}{24:}
+MULT:ARRAY[2..ORDMAX]OF INTEGER;{:24}
+BEGIN{3:}{11:}{16:}J:=1;K:=1;P[1]:=2;{:16}
+{18:}ORD:=2;SQUARE:=9;{:18};
+WHILE K<M DO BEGIN{14:}REPEAT J:=J+2;{20:}
+IF J=SQUARE THEN BEGIN ORD:=ORD+1;{21:}
+SQUARE:=P[ORD]*P[ORD];{:21}{25:}
+MULT[ORD-1]:=J;{:25};END{:20};{22:}N:=2;
+JPRIME:=TRUE;
+WHILE(N<ORD)AND JPRIME DO BEGIN{26:}
+WHILE MULT[N]<J DO MULT[N]:=MULT[N]+P[N]+P[N]
+;IF MULT[N]=J THEN JPRIME:=FALSE{:26};N:=N+1;
+END{:22};UNTIL JPRIME{:14};K:=K+1;P[K]:=J;
+END{:11};{8:}BEGIN PAGENUMBER:=1;
+PAGEOFFSET:=1;
+WHILE PAGEOFFSET<=M DO BEGIN{9:}
+BEGIN WRITE('The First ');WRITE(M:1);
+WRITE(' Prime Numbers --- Page ');
+WRITE(PAGENUMBER:1);WRITELN;WRITELN;
+FOR ROWOFFSET:=PAGEOFFSET TO PAGEOFFSET+RR-1
+DO{10:}
+BEGIN FOR C:=0 TO CC-1 DO IF ROWOFFSET+C*RR<=
+M THEN WRITE(P[ROWOFFSET+C*RR]:WW);WRITELN;
+END{:10};PAGE;END{:9};
+PAGENUMBER:=PAGENUMBER+1;
+PAGEOFFSET:=PAGEOFFSET+RR*CC;END;END{:8}{:3};
+END.{:2}{:1}
+/endverbatim
+\medskip
+\caption 3. PASCAL program generated from the \WEB\ file.
+\medskip
+\hrule
+\endfloat
+
+\beginsection F. THE WOVEN OUTPUT
+
+I mentioned earlier that {\tt WEAVE} is a program that converts a file
+like {\tt PRIMES.WEB} into a file {\tt PRIMES.TEX} that is a syntactically
+correct source file for \TeX. Figure~4 gives a sampling of {\tt PRIMES.TEX},
+which is even more unreadable than {\tt PRIMES.PAS}. The instructions that
+cause \TeX\ to produce formatted \PASCAL\ programs, with appropriate
+typefaces and indentation, etc., are somewhat complex because they are
+supposed to give decent results regardless of the page size.
+
+There is no need to discuss Figure~4 further in the present paper, because
+the details of ``pretty printing'' are not relevant to my main theme.
+I have shown this much of {\tt PRIMES.TEX} only to make the point that
+it is nice to have a program like {\tt WEAVE} to do all the formatting;
+computer programs are not easy to typeset.
+
+\leftfloat
+\ttverbatim
+/hrule
+/medskip
+\input webmac
+\font\ninerm=amr9
+/cvdots
+syntactically correct \PASCAL\ program will
+be obtained.\]
+/medskip
+\Y\P$\4\X2:Program to print the first
+thousand prime numbers\X\S$\6
+\4\&{program}\1\ \37$\\{print\_primes}(%
+\\{output})$;\6
+\4\&{const} \37$\|m=1000$;\5
+\X5:Other constants of the program\X\6
+\4\&{var} \37\X4:Variables of the program\X\6
+\&{begin} \37\X3:Print the first \|m prime
+numbers\X;\6
+\&{end}.\par
+\U section~1.\fi
+/cvdots
+The first three macro definitions here are
+parametric; the other two are simple.\]
+/medskip
+\Y\P\D \37$\\{print\_string}(\#)\S\\{write}(%
+\#)$\C{put a given string into the %
+\\{output} file}\par
+/cvdots
+\inx
+\:{Bertrand, Joseph, postulate}, 21.
+\:\\{boolean}, 15.
+/cvdots
+\:\.{WEB}, 1.
+\:\\{write}, 6.
+\:\\{write\_ln}, 6.
+\:\\{ww}, \[5], 6.
+\fin
+/cvdots
+\:\X4, 7, 12, 15, 17, 23, 24:Variables of
+the program\X
+\U section~2.
+\con
+/endverbatim
+\medskip
+\caption 4. \TeX\ program generated from the \WEB\ file.
+\medskip
+\hrule
+\endfloat
+
+\beginsection G. ADDITIONAL BELLS AND WHISTLES
+
+A system like \WEB\ can be successful only if it is capable of handling
+large programs as well as small ones, and only if it is complete enough
+to take care of all the practical requirements that arise when many
+different kinds of programs are considered. A small example like
+{\tt PRIMES.WEB} is a satisfactory vehicle for illustrating the general
+ideas, but it cannot be convincing as a demonstration of \WEB's ability
+to produce quality software in the ``real world.'' My original design
+of \WEB\ in September, 1981, was followed by a year of extensive
+experiments, so that by the time Version~1 was released in
+September, 1982, I could be fairly confident that the language was
+reasonably complete. Since then only one or two small extensions
+have proved to be necessary; and although numerous enhancements can
+easily be imagined, I believe that a useful stopping point for a
+working system called {\tt WEB83} has been reached.
+
+A full description of {\tt WEB83} appears in a Stanford report,\ref\WEBman%
+{D. E. Knuth, {\sl The \WEB\kern-2pt\ System of Structured Documentation}.
+Stanford Computer Science Report CS980 (September 1983).}
+which also contains the complete \WEB\ programs for {\tt WEAVE} and
+{\tt TANGLE}. The full language contains only a few features that
+do not show up in the {\tt PRIMES} example considered above:
+
+\def\nindent#1{\noindent\hbox to\parindent{#1)\hfil}\ignorespaces}
+\smallskip
+\nindent1 There are facilities to override {\tt WEAVE}'s
+automatic formatting of \PASCAL\ programs. For example, it is
+possible to force a statement to begin on a new line, or to force
+several statements to appear on the same line, or to suggest
+a desirable breakpoint in the middle of a long expression. In
+unusual cases, {\tt WEAVE} must parse program fragments that
+are not syntactically complete---for example, there may be a
+{\bf begin} without a matching {\bf end}---so a \WEB\ user must
+be given a chance to control the results. Furthermore there is a
+facility for changing {\tt WEAVE}'s formatting rules by declaring
+that a certain identifier should be treated as a certain \PASCAL\
+reserved word, or by declaring that a certain reserved word
+should be treated as an ordinary identifier.
+
+\smallskip
+\nindent2 There is a way to force {\tt TANGLE} to omit a
+space between two adjacent pieces of text, so that a name
+like `\\{x3}' can be manufactured from `\|x' and `\\3'. Similarly,
+there is a way to pass an arbitrary sequence of characters through
+{\tt TANGLE} so that the same sequence will appear ``verbatim'' in
+the \PASCAL\ file; and there is a way to force beginning-of-line
+in that file. The latter extensions have proved to be necessary
+to deal with various nonstandard conventions of different \PASCAL\ compilers.
+When a comment in braces is sent to the \PASCAL\ file, {\tt TANGLE}
+is careful not to introduce further braces inside the comment.
+
+\smallskip
+\nindent3 There are facilities for octal and hexadecimal constants in \WEB\
+thees. {\tt TANGLE} converts such constants to decimal form; {\tt WEAVE} gives
+them an appropriate typographic treatment.
+
+\smallskip
+\nindent4 There is a facility for dealing with alphabetic constants.
+When a program contains a double-quoted character like {\tt"A"},
+{\tt TANGLE} converts this to an integer between 0 and~127 that
+equals the corresponding {\mc ASCII} code (in this case 65).
+The use of {\mc ASCII} code facilitates the construction of software
+that is readily portable from one machine to another, independent of
+the actual character set in use.
+
+\smallskip
+\nindent5 Furthermore, if a double-quoted constant is a string
+of several characters, like {\tt"cat"}, {\tt TANGLE} converts it
+into a unique integer that is 128 or more. A special {\it string pool
+file\/} is written, containing all of the strings that have been
+specially encoded in this way. I have used this general mechanism only
+in large programs, but experience has shown that it makes quite a
+nice substitute for the string-processing capabilities that \PASCAL\
+lacks. (Incidentally, I noticed after several months that a program
+needs to have some indication that the string-pool file it is reading
+contains the same strings that {\tt TANGLE} generated when the program
+itself was tangled. Therefore a ``check sum'' is included in the
+string pool file; each program is able to refer to its own check sum
+and to compare it with the value in the file. This check-sum extension
+was one of the last features to be added to \WEB.)
+
+\smallskip
+\nindent6 The {\tt PRIMES} example illustrates macros with
+parameters and macros without parameters. \WEB\ also allows ``numeric''
+macros, which are small integer constants; {\tt TANGLE} is capable of
+doing simple arithmetic on such constants. This feature of \WEB\ was
+introduced specifically to overcome \PASCAL's unfortunate inability to
+do compile-time arithmetic. For example, it is impossible to have a
+\PASCAL\ array whose bounds are `$0\to n-1$', or to write
+`$20+3:$' as the label of one of the cases in `{\bf case} $x+y$';
+\WEB's numeric macros make it possible for {\tt TANGLE} to
+preprocess such constants.
+
+\beginsection H. OCCAM'S RAZOR
+
+I would also like to mention several things that were intentionally left
+out of \WEB, since I have tried to keep the language as simple as I could.
+
+There are no ``conditional macros,'' nor does {\tt TANGLE}
+evaluate Boolean expressions that might influence the
+output. I~found that everything I needed could be done
+satisfactorily by commenting out the optional code.
+
+For example, a system program is often designed to gather statistics about
+its own operation, but such statistics-gathering is pointless unless someone
+is actually going to use the results. In order to make the instrumentation
+code optional, I include the word `{\bf stat}' just before any special
+code for statistics, and `{\bf tats}' just after such code; and I tell
+{\tt WEAVE} to regard {\bf stat} and {\bf tats} as if they were {\bf begin}
+and {\bf end}. But {\bf stat} and {\bf tats} are actually simple macros.
+When I do want to gather the statistics, I define {\bf stat} and {\bf tats} to
+be null; but in a production version of the software, I make {\bf stat}
+expand to~`{\tt@\char`\{}' and {\bf tats} expand to~`{\tt@\char`\}}',
+where {\tt@\char`\{} and {\tt@\char`\}} are special braces that {\tt TANGLE}
+does not remove. Thus the optional code appears as a harmless comment in
+the \PASCAL\ program.
+
+\WEB's macros are allowed to have at most one parameter. Again, I did this
+in the interests of simplicity, because I noticed that most applications
+of multiple parameters could in fact be reduced to the one-parameter case.
+For example, suppose that you want to define something like
+$$\hbox{\tt mac(\#1,\#2) == m[\#1*r+\#2]}$$
+which \WEB\ doesn't permit. You can get essentially the same result
+with two one-parameter macros
+$$\vbox{\halign{\tt#\hfil\cr
+mac\char`\_tail(\#) == \#]\cr
+mac(\#) == m[\#*r+mac\char`\_tail\cr}}$$
+since, e.g., `{\tt mac(a)(b)}' will expand into `{\tt m[a*r+b]}'.
+
+Here is another example that indicates some of the surprising generality
+of one-parameter macros: Consider the two definitions
+$$\vbox{\halign{\tt#\hfil\cr
+define two\char`\_cases(\#)==case j of\cr
+\ \ \ \ \ \ \ \ \ \ \ \ \ 1:\#(1); 2:\#(2); end\cr
+define reset\char`\_file(\#)==reset(file@\&\#)\cr}}$$
+where `{\tt@\char`\&}' in the second definition is the concatenation operation
+that pastes two texts together. You can now say
+$$\hbox{\tt two\char`\_cases(reset\char`\_file)}$$
+and the resulting \PASCAL\ output will be
+$$\vbox{\halign{\tt#\hfil\cr
+case j of\cr
+1:reset(file1);\cr
+2:reset(file2);\cr
+end\cr}}$$
+In other words, the name of one macro can usefully be a parameter to
+another macro. This particular trick makes it possible to live with
+\PASCAL\ compilers that do not allow arrays of files.
+
+\beginsection I. PORTABILITY
+
+One of the goals of my \TeX\ research has been to produce portable
+software, and the {\tt WEB} system has been extremely helpful in this
+respect. Although my own work is done on a DEC-10 computer with
+Stanford's one-of-a-kind operating system, the software developed
+with \WEB\ has already been transported successfully to a wide
+variety of computers made by other manufacturers (including IBM,
+Control Data, XEROX, Hewlett-Packard), and to a variety
+of different operating systems for those machines. To my knowledge,
+no other software of such complexity has ever been transported to
+so many different machines. It seems likely that \TeX\ will soon be
+operating on all but the smallest of the world's computer systems.
+
+To my surprise, the main bottleneck to portability of the \TeX ware
+has been the lack of suitable \PASCAL\ compilers, because \PASCAL\ has
+often been implemented without system programming in mind. Anybody
+who has a decent \PASCAL\ compiler can install \WEB\ (and all programs
+written in \WEB) without great difficulty, essentially as follows:
+
+\smallskip
+\item{1)} Start with the three files {\tt WEAVE.WEB}, {\tt TANGLE.WEB}, and
+{\tt TANGLE.PAS}. (The programs have not been copyrighted, so
+these files are not difficult to obtain.)
+
+\item{2)} Run {\tt TANGLE.PAS} through your \PASCAL\ compiler to
+get a working {\tt TANGLE} program.
+
+\item{3)} Check your {\tt TANGLE} by applying it to {\tt TANGLE.WEB};
+your output file should match {\tt TANGLE.PAS}.
+
+\item{4)} Apply your {\tt TANGLE} to the file {\tt WEAVE.WEB}, obtaining
+{\tt WEAVE.PAS}; then apply \PASCAL\ to {\tt WEAVE.PAS} and you'll
+have a working {\tt WEAVE} system.
+
+\item{5)} The same process applies to any software written in \WEB,
+notably to \TeX\ itself. (However, you need fonts and suitable output
+equipment in order to make proper use of \TeX; that may be another
+bottleneck.) Once you have \TeX\ working, you can apply {\tt WEAVE}
+and \TeX\ to your \WEB\ files, thereby getting program documents
+as illustrated above.
+
+\smallskip\noindent
+Notice that a {\tt TANGLE.PAS} file is needed in order to get this
+``bootstrapping'' process started. If you have just {\tt WEAVE.WEB}
+and {\tt TANGLE.WEB}, you can't do the first step.
+
+However, anybody who has looked seriously into the question of software
+portability will realize that my comments in the preceding paragraphs
+have been oversimplified. I have glossed over some serious
+problems that arise: Character sets are different; file naming conventions
+are different; special conventions are needed to interact with a user's
+terminal; data is packed differently on different machines; floating-point
+arithmetic is always nonstandard and sometimes nonexistent; users want
+``friendly'' interaction with existing programs for editing and spooling;
+etc., etc. Furthermore, many of the world's \PASCAL\ compilers are incredibly
+bizarre. Therefore it is quite na\"\i ve to believe that a single program
+{\tt TANGLE.PAS} could actually work on very many different machines, or
+even that one single source file {\tt TANGLE.WEB} could be adequate; some
+system-dependent\kern-.5pt\kern.5pt\ changes are inevitable.
+
+The \WEB\ system caters to system-dependent changes in a simple but surprisingly
+effective way that I neglected to mention when I listed its other features.
+Both {\tt TANGLE} and {\tt WEAVE} are designed to work with
+{\it two\/} input files, not just one: In addition to a \WEB\ source file
+like {\tt TEX.WEB}, there is also a ``change file'' {\tt TEX.CH} that
+contains whatever changes are needed to customize \TeX\ for a particular
+system. (Similarly, the source files {\tt WEAVE.WEB} and {\tt TANGLE.WEB}
+are accompanied by {\tt WEAVE.CH} and {\tt TANGLE.CH}.)
+
+Here's how change files work: Each change has the form ``replace
+$x_1\ldots x_m$ by $y_1\ldots y_n$,'' for some $m\ge 1$ and $n\ge0$;
+here $x_i$ and~$y_j$ represent lines in the change file.
+The {\tt WEAVE} and {\tt TANGLE} programs
+read data from the \WEB\ input file until finding a line that matches
+$x_1$; this line, and the $m-1$ following lines, are replaced by
+$y_1\ldots y_n$. An error message is given if the $m$ lines replaced did
+not match $x_1\ldots x_m$ perfectly.
+
+For example, the program {\tt PRIMES.WEB} invokes a \\{page} procedure to
+begin a new page; but \\{page} was not pres\-ent in Wirth's original \PASCAL\
+and it is defined rather vaguely in the \PASCAL\ standard. Therefore
+a system-dependent change may be needed here. A change file {\tt
+PRIMES.CH} could be made by copying the line
+$$\hbox{\tt @d new\char`\_page==page}$$ from
+Figure~2c and specifying one or more appropriate replacement lines.
+
+The program {\tt TANGLE} itself contains about 190 sections, and a
+typical installation will have to change about 15 of these. If you
+want to transport {\tt TANGLE} to a new environment, you therefore
+need to create a suitable file {\tt TANGLE.CH} that modifies 15~or~so parts
+of {\tt TANGLE.WEB}. (Examples of {\tt TANGLE.CH} are provided to
+all people who receive {\tt TANGLE.WEB}, so that each implementor has
+a model of what to do.) You need to insert your changes by hand into
+{\tt TANGLE.PAS}, until you have a {\tt TANGLE} program that works
+sufficiently well to support further bootstrapping. But you never
+actually change the master file {\tt TANGLE.WEB}.
+
+This approach has two important advantages. First, the same
+master file {\tt TANGLE.WEB} is used by everybody, and it
+contains the basic logic of {\tt TANGLE} that really defines the
+essence of tangling. The system-dependent changes do not affect
+any of the subtle parts of {\tt TANGLE}'s control structures or
+data structures. Second, when the official {\tt TANGLE} has been
+upgraded to a newer version, a brand new {\tt TANGLE.WEB} will
+almost always work with the old {\tt TANGLE.CH}, since changes
+are rarely made to the system-dependent parts. In other words,
+this dual-input-file scheme works when the \WEB\ file is constant
+and the {\tt CH} file is modified, and it also works when the
+{\tt CH} file is constant but the \WEB\ file is modified.
+
+Change files were added to \WEB\ about three months after the system was
+initially designed, based on our initial experiences with people who had
+volunteered to participate in portability experiments. We realized
+about a year later that {\tt WEAVE} could be modified so that
+only the changed parts of a program would (optionally) be printed; thus,
+it's now possible to document the changes by listing only the sections
+that are actually affected by the {\tt CH} file that {\tt WEAVE} has
+processed. We also generalized the original format of {\tt CH} files,
+which permitted only changes that extended to the end of a section. These
+two important ideas were among the final enhancements incorporated into
+{\tt WEB83}.
+
+\beginsection J. PROGRAMS AS WEBS
+
+When I first began to work with the ideas that eventually became the
+\WEB\ system, I thought that I would be designing a language for ``top-down''
+programming, where a top-level description is given first and successively
+refined. On the other hand I knew that I often created major parts
+of programs in a ``bottom-up'' fashion, starting with the definitions of
+basic procedures and data structures and gradually building more and
+more powerful subroutines. I had the feeling that top-down and bottom-up
+were opposing methodologies: one more suitable for program exposition
+and the other more suitable for program creation.
+
+But after gaining experience with \WEB, I have come to realize that there is
+no need to choose once and for all between top-down and bottom-up, because
+a program is best thought of as a web instead of a tree. A hierarchical
+structure is present, but the most important thing about a program is
+its structural relationships. A complex piece of software consists of
+simple parts and simple relations between those parts; the programmer's
+task is to state those parts and those relationships, in whatever order
+is best for human comprehension---not in some rigidly determined
+order like top-down or bottom-up.
+
+When I'm writing a longish program like {\tt TANGLE.WEB} or {\tt WEAVE.WEB}
+or {\tt TEX.WEB}, I invariably have strong feelings about what part of the
+whole should be tackled next. For example, I'll come to a point where I need
+to define a major data structure and its conventions, before I'll feel
+happy about going further. My experiences have led me to believe that a
+person reading a program is, likewise, ready to comprehend it by
+learning its various parts in approximately the order in which it
+was written. The {\tt PRIMES.WEB} example illustrates this principle on
+a small scale; the decisions that Dijkstra made as he composed the original
+program$^\Dijk$ appear in the \WEB\ documentation in the same order.
+
+Top-down programming gives you a strong idea of where you are going, but
+it forces you to keep a lot of plans in your head; suspense builds up
+because nothing is really nailed down until the end. Bottom-up programming
+has the advantage that you continually wield a more and more powerful
+pencil, as more and more subroutines have been constructed; but it forces
+you to postpone the overall program organization until the last minute,
+so you might flounder aimlessly.
+
+When I tear up the first draft of a program and start over, my second draft
+usually considers things in almost the same order as the first one did.
+Sometimes the ``correct'' order is top-down, sometimes it is bottom-up,
+and sometimes it's a mixture; but always it's an order that makes sense on
+expository grounds.
+
+Thus the \WEB\ language allows a person to express programs
+in a ``stream of consciousness'' order. {\tt TANGLE} is able to scramble
+everything up into the arrangement that a \PASCAL\ compiler demands. This
+feature of \WEB\ is perhaps its greatest asset; it makes a \WEB-written
+program much more readable than the same program written purely in
+\PASCAL, even if the latter program is well commented. And the fact that there's
+no need to be hung up on the question of top-down versus bottom-up---since
+a programmer can now view a large program as a web, to be explored in
+a psychologically correct order---is perhaps the greatest lesson I have
+learned from my recent experiences.
+
+Another surprising thing that I learned while using \WEB\ was that
+traditional programming languages had been causing me to write inferior
+programs, although I hadn't realized what I was doing. My original idea was that
+\WEB\ would be merely a tool for documentation, but I actually found that
+my \WEB\ programs were better than the programs I had been writing
+in other languages. How could this be?
+
+Well, imagine that you are writing a small subroutine that updates part
+of a data structure, and suppose that the updating takes only
+one or two lines of code. In practical programs, there's often something
+that can go wrong, if the user's input is incorrect, so the subroutine
+has to check that the input is correct before doing the update.
+Thus, the subroutine has the general form
+$$\vbox{\halign{#\hfil\cr
+\&{procedure} \\{update};\cr
+\&{begin if} \<input data is invalid\> \&{then}\cr
+\quad \<Issue an error message and try to recover\>;\cr
+\<Update the data structure\>;\cr
+\&{end}.\cr}}$$
+A subtle phenomenon occurs in traditional programming languages: While
+writing the program for `\<Issue an error message and try to recover\>',
+a programmer subconsciously tries to get by with the fewest possible
+lines of code, since the program for `\<Update the data structure\>' is
+quite short. If an extensive error recovery is actually programmed, the
+subroutine will appear to have error-message printing as its main purpose.
+But the programmer knows that the error is really an exceptional case that
+arises only rarely; therefore a lengthy error recovery doesn't look right,
+and most programmers will minimize it (without realizing that they are doing
+so) in order to make the subroutine's appearance match its intended behavior.
+On the other hand when the same task is programmed with \WEB, the purpose
+of \\{update} can be shown quite clearly, and the possibility of error
+recovery can be reduced to a mere mention when \\{update} is defined.
+When another section entitled `\<Issue an error message and try to
+recover\>' is subsequently written, the whole point of that section is to do
+the best error recovery, and it becomes quite natural to write a better program
+as a result.
+
+\begingroup
+\tolerance=3000
+
+This fact---that \WEB\ allows you to let each part of the program have
+its appropriate size, without distorting the readability of other parts---means
+that good programmers find their \WEB\ programs better than their \PASCAL\
+programs, even though their \PASCAL\ programs once looked like the work
+of an expert.
+
+\endgroup
+
+\beginsection K. STYLISTIC ISSUES
+
+I found that my style of using \WEB\ evolved quite a bit during the first
+year. The general format, in which each section beings with commentary and
+ends with a formal program fragment, is extremely versatile; you have the
+freedom to say anything you want, yet you must make a decision about how
+you'll do it. I imagine that different programmers will converge to
+quite different styles, but I would like to note down some of the things
+that have seemed to work best for me.
+
+Consider first the question of macros versus section names. A named section,
+like `\<Issue an error message and try to recover\>', is essentially the
+same as a parameterless macro; \WEB\ provides both. I prefer to use
+parameterless macros for ``small'' things that can be embodied in a word
+or two, but named sections for longer portions of the program that
+merit a fuller description.
+
+I usually start the name of a section with an imperative verb, but I give
+a declarative commentary at the beginning of a section. Thus,
+{\tt PRIMES.WEB} says `{\bf 8.}~Now that appropriate $\ldots$
+\X8:Print table $p$\X$\;\S\;$\dots\thinspace'; I wouldn't do the opposite
+and say `{\bf8.}~Print the table. \X8:Code for printing\X$\;\S\;$\dots'.
+
+The name of a section (enclosed in angle brackets) should be long enough
+to encapsulate the essential characteristics of the code in that section,
+but it should not be too verbose. I found very early that it would be a
+mistake to include all of the assumptions about local and global variables
+in the name of each section, even though such information would strictly
+be necessary to isolate that section as an independent module. The trick is
+to find a balance between formal and informal exposition so that a reader
+can grasp what is happening without being overwhelmed with detail.\ref\Naur%
+{P. Naur, Formalization in program development. {\sl BIT\/ \bf22},
+437--453 (1982).}
+
+Another lesson I learned early in the game was that the name of a section
+should explicitly mention any nonstandard control structures, even though
+its data structures can often be left implied. Furthermore, if the control
+flow is properly explained, you can avoid the usual errors associated
+with \&{goto} statements; such statements can safely be introduced in
+a restrained but natural manner.
+
+For example, \sec14 of the prime-printing example could be reprogrammed as
+follows, using `\&{loop}' as a macro abbreviation for `\&{while} \\{true}
+\&{do}':
+$$\vbox{\halign{\hbox to\hsize{#\hfil}\cr
+\X14:Increase $j$ until it is the next prime number\X$\;\S$\cr
+\quad\&{loop begin} $j\K j+2$;\cr
+\qquad\X20:Update variables that depend on $j$\X;\cr
+\qquad\X22:If $j$ is prime, \&{goto} \\{found}\X;\cr
+\qquad\&{end};\cr
+\\{found}:\cr}}$$
+With this change, \sec22 could become
+$$\vbox{\halign{\hbox to\hsize{#\hfil}\cr
+\X22:If $j$ is prime, \&{goto} \\{found}\X$\;\S$\cr
+\quad$n\K2$;\cr
+\quad\&{while} $n<\\{ord}$ \&{do}\cr
+\qquad\&{begin} \X26:If $p[n]$ is a factor of $j$, \&{goto} \\{not\_found}\X;\cr
+\qquad$n\K n+1$;\cr
+\qquad\&{end};\cr
+\quad\&{goto} \\{found};\cr
+\\{not\_found}:\cr}}$$
+if \sec26 changes in the obvious way. The resulting program will be more
+efficient on most machines; and I believe that it is actually easier to
+read and to write, in spite of the fact that two \&{goto} statements
+appear, because the labels have been used with appropriate interpretations
+of their abstract significance.
+
+Of course, \PASCAL\ makes it difficult to use \&{goto} statements,
+because Wirth decided that labels should be numeric, and that they
+should be declared in advance. If I were to introduce the \&{goto}
+statements as suggested, I would have to define numeric macros
+\\{found} and \\{not\_found}, and I would have to insert
+`\&{label} \\{found}, \\{not\_found}' into the program at the right place.
+Such extra work is a bit of a nuisance, but it can be done in \WEB\ without
+spoiling the exposition.
+
+\PASCAL\ has a few other misfeatures that prove to be inconvenient with
+respect to \WEB\ exposition. The worst of these is the inability to
+declare local variables in the midst of a program or procedure. For
+example, a programmer often finds it most natural to define an integer
+variable when a \&{for} loop is introduced, but the rules of \PASCAL\
+insist that such a variable be declared rather far away from
+that \&{for} loop. My \WEB\ programs overcome this problem by having
+sections like `\<Local variables for \\{xyzzy}\>' whenever there's a
+rather lengthy procedure `\\{xyzzy}' whose local variables should not
+be declared all at once. But when a procedure is short, say only half
+a dozen sections long, there's usually no harm in declaring its local
+variables in \PASCAL\ style, because the entire text of the procedure will
+tend to appear on one or two adjacent pages of the documentation.
+
+Another slightly awkward aspect of \PASCAL\ is its treatment of semicolons.
+If you look closely at the prime-number example, you'll see that I had to
+be a bit careful about where I put semicolons; sometimes they occur at the
+end of the expanded text of a section, but usually they don't. With
+a little self discipline, a person can learn to do this quite satisfactorily,
+but it is a nuisance until you get used to it.
+
+\beginsection L. ECONOMIC ISSUES
+
+What does it cost to use \WEB? Let's look first at the lowest level, where
+computer costs are considered, because it is easy to make quantitative
+statements at this level. The running time to {\tt TANGLE} a \WEB\ file is
+approximately the same as the time needed to compile the resulting
+\PASCAL\ program; hence the extra preprocessing does not cost much.
+Similarly, {\tt WEAVE} doesn't take long to produce a file for \TeX.
+However, \TeX\ needs a comparatively large amount of time to typeset the
+final document. For example, if we assume that each page requires four
+seconds, it will take four minutes to produce a 60-page document. The
+running time for {\tt WEAVE}-plus-\TeX\ is quite reasonable when you
+consider that your program is effectively being
+converted into a fairly substantial booklet; but the costs are sufficiently
+large to discourage remaking and reprinting such a booklet more than once or
+twice a day. When a new program is being developed, it is therefore customary
+to work with hardcopy documentation that is slightly obsolete, and to read
+the \WEB\ source file itself when up-to-date information is required;
+the source file is sufficiently easy to read for such purposes.
+
+The costs of \WEB\ are more difficult to estimate at higher levels, but I have
+found to my surprise that the total time of writing and debugging a \WEB\
+program is no greater than the total time of writing and debugging an
+{\mc ALGOL} or {\mc PASCAL} program, even though my \WEB\ programs are
+much better, and even though I am putting substantially more documentation
+into the programs. Therefore I have lately been using \WEB\ for all of my
+programming, even for one-off jobs that I write ``for my eyes only'' just
+to explore occasional problems. The extra time I spend in preparing additional
+commentary is regained because the debugging time is reduced.
+
+In retrospect, the fact that a ``literate'' program takes much less time to
+debug is not surprising, because the \WEB\ language encourages a discipline
+that I was previously unwilling to impose on myself. I had known for a long
+time that the programs I construct for publication in a book, or the programs
+that I construct in front of a class, have tended to be comparatively free
+of errors, because I am forced to clarify my thoughts as I do the programming.
+By contrast, when writing for myself alone, I have often taken shortcuts that
+proved later to be dreadful mistakes. It's harder for me to fool myself in
+such ways when I'm writing a \WEB\ program, because I'm in ``expository
+mode'' (analogous to classroom lecturing) whenever a \WEB\ is being spun.
+Ergo, less debugging time.
+
+Now that I am writing all my programs in \WEB, an unforeseen problem has,
+however, arisen: I suddenly have a collection of programs that seem quite
+beautiful in my own eyes, and I have a compelling urge to publish all of
+them so that everybody can admire these works of art. A nice little 10-page
+program can easily be written and debugged in an afternoon and evening;
+if I keep accumulating such gems, I'll soon run out of storage space,
+and my office will be encrusted with webs of my own making. There is no
+telling what will happen if lots of other people catch \WEB\ fever and
+start foisting their creations on each other. I can already envision the
+appearance of a new journal, to be entitled {\sl Webs}, for the publication
+of literate programs; I imagine that it will have a large backlog and
+a large group of dedicated editors and referees.
+
+\beginsection M. RELATED WORK
+
+Nothing about \WEB\ is really new; I have simply combined a bunch of
+ideas that have been in the air for a long time. I would like to
+summarize in the next few paragraphs the things that had the greatest
+influence on my thinking as I put those pieces together.
+
+George Forsythe wrote in 1966 that ``A useful algorithm is a substantial
+contribution to knowledge. Its publication constitutes an important
+piece of schol\-ar\-ship.''\ref\GEF{G. E. Forsythe, Algorithms for
+scientific computation. {\sl Communications of the ACM\/ \bf9}, 255--256
+(1966).} His comments have always inspired me to strive for excellence
+in programming, and they have played a major r\^^Dole in shaping my present
+view that it is worthwhile to consider {\it every\/} program as a
+work of literature.
+
+The design of \WEB\ was influenced primarily by the pioneering work
+of Pierre-Arnoul de Marneffe,\ref\deM{P. A. de Marneffe, {\sl Holon
+Programming}. Univ.~de Liege, Service D'Informatique (December, 1973).}$^,$%
+\ref\deMR{P. A. de Marneffe and D. Ribbens, Holon Programming, in
+A. G\"unther et al.\ (eds.), {\sl International Computing Symposium 1973\/},
+Amsterdam, North-Holland (1974).} whose research on what he called
+``Holon Programming'' has not received the attention it deserves. His
+work was, in turn, inspired by Arthur Koestler's excellent treatise
+on the structure of complex systems and organisms;\ref\Koest{A.
+Koestler, {\sl The Ghost in the Machine}. New York, Macmillan (1968).}
+thus we have another connection between programming and literature.
+A somewhat similar system was independently created by Edwin Towster.\ref\Tow%
+{E. Towster, A convention for explicit declaration of environments
+and top-down refinement of data. {\sl IEEE Transactions on Software
+Engineering\/ \bf SE--5}, 374--386 (1979).}
+
+I owe a great debt to Edsger Dijkstra, Tony Hoare, Ole-Johan Dahl, and
+Niklaus Wirth for opening my eyes to the importance of abstraction in the
+reading and writing of programs, and to Peter Naur for stressing the
+importance of a balance between formal and informal methods.
+
+Tony Hoare provided a special impetus for \WEB\ when he suggested in 1978
+that I should publish my program for \TeX. Since very few large-scale
+software systems were available in the literature, he had been trying to
+promote the publication of well-written programs. Hoare's suggestion was
+actually rather terrifying to me, and I'm sure he knew that he was posing
+quite a challenge. As a professor of computer science, I was quite
+comfortable publishing papers about toy problems that could be polished up
+nicely and presented in an elegant manner; but I had no idea how to take a
+piece of real software, with all the compromises necessary to make it
+useful to a large class of people on a wide variety of systems, and to open
+it up to public scrutiny. How could a supposedly respectable academic, like
+me, reveal the way he actually writes large programs? And could a large
+program be made intelligible? My previous attempts along these
+lines\ref\CF{D. E. Knuth, Computer-drawn flow charts. {\sl
+Communications of the ACM\/ \bf 6}, 555--563 (1963).} were by now
+hopelessly out of date. I decided that this would be a good time to try
+out de Marneffe's ideas; furthermore, the \TeX\ system itself provided me
+with new tools for printing and format control, so I suspected that it
+would be possible to obtain state-of-the-art documentation by making
+proper use of typography.
+
+It is interesting to reread some of the comments that Tony made ten years
+ago in his keynote address to the first ACM symposium on Principles
+of Programming Languages:\ref\Hoare{C. A. R. Hoare, {\sl Hints on
+Programming Language Design}. Stanford Computer Science Report CS403
+(October 1973).}
+\smallskip
+{\narrower\noindent
+Documentation must be regarded as an integral part of the process of
+design and coding. A good programming language will encourage and
+assist the programmer to write clear, self-documenting code, and even
+perhaps to develop and display a pleasant style of writing.
+\smallskip}
+\noindent He foresaw many future trends, but not the impending improvements in
+typesetting quality:
+\smallskip
+{\narrower\noindent
+It is of course possible for a compiler or service program to expand the
+abbreviations, fill in the defaults, and make explicit the assumptions.
+But in practice, experience shows that it is very unlikely that the
+output of a computer will ever be more readable than its input, except
+in such trivial but important aspects as improved indentation.
+\smallskip}
+
+Typographic formatting of computer programs has a long tradition, originating
+with {\mc ALGOL} and its immediate precursors. I'm not sure who made the
+first experiments, but I believe that the lion's share of the credit
+for developing excellent programming-language typography belongs to two
+people: Peter Naur, who edited the {\mc ALGOL~60} report\ref\Alg{P. Naur
+(ed.)~et al., Report on the algorithmic language ALGOL 60.
+{\sl Communications of the ACM\/ \bf3}, 299--314.} and gave special
+care to its presentation; and Myrtle Kellington, who served for many years
+as executive editor of ACM publications and set the standards that have
+been adopted by other journals. The computing profession owes much to
+these people, who made published programs so much more readable than they
+would otherwise have been; the magnitude of their contribution can only
+be appreciated by people who submit computer programs to journals
+like {\sl Acta Arithmetica\/} whose editors are unfamiliar with computer
+science. Bill McKeeman called attention to formatting issues when he
+published Algorithm~268, ``{\mc ALGOL~60} reference language editor,''
+in 1965.\ref\McK{W. M. McKeeman, Algorithm 268. {\sl Communications
+of the ACM\/ \bf8}, 667--668 (1965).} There has been a flowering of
+such algorithms in recent years; the papers by Oppen\ref\DO{D. Oppen,
+Prettyprinting. {\sl ACM Transactions on Programming Languages and
+Systems\/ \bf2}, 465--483 (1980).} and by Rose and Welsh\ref\RW{G. A.
+Rose and J. Welsh, Formatted programming languages. {\sl Software---%
+Practice \char'46\ Experience\/ \bf11}, 651--669 (1981).} are particularly
+noteworthy.
+
+I began to design \WEB\ in the spring of 1979, when I constructed a prototype
+system that was called {\tt DOC}. Luis Trabb~Pardo helped me to develop
+a suitable style of exposition at that time; then Ignacio Zabala~Salelles
+gave a {\tt DOC} a thorough test when he prepared a full implementation
+of \TeX\ in \PASCAL. Zabala's implementation was successfully transported
+to many different computers,\ref\Z{I. Zabala and L. Trabb Pardo,
+The status of the PASCAL implementation of \TeX. {\sl TUGboat\/ \bf1},
+16--17 (1980).}\silentref\ZZ{I. Zabala, \TeX-PASCAL and PASCAL compilers.
+{\sl TUGboat\/ \bf2} (1), 11--12 (1981).}\silentref\ZZZ{I. Zabala,
+Some feedback from PTEX installations. {\sl TUGboat\/ \bf2} (2), 16--19
+(1981).}$^-$\ref\ZZZZ{I. A. Zabala, How
+portable is PASCAL? Draft of paper in preparation (1982).}
+and this experience was of immense value to me when I cast \WEB\ into its
+present form in 1981. Since then many significant improvements have been
+suggested by my colleague David R. Fuchs, and I have also benefited from
+the experiences of a large number of outstanding people who volunteered to
+be guinea pigs for pre-released versions of \TeX. It's impossible for me
+to name everyone who has helped, but I would like to give special thanks
+to Arthur Samuel, Howard Trickey, Joe Weening, and Pierre MacKay for
+important contributions. I'm fortunate indeed to share a working
+environment with such stimulating people.
+
+When I originally designed the \WEB\ system, I spent about six
+weeks preparing the files {\tt TANGLE.WEB} and {\tt WEAVE.WEB},
+during which time I was continually changing the language and
+trying different styles of exposition. (The programs were neither
+long nor complicated, but this was rather intensive work, so I
+didn't get much else done during those six weeks. The first two
+weeks were actually spent drafting the first ten per cent of what
+is now {\tt TEX.WEB}.) Then I spent about six tedious hours with
+a text editor, hand-simulating the behavior of {\tt TANGLE} on
+{\tt TANGLE.WEB}, so that I had a program {\tt TANGLE.PAS} that
+was ripe for debugging. At first I had to correct errors both in
+{\tt TANGLE.WEB} and {\tt TANGLE.PAS}, but soon {\tt TANGLE} was
+working well enough that I needed only {\tt TANGLE.WEB} as a
+source file. Then {\tt WEAVE.WEB} could be tangled and debugged
+too. The total time to create ``Version~0'' of the \WEB\ system,
+including the language design and the time to debug the programs
+and write a brief manual for users, was about eight weeks; then
+enhancements were added at the rate of about one per month for
+the next 18 months. As a result of this experience I think it's
+reasonable to state that a {\tt WEB}-like system can be created
+from scratch in a fairly short time, for some other pair of
+languages besides \TeX\ and \PASCAL, by an expert system
+programmer who is conversant with both languages. Indeed, I spoke
+about \WEB\ on a recent visit to London and one of the people in
+the audience decided to test this hypothesis; shortly afterwards I
+received an elegant report from Harold Thimbleby, who had just constructed
+an excellent system called {\tt Cweb}, based on Troff/Nroff and {\mc
+C} instead of \TeX\ and \PASCAL.\ref\Thim{H. Thimbleby, {\sl Cweb}.
+Preprint, University of York (August 1983).}
+
+\beginsection N. RETROSPECT AND PROSPECTS
+
+Enthusiastic reports about new computer languages, by the authors of those
+languages, are commonplace. Hence I'm well aware of the fact that my own
+experiences cannot be extrapolated too far. I also realize that, whenever I have
+encountered a problem with \WEB, I've simply changed
+the system; other users of \WEB\ cannot operate under the same ground rules.
+
+However, I believe that I have stumbled on a way of programming that produces
+better programs that are more port\-able and more easily understood and
+maintained; furthermore, the system seems to work with large programs as
+well as with small ones. I'm pleased that my work on typography, which
+began as an application of computers to another field, has come full circle
+and become an application of typography to the heart of
+computer science; I like to think of \WEB\ as a neat ``spinoff'' of my
+research on \TeX. However, all of my experiences with this system have
+been highly colored by my own tastes, and only time will tell if a large
+number of other people will find \WEB\ to be equally attractive and useful.
+
+I made a conscious decision not to design a language that would be
+suitable for everybody. My goal was to provide a tool for system
+programmers, not for high school students or for hobbyists. I don't have
+anything against high school students and hobbyists, but I don't believe
+every computer language should attempt to offer all things to all people.
+A user of \WEB\ needs to be good enough at computer science that he or she
+is comfortable dealing with several languages simultaneously. Since
+\WEB\ combines \TeX\ and \PASCAL\ with a few rules of its own, \WEB\ programs
+can contain \WEB\ syntax errors, \TeX\ syntax errors, \PASCAL\ syntax errors,
+and algorithmic errors; in practice, all four types of errors occur, and
+a bit of sophistication is needed to sort out which is which. Computer
+scientists tend to be better at such things than other people. I have found
+that \WEB\ programs can be debugged rapidly in spite of the profusion
+of languages, but I'm sure that many other intelligent people will find
+such a task difficult.
+
+In other words, \WEB\ seems to be specifically for the peculiar breed of
+people who are called computer scientists. And I'm pretty sure that there
+are also a lot of computer scientists who will not enjoy using \WEB; some
+of us are glad that traditional programming languages have comparatively
+primitive capabilities for inserted comments, because such difficulties provide
+a good excuse for not documenting programs well. Thus, \WEB\ may be only for the
+subset of computer scientists who like to write and to explain what they
+are doing. My hope is that the ability to make explanations more natural will
+cause more programmers to discover the joys of literate programming,
+because I believe it's quite a pleasure to combine verbal and mathematical
+skills; but perhaps I'm hoping for too much. The fact that at least one
+paper has been written that is a syntactically correct {\mc ALGOL 68}
+program\ref\ft{C. H. Lindsey, ALGOL 68 with fewer tears. {\sl The
+Computer Journal\/ \bf15}, 176--188 (1972).} encourages me to persevere
+in my hopes for the future. Perhaps we will even one day find Pulitzer
+prizes awarded to computer programs.
+
+And what about the future of \WEB? If the next year or so of trial use
+shows that a lot of other people besides myself become ``hooked'' on this
+method of programming, there will be many ways to incorporate the \WEB\
+philosophy into a really effective programming environment. For example,
+it will be worthwhile to produce a unified system that does both
+tangling and compiling, instead of using separate programs as in Figure~1;
+and it will also be worthwhile to carry the unification one step further,
+so that run-time debugging as well as syntactic debugging can be done
+entirely in terms of the \WEB\ source language. Furthermore, a \WEB-like
+system could be designed to incorporate additional modularization,
+so that it would be easier to compile different parts of a program
+independently. The new generation of graphic workstations makes it
+desirable to display selected program sections on demand, by using \TeX\
+only on the sections that are of current interest, instead of producing
+hardcopy for an entire document. And so on; a considerable amount of
+additional research and development will be appropriate if the idea
+of literate programming catches on.
+
+\bigskip\leftline{\bf Acknowledgements}
+\smallskip
+{\eightrm\baselineskip9pt
+\noindent The preparation of this paper was supported in part by
+the National Science Foundation under grants IST-8201926 and MCS-8300984,
+and by the System Development Foundation. `\TeX' is a trademark of the
+American Mathematical Society.\par}
+
+\enddoublecolumns % prepare for the references
+\bigskip\bigskip
+\hbox to\pagewidth{\hss\bf REFERENCES\hss\strut}
+\CJrule width\pagewidth
+\bigskip
+\begindoublecolumns
+\let\rm=\eightss \let\sl=\eightssi \let\bf=\eightssb \rm
+\baselineskip=9pt
+\tolerance=1000
+\references
+\bigskip
+\noindent
+Received September 1983
+\enddoublecolumns
+\kern6mm
+\CJrule width\pagewidth
+\bye
diff --git a/support/makeprog/docu/webmac.tex b/support/makeprog/docu/webmac.tex
new file mode 100644
index 0000000000..e4a5630ce5
--- /dev/null
+++ b/support/makeprog/docu/webmac.tex
@@ -0,0 +1,200 @@
+% standard macros for WEB listings (in addition to PLAIN.TEX)
+\xdef\fmtversion{\fmtversion+WEBMAC1.4}
+\parskip 0pt % no stretch between paragraphs
+\parindent 1em % for paragraphs and for the first line of Pascal text
+
+\font\eightrm=cmr8
+\let\sc=\eightrm \let\mainfont=\tenrm
+\font\titlefont=cmr7 scaled\magstep4 % title on the contents page
+\font\ttitlefont=cmtt10 scaled\magstep2 % typewriter type in title
+\font\tentex=cmtex10 % TeX extended character set (used in strings)
+
+\def\\#1{\hbox{\it#1\/\kern.05em}} % italic type for identifiers
+\def\|#1{\hbox{$#1$}} % one-letter identifiers look a bit better this way
+\def\&#1{\hbox{\bf#1\/}} % boldface type for reserved words
+\def\.#1{\hbox{\tentex % typewriter type for strings
+ \let\\=\BS % backslash in a string
+ \let\'=\RQ % right quote in a string
+ \let\`=\LQ % left quote in a string
+ \let\{=\LB % left brace in a string
+ \let\}=\RB % right brace in a string
+ \let\~=\TL % tilde in a string
+ \let\ =\SP % space in a string
+ \let\_=\UL % underline in a string
+ \let\&=\AM % ampersand in a string
+ #1}}
+\def\#{\hbox{\tt\char`\#}} % parameter sign
+\def\${\hbox{\tt\char`\$}} % dollar sign
+\def\%{\hbox{\tt\char`\%}} % percent sign
+\def\^{\ifmmode\mathchar"222 \else\char`^ \fi} % pointer or hat
+% circumflex accents can be obtained from \^^D instead of \^
+\def\AT!{@} % at sign for control text
+
+\chardef\AM=`\& % ampersand character in a string
+\chardef\BS=`\\ % backslash in a string
+\chardef\LB=`\{ % left brace in a string
+\def\LQ{{\tt\char'22}} % left quote in a string
+\chardef\RB=`\} % right brace in a string
+\def\RQ{{\tt\char'23}} % right quote in a string
+\def\SP{{\tt\char`\ }} % (visible) space in a string
+\chardef\TL=`\~ % tilde in a string
+\chardef\UL=`\_ % underline character in a string
+
+\newbox\bak \setbox\bak=\hbox to -1em{} % backspace one em
+\newbox\bakk\setbox\bakk=\hbox to -2em{} % backspace two ems
+
+\newcount\ind % current indentation in ems
+\def\1{\global\advance\ind by1\hangindent\ind em} % indent one more notch
+\def\2{\global\advance\ind by-1} % indent one less notch
+\def\3#1{\hfil\penalty#10\hfilneg} % optional break within a statement
+\def\4{\copy\bak} % backspace one notch
+\def\5{\hfil\penalty-1\hfilneg\kern2.5em\copy\bakk\ignorespaces}% optional break
+\def\6{\ifmmode\else\par % forced break
+ \hangindent\ind em\noindent\kern\ind em\copy\bakk\ignorespaces\fi}
+\def\7{\Y\6} % forced break and a little extra space
+
+\let\yskip=\smallskip
+\def\to{\mathrel{.\,.}} % double dot, used only in math mode
+\def\note#1#2.{\Y\noindent{\hangindent2em\baselineskip10pt\eightrm#1 #2.\par}}
+\def\lapstar{\rlap{*}}
+\def\startsection{\Q\noindent{\let\*=\lapstar\bf\modstar.\quad}}
+\def\defin#1{\global\advance\ind by 2 \1\&{#1 }} % begin `define' or `format'
+\def\A{\note{See also}} % cross-reference for multiply defined section names
+\def\B{\mathopen{\.{@\{}}} % begin controlled comment
+\def\C#1{\ifmmode\gdef\XX{\null$\null}\else\gdef\XX{}\fi % Pascal comments
+ \XX\hfil\penalty-1\hfilneg\quad$\{\,$#1$\,\}$\XX}
+\def\D{\defin{define}} % macro definition
+\def\E{\cdot10^} % exponent in floating point constant
+\def\F{\defin{format}} % format definition
+\let\G=\ge % greater than or equal sign
+\def\H#1{\hbox{\rm\char"7D\tt#1}} % hexadecimal constant
+\let\I=\ne % unequal sign
+\def\J{\.{@\&}} % TANGLE's join operation
+\let\K=\gets % left arrow
+\let\L=\le % less than or equal sign
+\outer\def\M#1.{\MN#1.\ifon\vfil\penalty-100\vfilneg % beginning of section
+ \vskip12ptminus3pt\startsection\ignorespaces}
+\outer\def\N#1.#2.{\MN#1.\vfil\eject % beginning of starred section
+ \def\rhead{\uppercase{\ignorespaces#2}} % define running headline
+ \message{*\modno} % progress report
+ \edef\next{\write\cont{\Z{#2}{\modno}{\the\pageno}}}\next % to contents file
+ \ifon\startsection{\bf\ignorespaces#2.\quad}\ignorespaces}
+\def\MN#1.{\par % common code for \M, \N
+ {\xdef\modstar{#1}\let\*=\empty\xdef\modno{#1}}
+ \ifx\modno\modstar \onmaybe \else\ontrue \fi \mark{\modno}}
+\def\O#1{\hbox{\rm\char'23\kern-.2em\it#1\/\kern.05em}} % octal constant
+\def\P{\rightskip=0pt plus 100pt minus 10pt % go into Pascal mode
+ \sfcode`;=3000
+ \pretolerance 10000
+ \hyphenpenalty 10000 \exhyphenpenalty 10000
+ \global\ind=2 \1\ \unskip}
+\def\Q{\rightskip=0pt % get out of Pascal mode
+ \sfcode`;=1500 \pretolerance 200 \hyphenpenalty 50 \exhyphenpenalty 50 }
+\let\R=\lnot % logical not
+\let\S=\equiv % equivalence sign
+\def\T{\mathclose{\.{@\}}}} % terminate controlled comment
+\def\U{\note{This code is used in}} % cross-reference for uses of sections
+\let\V=\lor % logical or
+\let\W=\land % logical and
+\def\X#1:#2\X{\ifmmode\gdef\XX{\null$\null}\else\gdef\XX{}\fi % section name
+ \XX$\langle\,$#2{\eightrm\kern.5em#1}$\,\rangle$\XX}
+\def\Y{\par\yskip}
+\let\Z=\let % now you can \send the control sequence \Z
+\def\){\hbox{\.{@\$}}} % sign for string pool check sum
+\def\]{\hbox{\.{@\\}}} % sign for forced line break
+\def\=#1{\kern2pt\hbox{\vrule\vtop{\vbox{\hrule
+ \hbox{\strut\kern2pt\.{#1}\kern2pt}}
+ \hrule}\vrule}\kern2pt} % verbatim string
+\let\~=\ignorespaces
+\let\*=*
+
+\def\onmaybe{\let\ifon=\maybe} \let\maybe=\iftrue
+\newif\ifon \newif\iftitle \newif\ifpagesaved
+\def\lheader{\mainfont\the\pageno\eightrm\qquad\rhead\hfill\title\qquad
+ \tensy x\mainfont\topmark} % top line on left-hand pages
+\def\rheader{\tensy x\mainfont\topmark\eightrm\qquad\title\hfill\rhead
+ \qquad\mainfont\the\pageno} % top line on right-hand pages
+\def\page{\box255 }
+\def\normaloutput#1#2#3{\ifodd\pageno\hoffset=\pageshift\fi
+ \shipout\vbox{
+ \vbox to\fullpageheight{
+ \iftitle\global\titlefalse
+ \else\hbox to\pagewidth{\vbox to10pt{}\ifodd\pageno #3\else#2\fi}\fi
+ \vfill#1}} % parameter #1 is the page itself
+ \global\advance\pageno by1}
+
+\def\rhead{\.{WEB} OUTPUT} % this running head is reset by starred sections
+\def\title{} % an optional title can be set by the user
+\def\topofcontents{\centerline{\titlefont\title}
+ \vfill} % this material will start the table of contents page
+\def\botofcontents{\vfill} % this material will end the table of contents page
+\def\contentspagenumber{0} % default page number for table of contents
+\newdimen\pagewidth \pagewidth=6.5in % the width of each page
+\newdimen\pageheight \pageheight=8.7in % the height of each page
+\newdimen\fullpageheight \fullpageheight=9in % page height including headlines
+\newdimen\pageshift \pageshift=0in % shift righthand pages wrt lefthand ones
+\def\magnify#1{\mag=#1\pagewidth=6.5truein\pageheight=8.7truein
+ \fullpageheight=9truein\setpage}
+\def\setpage{\hsize\pagewidth\vsize\pageheight} % use after changing page size
+\def\contentsfile{CONTENTS} % file that gets table of contents info
+\def\readcontents{\input CONTENTS}
+
+\newwrite\cont
+\output{\setbox0=\page % the first page is garbage
+ \openout\cont=\contentsfile
+ \global\output{\normaloutput\page\lheader\rheader}}
+\setpage
+\vbox to \vsize{} % the first \topmark won't be null
+
+\def\ch{\note{The following sections were changed by the change file:}
+ \let\*=\relax}
+\newbox\sbox % saved box preceding the index
+\newbox\lbox % lefthand column in the index
+\def\inx{\par\vskip6pt plus 1fil % we are beginning the index
+ \write\cont{} % ensure that the contents file isn't empty
+ \closeout\cont % the contents information has been fully gathered
+ \output{\ifpagesaved\normaloutput{\box\sbox}\lheader\rheader\fi
+ \global\setbox\sbox=\page \global\pagesavedtrue}
+ \pagesavedfalse \eject % eject the page-so-far and predecessors
+ \setbox\sbox\vbox{\unvbox\sbox} % take it out of its box
+ \vsize=\pageheight \advance\vsize by -\ht\sbox % the remaining height
+ \hsize=.5\pagewidth \advance\hsize by -10pt
+ % column width for the index (20pt between cols)
+ \parfillskip 0pt plus .6\hsize % try to avoid almost empty lines
+ \def\lr{L} % this tells whether the left or right column is next
+ \output{\if L\lr\global\setbox\lbox=\page \gdef\lr{R}
+ \else\normaloutput{\vbox to\pageheight{\box\sbox\vss
+ \hbox to\pagewidth{\box\lbox\hfil\page}}}\lheader\rheader
+ \global\vsize\pageheight\gdef\lr{L}\global\pagesavedfalse\fi}
+ \message{Index:}
+ \parskip 0pt plus .5pt
+ \outer\def\:##1, {\par\hangindent2em\noindent##1:\kern1em} % index entry
+ \let\ttentry=\. \def\.##1{\ttentry{##1\kern.2em}} % give \tt a little room
+ \def\[##1]{$\underline{##1}$} % underlined index item
+ \rm \rightskip0pt plus 2.5em \tolerance 10000 \let\*=\lapstar
+ \hyphenpenalty 10000 \parindent0pt}
+\def\fin{\par\vfill\eject % this is done when we are ending the index
+ \ifpagesaved\null\vfill\eject\fi % output a null index column
+ \if L\lr\else\null\vfill\eject\fi % finish the current page
+ \parfillskip 0pt plus 1fil
+ \def\rhead{NAMES OF THE SECTIONS}
+ \message{Section names:}
+ \output{\normaloutput\page\lheader\rheader}
+ \setpage
+ \def\note##1##2.{\hfil\penalty-1\hfilneg\quad{\eightrm##1 ##2.}}
+ \linepenalty=10 % try to conserve lines
+ \def\U{\note{Used in}} % cross-reference for uses of sections
+ \def\:{\par\hangindent 2em}\let\*=*\let\.=\ttentry}
+\def\con{\par\vfill\eject % finish the section names
+ \rightskip 0pt \hyphenpenalty 50 \tolerance 200
+ \setpage
+ \output{\normaloutput\page\lheader\rheader}
+ \titletrue % prepare to output the table of contents
+ \pageno=\contentspagenumber \def\rhead{TABLE OF CONTENTS}
+ \message{Table of contents:}
+ \topofcontents
+ \line{\hfil Section\hbox to3em{\hss Page}}
+ \def\Z##1##2##3{\line{\ignorespaces##1
+ \leaders\hbox to .5em{.\hfil}\hfil\ ##2\hbox to3em{\hss##3}}}
+ \readcontents\relax % read the contents info
+ \botofcontents \end} % print the contents page(s) and terminate
diff --git a/support/makeprog/dos/makeprog.cf1 b/support/makeprog/dos/makeprog.cf1
new file mode 100644
index 0000000000..b8345ef3d7
--- /dev/null
+++ b/support/makeprog/dos/makeprog.cf1
@@ -0,0 +1,58 @@
+% This is MAKEPROG.CF.STDOUT as of 02 May 89
+%--------------------------------------------------------
+% (c) 1988,1989 by J.Schrod.
+
+%
+% Changefile to map terminal output to standard output
+% assumes terminal output to be unbuffered
+%
+
+
+@x S 2
+program MAKEPROG(@!doc_file,@!change_file,@!prog_file);
+@y
+program MAKEPROG(@!output,@!doc_file,@!change_file,@!prog_file);
+@z
+
+
+@x S 20
+is assumed to consist of characters of type |text_char|:
+@^system dependencies@>
+
+@d print(#)==write(term_out,#) {`|print|' means write on the terminal}
+@d print_ln(#)==write_ln(term_out,#) {`|print|' and then start new line}
+@d new_line==write_ln(term_out) {start new line}
+@d print_nl(#)== {print information starting on a new line}
+ begin new_line; print(#);
+ end
+
+@<Globals...@>=
+@!term_out:text_file; {the terminal as an output file}
+@y
+is assumed to consist of characters of type |text_char|:
+@^system dependencies@>
+
+@d term_out == output {the output file is normaly the terminal}
+@#
+@d print(#)==write(term_out,#) {`|print|' means write on the terminal}
+@d print_ln(#)==write_ln(term_out,#) {`|print|' and then start new line}
+@d new_line==write_ln(term_out) {start new line}
+@d print_nl(#)== {print information starting on a new line}
+ begin new_line; print(#);
+ end
+@z
+
+
+@x S 21
+rewrite(term_out,'TTY:'); {send |term_out| output to the terminal}
+@y
+do_nothing; {|output| is opened automatically}
+@z
+
+
+@x S 22
+@d update_terminal == break(term_out) {empty the terminal output buffer}
+@y
+@d update_terminal == do_nothing {output to |output| is unbuffered}
+@z
+
diff --git a/support/makeprog/dos/makeprog.cf2 b/support/makeprog/dos/makeprog.cf2
new file mode 100644
index 0000000000..88cc2e3cdc
--- /dev/null
+++ b/support/makeprog/dos/makeprog.cf2
@@ -0,0 +1,140 @@
+% This is MAKEPROG.CF.SYSTEM.TURBO as of 02 May 89
+%--------------------------------------------------------
+% (c) 1988,1989 by J.Schrod.
+
+% Revision 1 was released in November, 1988.
+% Revision 2 switched to Turbo Pascal. (89-05-02)
+
+%
+% Changefile for system dependencies of Turbo-Pascal (V5.0)
+% documentation updates (too less...)
+% no non-local goto's (=> no global label end_of_MAKEPROG)
+% units CRT and DOS are used (???)
+% compiler directives
+% othercases
+% new_line is appended at end (for Compaq DOS 3.3!)
+%
+% I/O handling is done later
+%
+
+
+@x Limbo
+\def\version{1.0}
+@y
+ \let\maybe=\iffalse
+\def\version{1.0, Rev.~2}
+@z
+
+
+@x Limbo
+ \centerline{\titlefont The MAKEPROG processor}
+@y
+ \centerline{\titlefont DOS Changes to the MAKEPROG processor}
+@z
+
+
+@x S 1
+@d banner=='This is MAKEPROG, Version 1.0.'
+@y
+@d banner=='This is MAKEPROG, Version 1.0 (DOS Changes, Rev. 2).'
+@z
+
+
+@x
+@d end_of_MAKEPROG = 9999 {go here to wrap it up}
+@y
+@f uses == const
+@z
+
+
+@x S 2
+label end_of_MAKEPROG; {go here to finish}
+@y
+ uses CRT, DOS ;
+@z
+
+
+ the following change should be ignored after TIE
+
+@x S 3
+@d debug==@{ {change this to `$\\{debug}\equiv\null$' when debugging}
+@d gubed==@t@>@} {change this to `$\\{gubed}\equiv\null$' when debugging}
+@y
+@d debug== {we are debugging \.{MAKEPROG}}
+@d gubed==
+@z
+
+
+@x S 4
+@<Compiler directives@>=
+@{@&@=$D-@> @} {no debug overhead}
+@!debug @{@&@=$D+@> @}@+ gubed @; {but turn everything on when debugging}
+@y
+@<Compiler directives@>=
+@{@=$R-,B-,D-,E-,L-,S+,V-@>@}
+
+{ R- no range checking }
+{ B- boolean evaluation ... short circuit }
+{ D- debug information off }
+{ E- emulation off }
+{ L- local symbols ... off }
+{ S+ stack checking ... on }
+{ V- var string checking ... relaxed }
+@z
+
+
+@x S 7
+@d othercases == others: {default for cases not listed explicitly}
+@y
+@d othercases == else {default for cases not listed explicitly}
+@z
+
+
+@x S 31
+procedure jump_out;
+begin goto end_of_MAKEPROG;
+end;
+@y
+procedure jump_out;
+ begin
+ {here files should be closed if the operating system requires it}
+ @;@#
+ @<Print the job |history|@>;
+ halt;
+ end;
+@z
+
+
+@x
+end_of_MAKEPROG:
+ @#
+ {here files should be closed if the operating system requires it}
+ @;@#
+ @<Print the job |history|@>;
+@y
+ jump_out;
+@z
+
+
+@x S 187
+@<Print the job |history|@>=
+case history of
+spotless: print_nl('(No errors were found.)');
+harmless_message: print_nl('(Did you see the warning message above?)');
+error_message: print_nl('(Pardon me, but I think I spotted something wrong.)');
+fatal_message: print_nl('(That was a fatal error, my friend.)');
+end {there are no other cases}
+@y
+@<Print the job |history|@>=
+begin
+case history of
+ spotless: print_nl('(No errors were found.)');
+ harmless_message: print_nl('(Did you see the warning message above?)');
+ error_message:
+ print_nl('(Pardon me, but I think I spotted something wrong.)');
+ fatal_message: print_nl('(That was a fatal error, my friend.)');
+ end; {there are no other cases}
+new_line;
+end
+@z
+
diff --git a/support/makeprog/dos/makeprog.cf3 b/support/makeprog/dos/makeprog.cf3
new file mode 100644
index 0000000000..7ed17748c3
--- /dev/null
+++ b/support/makeprog/dos/makeprog.cf3
@@ -0,0 +1,230 @@
+% This is MAKEPROG.CF.IO.TURBO as of 02 May 89
+%--------------------------------------------------------
+% (c) 1989 by J.Schrod.
+
+%
+% Changefile for I/O handling with Turbo-Pascal (V5.0)
+% text_char is extended ASCII (up to chr(255))
+% text_file must be named text
+% tab marks should be recognized
+% binding of external files to internal file variables is not done by the
+% run time system, therefor reset and rewrite must be done with own
+% procedures
+% file name is taken from command line
+% files are buffered for higher performance
+% file access is done with a read/write in a string (no get/put available)
+% files must be closed (???)
+%
+
+
+@x S 2
+@t\4@>@<Error handling procedures@>@;
+@y
+@t\4@>@<Turbo Pascal specific procedures@>@;
+@t\4@>@<Error handling procedures@>@;
+@z
+
+
+@x S 12
+@d last_text_char=127 {ordinal number of the largest element of |text_char|}
+@y
+@d last_text_char=255 {ordinal number of the largest element of |text_char|}
+@z
+
+
+@x S 12
+@!text_file=packed file of text_char;
+@y
+@!text_file=text;
+@z
+
+
+@x S 17
+for i:=1 to " "-1 do xchr[i]:=' ';
+@y
+for i:=1 to " "-1 do xchr[i]:=' ';
+xchr[tab_mark] := chr(tab_mark);
+@z
+
+
+@x S 24
+reset(doc_file); reset(change_file);
+@y
+@< Initialize the Turbo Pascal specific input/output related variables @>;
+tp_reset(doc_file, 'DOC', doc_buffer);
+tp_reset(change_file, 'CHF', chf_buffer);
+@z
+
+
+@x S 26
+rewrite(prog_file);
+@y
+tp_rewrite(prog_file, prog_ext, prog_buffer);
+@z
+
+
+@x S 28 [ERROR]
+function input_ln(var f:text_file):boolean; {inputs a line or returns |false|}
+ var final_limit:0..buf_size; {|limit| without trailing blanks}
+ begin limit:=0; final_limit:=0;
+ if eof(f) then input_ln:=false
+ else begin
+ while not eoln(f) do
+ begin buffer[limit]:=xord[f^]; get(f);
+ incr(limit);
+ if (buffer[limit-1]<>" ") and (buffer[limit-1]<>tab_mark) then
+ final_limit:=limit;
+ if limit=buf_size then
+ begin while not eoln(f) do get(f);
+ decr(limit); {keep |buffer[buf_size]| empty}
+ print_nl('! Input line too long'); error; mark_error;
+@.Input line too long@>
+ end;
+ end;
+ read_ln(f); limit:=final_limit; input_ln:=true;
+ end;
+ end;
+@y
+function input_ln(var f:text_file):boolean; {inputs a line or returns |false|}
+ var s: string; {temporary line storage}
+ final_limit: 0..buf_size+1; {index into |s|}
+ i: 0..buf_size; {index into |buffer|}
+ begin
+ if eof(f) then
+ begin limit := 0; input_ln := false;
+ end
+ else begin read_ln(f,s);
+ final_limit := ord(s[0]);
+ while (final_limit > 0) and
+ ((s[final_limit] = ' ') or (s[final_limit] = xchr[tab_mark])) do
+ decr(final_limit);
+ if final_limit > buf_size+1 then final_limit := buf_size + 1;
+ for i:=0 to final_limit-1 do buffer[i] := xord[s[i+1]];
+ if final_limit >= buf_size then
+ begin final_limit := buf_size - 1; {keep |buffer[buf_size]| empty}
+ print_nl('! Input line too long'); error; mark_error;
+@.Input line too long@>
+ end;
+ limit := final_limit; input_ln := true ;
+ end;
+ end;
+@z
+
+
+@x S 31
+ {here files should be closed if the operating system requires it}
+@y
+ close(prog_file); close(doc_file); close(change_file);
+@z
+
+
+@x
+procedure put_line;
+ var i: 0..buf_size;
+ begin
+ for i:=0 to limit-1 do write(prog_file, xchr[buffer[i]]);
+ write_ln(prog_file);
+ end;
+@y
+procedure put_line;
+ var i: 0..buf_size;
+ s: string; {temporary line storage}
+ begin
+ for i:=0 to limit-1 do s[i+1] := xchr[buffer[i]];
+ s[0] := chr(limit); write_ln(prog_file, s);
+ end;
+@z
+
+
+@x S 188
+\noindent This module should be replaced, if necessary, by
+changes to the program that are necessary to make
+\MAKEPROG{} work at a particular installation. It is
+usually best to design your change file so that all changes
+to previous modules preserve the module numbering; then
+everybody's version will be consistent with the printed
+program. More extensive changes, which introduce new
+modules, can be inserted here; then only the index itself
+will get a new module number.
+@^system dependencies@>
+@y
+\noindent This module should be replaced, if necessary, by
+changes to the program that are necessary to make
+\MAKEPROG{} work at a particular installation. It is
+usually best to design your change file so that all changes
+to previous modules preserve the module numbering; then
+everybody's version will be consistent with the printed
+program. More extensive changes, which introduce new
+modules, can be inserted here; then only the index itself
+will get a new module number.
+@^system dependencies@>
+
+
+
+@* Resetting and rewriting files.
+
+\noindent Turbo Pascal allows the usage of command line
+parameters but does not connect external files with the
+internal file variables automatically. Therefore we demand
+the file name (without extension) in the command line---with
+this name we can open resp.\ create the files. The real
+opening of input files is done via |tp_reset| and the
+creating of output files is done via |tp_rewrite|. Both
+procedures have two parameters, the file variable and the
+extension which should be used together with the file name.
+The extension is passed without a dot.
+
+@< Glob... @>=
+@!file_name: string;
+@!prog_ext: string;
+
+
+@ But first we have to look at the command line. If there is
+no parameter present we print a usage message and finish the
+program afterwards. Here |jump_out| cannot be used because
+files would be closed that would be not open.
+
+@< Initialize the Turbo... @>=
+if param_count < 1 then
+ begin print('! usage: makeprog [-ext] file_name'); halt;
+ end
+else begin
+ file_name := param_str(1);
+ if (param_count = 2) and (file_name[1] = '-') then
+ begin prog_ext := copy(file_name, 2, 3); file_name := param_str(2);
+ end
+ else prog_ext := 'PRG';
+ end;
+
+
+@ @< Type... @>=
+@!file_buffer=packed array[1..4096] of byte;
+
+
+@ @< Glob... @>=
+@!doc_buffer:file_buffer; {file buffer for primary input}
+@!chf_buffer:file_buffer; {file buffer for updates}
+@!prog_buffer:file_buffer; {file buffer for output}
+
+
+@ If an input file can't be opened we handle it just like a
+file that is not there. I.e., we use \.{NUL:} as the input
+file---|eof| will then always return true as presumed by the
+program.
+
+@< Turbo Pascal specific procedures @>=
+procedure tp_reset( var f: text_file; ext: string; var buf: file_buffer );
+ begin assign(f, file_name+'.'+ext); @/
+ @{@=$I-@>@} reset(f); @{@=$I+@>@}
+ if io_result = 0 then settextbuf(f, buf)
+ else begin assign(f, 'NUL'); reset(f); { |eof(f) = true| }
+ end;
+ end;
+
+@#
+
+procedure tp_rewrite( var f: text_file; ext: string; var buf: file_buffer );
+ begin assign(f, file_name+'.'+ext); rewrite(f); settextbuf(f, buf);
+ end;
+@z
+
diff --git a/support/makeprog/dos/makeprog.chf b/support/makeprog/dos/makeprog.chf
new file mode 100644
index 0000000000..e2ddd3d7ce
--- /dev/null
+++ b/support/makeprog/dos/makeprog.chf
@@ -0,0 +1,349 @@
+@x
+\def\version{1.0.1}
+@y
+ \let\maybe=\iffalse
+\def\version{1.0.1, Rev.~2}
+@z
+
+@x
+ \centerline{\titlefont The MAKEPROG processor}
+@y
+ \centerline{\titlefont DOS Changes to the MAKEPROG processor}
+@z
+
+@x
+@d banner=='This is MAKEPROG, Version 1.0.1.'
+@y
+@d banner=='This is MAKEPROG, Version 1.0.1 (DOS Changes, Rev. 2).'
+@z
+
+@x
+@d end_of_MAKEPROG = 9999 {go here to wrap it up}
+@y
+@f uses == const
+@z
+
+@x
+program MAKEPROG(@!doc_file,@!change_file,@!prog_file);
+@y
+program MAKEPROG(@!output,@!doc_file,@!change_file,@!prog_file);
+@z
+
+@x
+label end_of_MAKEPROG; {go here to finish}
+@y
+ uses CRT, DOS ;
+@z
+
+@x
+@t\4@>@<Error handling procedures@>@;
+@y
+@t\4@>@<Turbo Pascal specific procedures@>@;
+@t\4@>@<Error handling procedures@>@;
+@z
+
+ x
+@d debug==@{ {change this to `$\\{debug}\equiv\null$' when debugging}
+@d gubed==@t@>@} {change this to `$\\{gubed}\equiv\null$' when debugging}
+ y
+@d debug== {we are debugging \.{MAKEPROG}}
+@d gubed==
+ z
+
+@x
+@<Compiler directives@>=
+@{@&@=$D-@> @} {no debug overhead}
+@!debug @{@&@=$D+@> @}@+ gubed @; {but turn everything on when debugging}
+@y
+@<Compiler directives@>=
+@{@=$R-,B-,D-,E-,L-,S+,V-@>@}
+
+{ R- no range checking }
+{ B- boolean evaluation ... short circuit }
+{ D- debug information off }
+{ E- emulation off }
+{ L- local symbols ... off }
+{ S+ stack checking ... on }
+{ V- var string checking ... relaxed }
+@z
+
+@x
+@d othercases == others: {default for cases not listed explicitly}
+@y
+@d othercases == else {default for cases not listed explicitly}
+@z
+
+@x
+@d last_text_char=127 {ordinal number of the largest element of |text_char|}
+@y
+@d last_text_char=255 {ordinal number of the largest element of |text_char|}
+@z
+
+@x
+@!text_file=packed file of text_char;
+@y
+@!text_file=text;
+@z
+
+@x
+for i:=1 to " "-1 do xchr[i]:=' ';
+@y
+for i:=1 to " "-1 do xchr[i]:=' ';
+xchr[tab_mark] := chr(tab_mark);
+@z
+
+@x
+is assumed to consist of characters of type |text_char|:
+@^system dependencies@>
+
+@d print(#)==write(term_out,#) {`|print|' means write on the terminal}
+@d print_ln(#)==write_ln(term_out,#) {`|print|' and then start new line}
+@d new_line==write_ln(term_out) {start new line}
+@d print_nl(#)== {print information starting on a new line}
+ begin new_line; print(#);
+ end
+
+@<Globals...@>=
+@!term_out:text_file; {the terminal as an output file}
+@y
+is assumed to consist of characters of type |text_char|:
+@^system dependencies@>
+
+@d term_out == output {the output file is normaly the terminal}
+@#
+@d print(#)==write(term_out,#) {`|print|' means write on the terminal}
+@d print_ln(#)==write_ln(term_out,#) {`|print|' and then start new line}
+@d new_line==write_ln(term_out) {start new line}
+@d print_nl(#)== {print information starting on a new line}
+ begin new_line; print(#);
+ end
+@z
+
+@x
+rewrite(term_out,'TTY:'); {send |term_out| output to the terminal}
+@y
+do_nothing; {|output| is opened automatically}
+@z
+
+@x
+@d update_terminal == break(term_out) {empty the terminal output buffer}
+@y
+@d update_terminal == do_nothing {output to |output| is unbuffered}
+@z
+
+@x
+reset(doc_file); reset(change_file);
+@y
+@< Initialize the Turbo Pascal specific input/output related variables @>;
+tp_reset(doc_file, 'DOC', doc_buffer);
+tp_reset(change_file, 'CHF', chf_buffer);
+@z
+
+@x
+rewrite(prog_file);
+@y
+tp_rewrite(prog_file, prog_ext, prog_buffer);
+@z
+
+@x
+function input_ln(var f:text_file):boolean; {inputs a line or returns |false|}
+ var final_limit:0..buf_size; {|limit| without trailing blanks}
+ begin limit:=0; final_limit:=0;
+ if eof(f) then input_ln:=false
+ else begin
+ while not eoln(f) do
+ begin buffer[limit]:=xord[f^]; get(f);
+ incr(limit);
+ if (buffer[limit-1]<>" ") and (buffer[limit-1]<>tab_mark) then
+ final_limit:=limit;
+ if limit=buf_size then
+ begin while not eoln(f) do get(f);
+ decr(limit); {keep |buffer[buf_size]| empty}
+ print_nl('! Input line too long'); error; mark_error;
+@.Input line too long@>
+ end;
+ end;
+ read_ln(f); limit:=final_limit; input_ln:=true;
+ end;
+ end;
+@y
+function input_ln(var f:text_file):boolean; {inputs a line or returns |false|}
+ var s: string; {temporary line storage}
+ final_limit: 0..buf_size+1; {index into |s|}
+ i: 0..buf_size; {index into |buffer|}
+ begin
+ if eof(f) then
+ begin limit := 0; input_ln := false;
+ end
+ else begin read_ln(f,s);
+ final_limit := ord(s[0]);
+ while (final_limit > 0) and
+ ((s[final_limit] = ' ') or (s[final_limit] = xchr[tab_mark])) do
+ decr(final_limit);
+ if final_limit > buf_size+1 then final_limit := buf_size + 1;
+ for i:=0 to final_limit-1 do buffer[i] := xord[s[i+1]];
+ if final_limit >= buf_size then
+ begin final_limit := buf_size - 1; {keep |buffer[buf_size]| empty}
+ print_nl('! Input line too long'); error; mark_error;
+@.Input line too long@>
+ end;
+ limit := final_limit; input_ln := true ;
+ end;
+ end;
+@z
+
+@x
+procedure jump_out;
+begin goto end_of_MAKEPROG;
+end;
+@y
+procedure jump_out;
+ begin
+ close(prog_file); close(doc_file); close(change_file);
+ @;@#
+ @<Print the job |history|@>;
+ halt;
+ end;
+@z
+
+@x
+procedure put_line;
+ var i: 0..buf_size;
+ begin
+ for i:=0 to limit-1 do write(prog_file, xchr[buffer[i]]);
+ write_ln(prog_file);
+ end;
+@y
+procedure put_line;
+ var i: 0..buf_size;
+ s: string; {temporary line storage}
+ begin
+ for i:=0 to limit-1 do s[i+1] := xchr[buffer[i]];
+ s[0] := chr(limit); write_ln(prog_file, s);
+ end;
+@z
+
+@x
+end_of_MAKEPROG:
+ @#
+ {here files should be closed if the operating system requires it}
+ @;@#
+ @<Print the job |history|@>;
+@y
+ jump_out;
+@z
+
+@x
+@<Print the job |history|@>=
+case history of
+spotless: print_nl('(No errors were found.)');
+harmless_message: print_nl('(Did you see the warning message above?)');
+error_message: print_nl('(Pardon me, but I think I spotted something wrong.)');
+fatal_message: print_nl('(That was a fatal error, my friend.)');
+end {there are no other cases}
+@y
+@<Print the job |history|@>=
+begin
+case history of
+ spotless: print_nl('(No errors were found.)');
+ harmless_message: print_nl('(Did you see the warning message above?)');
+ error_message:
+ print_nl('(Pardon me, but I think I spotted something wrong.)');
+ fatal_message: print_nl('(That was a fatal error, my friend.)');
+ end; {there are no other cases}
+new_line;
+end
+@z
+
+@x
+\noindent This module should be replaced, if necessary, by
+changes to the program that are necessary to make
+\MAKEPROG{} work at a particular installation. It is
+usually best to design your change file so that all changes
+to previous modules preserve the module numbering; then
+everybody's version will be consistent with the printed
+program. More extensive changes, which introduce new
+modules, can be inserted here; then only the index itself
+will get a new module number.
+@^system dependencies@>
+@y
+\noindent This module should be replaced, if necessary, by
+changes to the program that are necessary to make
+\MAKEPROG{} work at a particular installation. It is
+usually best to design your change file so that all changes
+to previous modules preserve the module numbering; then
+everybody's version will be consistent with the printed
+program. More extensive changes, which introduce new
+modules, can be inserted here; then only the index itself
+will get a new module number.
+@^system dependencies@>
+
+
+
+@* Resetting and rewriting files.
+
+\noindent Turbo Pascal allows the usage of command line
+parameters but does not connect external files with the
+internal file variables automatically. Therefore we demand
+the file name (without extension) in the command line---with
+this name we can open resp.\ create the files. The real
+opening of input files is done via |tp_reset| and the
+creating of output files is done via |tp_rewrite|. Both
+procedures have two parameters, the file variable and the
+extension which should be used together with the file name.
+The extension is passed without a dot.
+
+@< Glob... @>=
+@!file_name: string;
+@!prog_ext: string;
+
+
+@ But first we have to look at the command line. If there is
+no parameter present we print a usage message and finish the
+program afterwards. Here |jump_out| cannot be used because
+files would be closed that would be not open.
+
+@< Initialize the Turbo... @>=
+if param_count < 1 then
+ begin print('! usage: makeprog [-ext] file_name'); halt;
+ end
+else begin
+ file_name := param_str(1);
+ if (param_count = 2) and (file_name[1] = '-') then
+ begin prog_ext := copy(file_name, 2, 3); file_name := param_str(2);
+ end
+ else prog_ext := 'PRG';
+ end;
+
+
+@ @< Type... @>=
+@!file_buffer=packed array[1..4096] of byte;
+
+
+@ @< Glob... @>=
+@!doc_buffer:file_buffer; {file buffer for primary input}
+@!chf_buffer:file_buffer; {file buffer for updates}
+@!prog_buffer:file_buffer; {file buffer for output}
+
+
+@ If an input file can't be opened we handle it just like a
+file that is not there. I.e., we use \.{NUL:} as the input
+file---|eof| will then always return true as presumed by the
+program.
+
+@< Turbo Pascal specific procedures @>=
+procedure tp_reset( var f: text_file; ext: string; var buf: file_buffer );
+ begin assign(f, file_name+'.'+ext); @/
+ @{@=$I-@>@} reset(f); @{@=$I+@>@}
+ if io_result = 0 then settextbuf(f, buf)
+ else begin assign(f, 'NUL'); reset(f); { |eof(f) = true| }
+ end;
+ end;
+
+@#
+
+procedure tp_rewrite( var f: text_file; ext: string; var buf: file_buffer );
+ begin assign(f, file_name+'.'+ext); rewrite(f); settextbuf(f, buf);
+ end;
+@z
+
diff --git a/support/makeprog/filelist b/support/makeprog/filelist
new file mode 100644
index 0000000000..d29ce7b3eb
--- /dev/null
+++ b/support/makeprog/filelist
@@ -0,0 +1,29 @@
+./makeprog/COPYING
+./makeprog/Filelist
+./makeprog/History
+./makeprog/Readme
+./makeprog/docu/mkprgdoc.bbl
+./makeprog/docu/mkprgdoc.tex
+./makeprog/docu/primes.web
+./makeprog/docu/web.tex
+./makeprog/docu/webmac.tex
+./makeprog/src/doc2tex.l
+./makeprog/src/makeprog.web
+./makeprog/src/progdoc.doc
+./makeprog/src/progdoc.tex
+./makeprog/src/progltx.doc
+./makeprog/src/progltx.sty
+./makeprog/src/tex2doc.l
+./makeprog/WEBtoC/convert
+./makeprog/WEBtoC/makefile
+./makeprog/WEBtoC/makepext.c
+./makeprog/WEBtoC/makeprog.c
+./makeprog/WEBtoC/makeprog.ch
+./makeprog/WEBtoC/makeprog.h
+./makeprog/WEBtoC/web2c.def
+./makeprog/WEBtoC/web2c.h
+./makeprog/dos/makeprog.cf1
+./makeprog/dos/makeprog.cf2
+./makeprog/dos/makeprog.cf3
+./makeprog/dos/makeprog.chf
+./makeprog/dos/makeprog.exe
diff --git a/support/makeprog/history b/support/makeprog/history
new file mode 100644
index 0000000000..f852fb8dc5
--- /dev/null
+++ b/support/makeprog/history
@@ -0,0 +1,14 @@
+% History for MAKEPROG 06 Oct 90
+%------------------------------------------------------------
+
+% !! MSCF -- most significant change first !!
+
+DATE WHO REMARK
+90-10-06 js added doc2tex and tex2doc
+90-10-05 js begun history
+
+
+AUTHOR:
+ js: Joachim Schrod <xitijsch@ddathd21.bitnet>
+CONTRIBUTORS:
+ (-: place enough for your name :-)
diff --git a/support/makeprog/readme b/support/makeprog/readme
new file mode 100644
index 0000000000..0cd59c7cf9
--- /dev/null
+++ b/support/makeprog/readme
@@ -0,0 +1,44 @@
+% Readme for MAKEPROG 25 Sep 90
+%---------------------------------------------------------
+% (c) 1989,1990 by J.Schrod (TeXsys).
+
+This is the MAKEPROG system of structured documentation.
+It has the version number 1.0.1.
+
+These programs are given away to you under the conditions of the GNU
+General Public License. This license is described in the file COPYING.
+
+It is delivered either as a compressed tar or a ZOO archive. If you
+dearchive it with ZOO you should use "x//" as the extraction command
+to create all directories.
+ The following directory structure is used:
+
+ ./makeprog General files, like Readme and COPYING.
+ ./makeprog/src WEB source and TeX macro files
+ ./makeprog/docu documentation
+ ./makeprog/dos DOS executable and Turbo Pascal changefiles
+ ./makeprog/webtoc changefiles and resulting C source from WEBtoC
+
+I have included the article ``Literate Programming'' of Prof. Knuth
+in the DOCU subdirectory, it consists of the two files web.tex and
+primes.web. It should be read first because it focuses on the
+principles standing behind every WEB-like system. Afterwards a look
+should be taken on mkprgdoc.tex -- the user documentation of the
+MAKEPROG system. The installation procedure is described (very short)
+in a section of this report.
+ Please note that the DOS changefile makeprog.chf is produced by
+merging the changefiles makeprog.cf? with TIE and discarding the debug
+switches afterwards.
+
+
+Please send bug reports or enhancements to:
+
+ Detig Schrod \TeX{}sys
+ Joachim Schrod
+ Kranichweg 1
+
+ D-6074 R\"odermark-Urberach
+ FR Germany
+
+ Bitnet: XITIJSCH@DDATHD21
+----
diff --git a/support/makeprog/src/doc2tex.l b/support/makeprog/src/doc2tex.l
new file mode 100644
index 0000000000..fbe22e600a
--- /dev/null
+++ b/support/makeprog/src/doc2tex.l
@@ -0,0 +1,122 @@
+%{
+/* doc2tex.l 06 Oct 90
+ *---------------------------------------------------------
+ * (c) 1990 by J.Schrod.
+ * Copyright conditions: GNU General Public License
+ */
+
+/*
+ * VERSION HISTORY
+ *
+ * DATE REMARK
+ * 90-10-06 mentioned filelist WEBWARE for LISTSERV in Heidelberg,
+ * added tuglib
+ * 90-01-14 june.cs.washington.edu instead of cs.washington.edu
+ * 90-01-20 first version
+ */
+
+%}
+
+%S PREAMBLE COMMENT COPY
+
+
+%{
+#include <ctype.h>
+void hint_to_makeprog();
+%}
+
+
+%%
+
+%{
+#ifdef MSDOS
+ check_yycrank(); /* this should go into ncform... */
+#endif
+ BEGIN PREAMBLE;
+%}
+
+
+^\ *\n putc('\n', yyout);
+
+
+<PREAMBLE>^%.*\n ECHO;
+<PREAMBLE>^. {
+ hint_to_makeprog();
+ unput(yytext[0]); NLSTATE;
+ BEGIN COMMENT;
+ }
+
+<COMMENT>^\\beginprog.*\n {
+ fputs("%%% ", yyout); ECHO;
+ BEGIN COPY;
+ }
+<COMMENT>^.*\n {
+ fputs("%%% ", yyout); ECHO;
+ }
+
+<COPY>^\\endprog.*\n {
+ fputs("%%% ", yyout); ECHO;
+ BEGIN COMMENT;
+ }
+<COPY>^%%%.*\n {
+ fputs("%%% ", yyout); ECHO;
+ fprintf(stderr, "Macro code changed at line %d\n", yylineno-1);
+ }
+<COPY>^.*\n ECHO;
+
+
+.|\n {
+ register char c = yytext[0];
+ fprintf(stderr,
+ "! Illegal state at char %c (\"%02x) in line %d\n",
+ ( isprint(c) ? c : ' ' ),
+ (unsigned char)c,
+ ( c == '\n' ? yylineno-1 : yylineno )
+ );
+ }
+
+
+%%
+
+void hint_to_makeprog()
+{
+ fputs("%%%%\n",yyout);
+ fputs("%%%%\n",yyout);
+ fputs(
+ "%%%% These TeX macros were documented with the documentation system\n",
+ yyout);
+ fputs(
+ "%%%% MAKEPROG and automatically converted to the current form.\n",
+ yyout);
+ fputs(
+ "%%%% If you have MAKEPROG available you may transform it back to\n",
+ yyout);
+ fputs(
+ "%%%% the original input: Remove every occurence of three percents\n",
+ yyout);
+ fputs(
+ "%%%% and one optional blank from the beginning of a line and remove\n",
+ yyout);
+ fputs(
+ "%%%% every line which starts with four percents. The following lex\n",
+ yyout);
+ fputs(
+ "%%%% program will do this:\n",
+ yyout);
+ fputs("%%%%\n",yyout);
+ fputs("%%%% %%\n",yyout);
+ fputs("%%%%\n",yyout);
+ fputs("%%%% ^%%%\\ ? ;\n",yyout);
+ fputs("%%%% ^%%%%.*\\n ;\n",yyout);
+ fputs("%%%%\n",yyout);
+ fputs(
+ "%%%% MAKEPROG may be obtained over the net from the Bitnet-Listserver\n",
+ yyout);
+ fputs(
+ "%%%% LISTSERV@DHDURZ1 (filelist WEBWARE), from tuglib@science.utah.edu,\n",
+ yyout);
+ fputs("%%%% or via ftp from june.cs.washington.edu.\n", yyout);
+ fputs("%%%%\n",yyout);
+ fputs("%%%%\n",yyout);
+ return;
+}
diff --git a/support/makeprog/src/makeprog.web b/support/makeprog/src/makeprog.web
new file mode 100644
index 0000000000..0ef2f4989d
--- /dev/null
+++ b/support/makeprog/src/makeprog.web
@@ -0,0 +1,1171 @@
+% This is MAKEPROG.WEB as of 25 Sep 90
+%---------------------------------------------------------
+% (c) 1988 by J.Schrod.
+% Major parts of this program have been taken from TANGLE.WEB
+% by D.E.Knuth, which is not copyrighted.
+
+%
+% VERSION HISTORY (MSCF -- most significant change first)
+%
+% DATE VER WHO REMARK
+% 90-09-25 1.0.1 js updated copyright notice
+% 88-11 1.0 js first release
+
+% bug reports to:
+%
+% Detig$\,\cdot\,$Schrod \TeX{}sys
+% Joachim Schrod
+% Kranichweg 1
+%
+% D-6074 R\"odermark-Urberach
+% FR Germany
+%
+% Tel. (+6074) 1617
+% Bitnet: XITIJSCH@DDATHD21
+
+% author:
+% js: Joachim Schrod <xitijsch@ddathd21.bitnet>
+% contributors:
+% (-: place enough for your name! :-)
+
+
+\def\title{MAKEPROG (V\version)}
+\def\version{1.0.1}
+\def\years{1988,1990}
+
+\font\ninerm=cmr9
+\let\mc=\ninerm % medium caps for names like EBCDIC
+
+\def\hang{\hangindent 3em\indent\ignorespaces}
+\def\item#1{ % fixed item of 30pt width
+ {\parskip=0pt\endgraf\noindent}% % new line
+ \hangindent 30pt %
+ \hbox to 30pt{\hfil#1\kern 1em}%
+ \ignorespaces % ignore following blanks
+ }
+
+\def\PASCAL{Pascal}
+\def\MAKEPROG{\leavevmode\hbox{\mc MAKEPROG\/}}
+\def\ASCII{\leavevmode\hbox{\mc ASCII\/}}
+\mathchardef\BA="3224 % double arrow as relation
+
+\def\topofcontents{\null\vfill
+ \centerline{\titlefont The MAKEPROG processor}
+ \vskip 15pt
+ \centerline{(Version \version)}
+ \vskip 2cm}
+\def\botofcontents{\vfill
+ \hangindent 3em
+ \noindent $\copyright$ \years{} by Joachim Schrod.
+ All rights reserved.
+ \par \vskip 1ex
+ \noindent \MAKEPROG{} comes with {\bf absolutely no warranty}.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; see section~2 for details.
+ \par}
+
+
+
+
+
+@* Introduction. % sect. 1
+
+\noindent This program converts a documentation file to a
+program file, i.e.\ all files between \.{\\beginprog} and
+\.{\\endprog} are copied verbatim. It was written by
+J.~Schrod in September, 1987. This program is written in
+\.{WEB}.
+
+The program uses a few features of the local \PASCAL\
+compiler that may need to be changed in other installations:
+
+\item{1)} Case statements have a default.
+
+\item{2)} Input-output routines may need to be adapted for
+use with a particular character set and/or for printing
+messages on the user's terminal.
+
+\noindent System-dependent portions of \MAKEPROG{} can be
+identified by looking at the entries for `system
+dependencies' in the index below.
+@!@^system dependencies@>
+
+
+@ % sect. 2
+This program is free software; you can redistribute it and/or
+modify it under the terms of the \GNU{} General Public License as
+published by the Free Software Foundation; either version~1, or (at your
+option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+{\bf without any warranty\/}; without even the implied warranty of
+{\bf merchantability\/} or {\bf fitness for a particular purpose}. See
+the \GNU{} General Public License for more details.
+
+You should have received a copy of the \GNU{} General Public License
+along with this program; if not, write to the Free Software Foundation,
+Inc., 675~Mass Ave, Cambridge, MA~02139, USA.
+
+The ``banner line'' defined here should be changed whenever
+\MAKEPROG{} is modified. The copyright notice must not be deleted.
+
+@d banner=='This is MAKEPROG, Version 1.0.1.'
+@d copy_right==' (c) 1988,1990 by J.Schrod.'
+@d rights_res==' All rights reserved.'
+
+
+@ % sect. 3
+The program begins with a fairly normal header, made up of
+pieces that will mostly be filled in later. The input comes
+from files |doc_file| and |change_file|, the output goes to
+file |prog_file|. Messages from \MAKEPROG{} are written to
+|term_out|, which is supposed to be the terminal.
+@^system dependencies@>
+
+If it is necessary to abort the job because of a fatal
+error, the program calls the `|jump_out|' procedure, which
+goes to the label |end_of_MAKEPROG|.
+
+@d end_of_MAKEPROG = 9999 {go here to wrap it up}
+
+@p @t\4@>@<Compiler directives@>@/
+program MAKEPROG(@!doc_file,@!change_file,@!prog_file);
+label end_of_MAKEPROG; {go here to finish}
+const @<Constants in the outer block@>@;
+type @<Types in the outer block@>@;
+var @<Globals in the outer block@>@;
+@t\4@>@<Error handling procedures@>@;
+procedure initialize;
+ var @<Local variables for initialization@>@;
+ begin @<Set initial values@>
+ end;
+
+
+@ % sect. 4
+Some of this code is optional for use when debugging only;
+such material is enclosed between the delimiters \&{debug}
+and \&{gubed}.
+
+@d debug==@{ {change this to `$\\{debug}\equiv\null$' when debugging}
+@d gubed==@t@>@} {change this to `$\\{gubed}\equiv\null$' when debugging}
+@f debug==repeat
+@f gubed==until
+
+
+@ % sect. 5
+The \PASCAL\ compiler used to develop this system has
+``compiler directives'' that can appear in comments whose
+first character is a dollar sign. In production versions of
+\MAKEPROG{} these directives tell the compiler that it is
+safe to avoid range checks and to leave out the extra code
+it inserts for the \PASCAL\ debugger's benefit.
+@^system dependencies@>
+
+@<Compiler directives@>=
+@{@&@=$D-@> @} {no debug overhead}
+@!debug @{@&@=$D+@> @}@+ gubed @; {but turn everything on when debugging}
+
+
+@ % sect. 6
+Labels are given symbolic names by the following
+definitions. We insert the label `|exit|' just before the
+`\&{end}' of a procedure in which we have used the
+`|return|' statement defined below; the label `|restart|' is
+occasionally used at the very beginning of a procedure; and
+the label `|reswitch|' is occasionally used just prior to a
+\&{case} statement in which some cases change the conditions
+and we wish to branch to the newly applicable case. Loops
+that are set up with the \&{loop} construction defined below
+are commonly exited by going to `|done|' or to `|found|' or
+to `|not_found|', and they are sometimes repeated by going
+to `|continue|'.
+
+@d exit=10 {go here to leave a procedure}
+@d restart=20 {go here to start a procedure again}
+@d reswitch=21 {go here to start a case statement again}
+@d continue=22 {go here to resume a loop}
+@d done=30 {go here to exit a loop}
+@d found=31 {go here when you've found it}
+@d not_found=32 {go here when you've found something else}
+
+
+@ % sect. 7
+Here are some macros for common programming idioms.
+
+@d incr(#) == #:=#+1 {increase a variable by unity}
+@d decr(#) == #:=#-1 {decrease a variable by unity}
+@d loop == @+ while true do@+ {repeat over and over until a |goto| happens}
+@d do_nothing == {empty statement}
+@d return == goto exit {terminate a procedure call}
+@f return == nil
+@f loop == xclause
+
+
+@ % sect. 8
+We assume that |case| statements may include a default case
+that applies if no matching label is found. Thus, we shall
+use constructions like
+@^system dependencies@>
+$$
+\vbox{\halign{#\hfil\cr
+|case x of|\cr
+ \quad 1: $\langle\,$code for $x=1\,\rangle$;\cr
+ \quad 3: $\langle\,$code for $x=3\,\rangle$;\cr
+ \quad |othercases| $\langle\,$code for |x<>1| and |x<>3|$\,\rangle$\cr
+|endcases|\cr
+}}
+$$
+since most \PASCAL\ compilers have plugged this hole in the
+language by incorporating some sort of default mechanism.
+For example, the compiler used to develop \.{WEB} and \TeX\
+allows `|others|:' as a default label, and other \PASCAL s
+allow syntaxes like `\&{else}' or `\&{otherwise}' or
+`\\{otherwise}:', etc. The definitions of |othercases| and
+|endcases| should be changed to agree with local
+conventions. (Of course, if no default mechanism is
+available, the |case| statements of this program must be
+extended by listing all remaining cases.)
+
+@d othercases == others: {default for cases not listed explicitly}
+@d endcases == @+end {follows the default case in an extended |case| statement}
+@f othercases == else
+@f endcases == end
+
+
+@ % sect. 9
+The following parameter is set big enough to be sufficient
+for most applications of \MAKEPROG{}.
+
+@<Constants...@>=
+@!buf_size=500; {maximum length of input line}
+
+
+@ % sect. 10
+A global variable called |history| will contain one of four values
+at the end of every run: |spotless| means that no unusual messages were
+printed; |harmless_message| means that a message of possible interest
+was printed but no serious errors were detected; |error_message| means that
+at least one error was found; |fatal_message| means that the program
+terminated abnormally. The value of |history| does not influence the
+behavior of the program; it is simply computed for the convenience
+of systems that might want to use such information.
+
+@d spotless=0 {|history| value for normal jobs}
+@d harmless_message=1 {|history| value when non-serious info was printed}
+@d error_message=2 {|history| value when an error was noted}
+@d fatal_message=3 {|history| value when we had to stop prematurely}
+@#
+@d mark_harmless==@t@>@+if history=spotless then history:=harmless_message
+@d mark_error==history:=error_message
+@d mark_fatal==history:=fatal_message
+
+@<Glob...@>=@!history:spotless..fatal_message; {how bad was this run?}
+
+@ % sect. 11
+@<Set init...@>=history:=spotless;
+
+
+
+
+
+@* The character set. % sect. 12
+
+\noindent One of the main goals in the design of \MAKEPROG{}
+has been to make it readily portable between a wide variety
+of computers. Yet \MAKEPROG{} by its very nature must use a
+greater variety of characters than most computer programs
+deal with, and character encoding is one of the areas in
+which existing machines differ most widely from each other.
+
+To resolve this problem, all input to \MAKEPROG{} is
+converted to an internal seven-bit code that is essentially
+standard \ASCII{}, the ``American Standard Code for
+Information Interchange.'' The conversion is done
+immediately when each character is read in. Conversely,
+characters are converted from \ASCII{} to the user's
+external representation just before they are output. Such
+an internal code is never relevant to users of \MAKEPROG{}.
+
+\noindent Here is a table of the standard visible \ASCII{} codes:
+$$\def\:{\char\count255\global\advance\count255 by 1}
+\count255='40
+\vbox{
+\hbox{\hbox to 40pt{\it\hfill0\/\hfill}%
+\hbox to 40pt{\it\hfill1\/\hfill}%
+\hbox to 40pt{\it\hfill2\/\hfill}%
+\hbox to 40pt{\it\hfill3\/\hfill}%
+\hbox to 40pt{\it\hfill4\/\hfill}%
+\hbox to 40pt{\it\hfill5\/\hfill}%
+\hbox to 40pt{\it\hfill6\/\hfill}%
+\hbox to 40pt{\it\hfill7\/\hfill}}
+\vskip 4pt
+\hrule
+\def\^{\vrule height 10.5pt depth 4.5pt}
+\halign{\hbox to 0pt{\hskip -24pt\O{#0}\hfill}&\^
+\hbox to 40pt{\tt\hfill#\hfill\^}&
+&\hbox to 40pt{\tt\hfill#\hfill\^}\cr
+04&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule}
+05&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule}
+06&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule}
+07&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule}
+10&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule}
+11&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule}
+12&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule}
+13&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule}
+14&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule}
+15&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule}
+16&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule}
+17&\:&\:&\:&\:&\:&\:&\:\cr}
+\hrule width 280pt}$$
+(Actually, of course, code @"20 is an invisible blank
+space.) Code @"3E was once an upward arrow (\.{\char'13}),
+and code @"3F was once a left arrow (\.^^X), in olden times
+when the first draft of \ASCII{} code was prepared; but
+\MAKEPROG{} works with today's standard \ASCII{} in which
+those codes represent circumflex and underline as shown.
+
+@<Types...@>=
+@!ASCII_code=0..@"7F; {seven-bit numbers, a subrange of the integers}
+
+
+@ % sect. 13
+The original \PASCAL\ compiler was designed in the late 60s,
+when six-bit character sets were common, so it did not make
+provision for lowercase letters. Nowadays, of course, we
+need to deal with both capital and small letters in a
+convenient way, so \MAKEPROG{} assumes that it is being used
+with a \PASCAL\ whose character set contains at least the
+characters of standard \ASCII{} as listed above. Some
+\PASCAL\ compilers use the original name |char| for the data
+type associated with the characters in text files, while
+other \PASCAL s consider |char| to be a 64-element subrange
+of a larger data type that has some other name.
+
+In order to accommodate this difference, we shall use the
+name |text_char| to stand for the data type of the
+characters in the input and output files. We shall also
+assume that |text_char| consists of the elements
+|chr(first_text_char)| through |chr(last_text_char)|,
+inclusive. The following definitions should be adjusted if
+necessary.
+@^system dependencies@>
+
+@d text_char == char {the data type of characters in text files}
+@d first_text_char=0 {ordinal number of the smallest element of |text_char|}
+@d last_text_char=127 {ordinal number of the largest element of |text_char|}
+
+@<Types...@>=
+@!text_file=packed file of text_char;
+
+
+@ % sect. 14
+The \MAKEPROG{} processor convert between \ASCII{} code and
+the user's external character set by means of arrays |xord|
+and |xchr| that are analogous to \PASCAL's |ord| and |chr|
+functions.
+
+@<Globals...@>=
+@!xord: array [text_char] of ASCII_code;
+ {specifies conversion of input characters}
+@!xchr: array [ASCII_code] of text_char;
+ {specifies conversion of output characters}
+
+
+@ % sect. 15
+If we assume that every system using \.{WEB} is able to read
+and write the visible characters of standard \ASCII{}
+(although not necessarily using the \ASCII{} codes to
+represent them), the following assignment statements
+initialize most of the |xchr| array properly, without
+needing any system-dependent changes. For example, the
+statement \.{xchr["A"]:=\'A\'} that appears in the present
+\.{WEB} file might be encoded in, say, \hbox{\mc EBCDIC}
+code on the external medium on which it resides, but
+\.{TANGLE} will convert from this external code to \ASCII{}
+and back again. Therefore the assignment statement
+\.{XCHR[65]:=\'A\'} will appear in the corresponding
+\PASCAL\ file, and \PASCAL\ will compile this statement so
+that |xchr[65]| receives the character \.A in the external
+(|char|) code. Note that it would be quite incorrect to say
+\.{xchr["A"]:="A"}, because |"A"| is a constant of type
+|integer|, not |char|, and because we have $|"A"|=65$
+regardless of the external character set.
+
+@<Set init...@>=
+xchr[" "]:=' ';
+xchr["!"]:='!';
+xchr[""""]:='"';
+xchr["#"]:='#';
+xchr["$"]:='$';
+xchr["%"]:='%';
+xchr["&"]:='&';
+xchr["'"]:='''';@/
+xchr["("]:='(';
+xchr[")"]:=')';
+xchr["*"]:='*';
+xchr["+"]:='+';
+xchr[","]:=',';
+xchr["-"]:='-';
+xchr["."]:='.';
+xchr["/"]:='/';@/
+xchr["0"]:='0';
+xchr["1"]:='1';
+xchr["2"]:='2';
+xchr["3"]:='3';
+xchr["4"]:='4';
+xchr["5"]:='5';
+xchr["6"]:='6';
+xchr["7"]:='7';@/
+xchr["8"]:='8';
+xchr["9"]:='9';
+xchr[":"]:=':';
+xchr[";"]:=';';
+xchr["<"]:='<';
+xchr["="]:='=';
+xchr[">"]:='>';
+xchr["?"]:='?';@/
+xchr["@@"]:='@@';
+xchr["A"]:='A';
+xchr["B"]:='B';
+xchr["C"]:='C';
+xchr["D"]:='D';
+xchr["E"]:='E';
+xchr["F"]:='F';
+xchr["G"]:='G';@/
+xchr["H"]:='H';
+xchr["I"]:='I';
+xchr["J"]:='J';
+xchr["K"]:='K';
+xchr["L"]:='L';
+xchr["M"]:='M';
+xchr["N"]:='N';
+xchr["O"]:='O';@/
+xchr["P"]:='P';
+xchr["Q"]:='Q';
+xchr["R"]:='R';
+xchr["S"]:='S';
+xchr["T"]:='T';
+xchr["U"]:='U';
+xchr["V"]:='V';
+xchr["W"]:='W';@/
+xchr["X"]:='X';
+xchr["Y"]:='Y';
+xchr["Z"]:='Z';
+xchr["["]:='[';
+xchr["\"]:='\';
+xchr["]"]:=']';
+xchr["^"]:='^';
+xchr["_"]:='_';@/
+xchr["`"]:='`';
+xchr["a"]:='a';
+xchr["b"]:='b';
+xchr["c"]:='c';
+xchr["d"]:='d';
+xchr["e"]:='e';
+xchr["f"]:='f';
+xchr["g"]:='g';@/
+xchr["h"]:='h';
+xchr["i"]:='i';
+xchr["j"]:='j';
+xchr["k"]:='k';
+xchr["l"]:='l';
+xchr["m"]:='m';
+xchr["n"]:='n';
+xchr["o"]:='o';@/
+xchr["p"]:='p';
+xchr["q"]:='q';
+xchr["r"]:='r';
+xchr["s"]:='s';
+xchr["t"]:='t';
+xchr["u"]:='u';
+xchr["v"]:='v';
+xchr["w"]:='w';@/
+xchr["x"]:='x';
+xchr["y"]:='y';
+xchr["z"]:='z';
+xchr["{"]:='{';
+xchr["|"]:='|';
+xchr["}"]:='}';
+xchr["~"]:='~';@/
+xchr[0]:=' '; xchr[@"7F]:=' '; {these \ASCII{} codes are not used}
+
+
+@ % sect. 16
+Some of the nonprintable \ASCII{} codes have been given
+symbolic names in \MAKEPROG{} because they are used with a
+special meaning.
+
+@d tab_mark=@"09 {\ASCII{} code used as tab-skip}
+@d line_feed=@"0A {\ASCII{} code thrown away at end of line}
+@d form_feed=@"0C {\ASCII{} code used at end of page}
+@d carriage_return=@"0D {\ASCII{} code used at end of line}
+
+
+@ % sect. 17
+When we initialize the |xord| array and the remaining parts of |xchr|,
+it will be convenient to make use of an index variable, |i|.
+
+@<Local variables for init...@>=
+@!i:0..last_text_char;
+
+
+@ % sect. 18
+Here now is the system-dependent part of the character set.
+If \MAKEPROG{} is being implemented on a garden-variety
+\PASCAL\ for which only standard \ASCII{} codes will appear
+in the input and output files, you don't need to make any
+changes here.
+@^system dependencies@>
+
+Changes to the present module will make \MAKEPROG{} more
+friendly on computers that have an extended character set,
+so that one can type things like Umlaute. If you have an
+extended set of characters that are easily incorporated into
+text files, you can assign codes arbitrarily here, giving an
+|xchr| equivalent to whatever characters the users of
+\MAKEPROG{} are allowed to have in their input files,
+provided that unsuitable characters do not correspond to
+special codes like |carriage_return| that are listed above.
+
+@<Set init...@>=
+for i:=1 to " "-1 do xchr[i]:=' ';
+
+
+@ % sect. 19
+The following system-independent code makes the |xord| array
+contain a suitable inverse to the information in |xchr|.
+
+@<Set init...@>=
+for i:=first_text_char to last_text_char do xord[chr(i)]:=" ";
+for i:=1 to "~" do xord[xchr[i]]:=i;
+
+
+
+
+
+@* Basic Input and output. % sect. 20
+
+\noindent The input conventions of \MAKEPROG{} are identical
+to those of \.{WEB}. Therefore people who need to make
+modifications to both systems should be able to do so
+without too many headaches.
+
+
+@ % sect. 21
+Terminal output is done by writing on file |term_out|, which
+is assumed to consist of characters of type |text_char|:
+@^system dependencies@>
+
+@d print(#)==write(term_out,#) {`|print|' means write on the terminal}
+@d print_ln(#)==write_ln(term_out,#) {`|print|' and then start new line}
+@d new_line==write_ln(term_out) {start new line}
+@d print_nl(#)== {print information starting on a new line}
+ begin new_line; print(#);
+ end
+
+@<Globals...@>=
+@!term_out:text_file; {the terminal as an output file}
+
+
+@ % sect. 22
+Different systems have different ways of specifying that the
+output on a certain file will appear on the user's terminal.
+Here is one way to do this on the \PASCAL{} system that was
+used in \.{TANGLE}'s initial development.
+@^system dependencies@>
+
+@<Set init...@>=
+rewrite(term_out,'TTY:'); {send |term_out| output to the terminal}
+
+
+@ % sect. 23
+The |update_terminal| procedure is called when we want to
+make sure that everything we have output to the terminal so
+far has actually left the computer's internal buffers and
+been sent.
+@^system dependencies@>
+
+@d update_terminal == break(term_out) {empty the terminal output buffer}
+
+
+@ % sect. 24
+The main input comes from |doc_file|; this input may be
+overridden by changes in |change_file|. (If |change_file|
+is empty, there are no changes.)
+
+@<Globals...@>=
+@!doc_file:text_file; {primary input}
+@!change_file:text_file; {updates}
+
+
+@ % sect. 25
+The following code opens the input files. Since these files
+were listed in the program header, we assume that the
+\PASCAL\ runtime system has already checked that suitable
+file names have been given; therefore no additional error
+checking needs to be done.
+@^system dependencies@>
+
+@< Set init... @>=
+reset(doc_file); reset(change_file);
+
+
+@ % sect. 26
+The output goes to |prog_file|.
+
+@<Globals...@>=
+@!prog_file: text_file;
+
+
+@ % sect. 27
+The following code opens |prog_file|. Since this file is
+listed in the program header, we assume that the \PASCAL\
+runtime system has checked that a suitable external file
+name have been given.
+@^system dependencies@>
+
+@<Set init...@>=
+rewrite(prog_file);
+
+
+@ % sect. 28
+Input goes into an array called |buffer|.
+
+@<Globals...@>=
+@!buffer: array[0..buf_size] of ASCII_code;
+
+
+@ % sect. 29
+The |input_ln| procedure brings the next line of input from
+the specified file into the |buffer| array and returns the
+value |true|, unless the file has already been entirely
+read, in which case it returns |false|. The conventions of
+\.{WEB} are followed; i.e., |ASCII_code| numbers
+representing the next line of the file are input into
+|buffer[0]|, |buffer[1]|, \dots, |buffer[limit-1]|; trailing
+blanks are ignored; and the global variable |limit| is set
+to the length of the line. The value of |limit| must be
+strictly less than |buf_size|.
+@^system dependencies@>
+
+We assume that none of the |ASCII_code| values of
+|buffer[j]| for |0<=j<limit| is equal to 0, @"7F,
+|line_feed|, |form_feed|, or |carriage_return|.
+
+@p
+function input_ln(var f:text_file):boolean; {inputs a line or returns |false|}
+ var final_limit:0..buf_size; {|limit| without trailing blanks}
+ begin limit:=0; final_limit:=0;
+ if eof(f) then input_ln:=false
+ else begin
+ while not eoln(f) do
+ begin buffer[limit]:=xord[f^]; get(f);
+ incr(limit);
+ if (buffer[limit-1]<>" ") and (buffer[limit-1]<>tab_mark) then
+ final_limit:=limit;
+ if limit=buf_size then
+ begin while not eoln(f) do get(f);
+ decr(limit); {keep |buffer[buf_size]| empty}
+ print_nl('! Input line too long'); error; mark_error;
+@.Input line too long@>
+ end;
+ end;
+ read_ln(f); limit:=final_limit; input_ln:=true;
+ end;
+ end;
+
+
+
+
+
+@* Reporting errors to the user. % sect. 30
+
+\noindent Errors are reported to the user by saying
+$$
+ \hbox{`|err_print('! Error message')|'},
+$$
+followed by `|jump_out|' if no recovery from the error is
+provided. This will print the error message followed by an
+indication of where the error was spotted in the source
+file. Note that no period follows the error message, since
+the error routine will automatically supply a period.
+
+\noindent The actual error indications are provided by a
+procedure called |error|.
+
+@d err_print(#)==begin print_nl(#); error; mark_error; end
+
+@<Error handling...@>=
+procedure error; {prints '\..' and location of error message}
+ begin @< Print error location @>;
+ update_terminal;
+ end;
+
+
+@ % sect. 31
+The error locations can be indicated by using the global
+variables |line| and |changing|, which tell respectively the
+the current line number and whether or not the current line
+is from |change_file| or |doc_file|. This routine should be
+modified on systems whose standard text editor has special
+line-numbering conventions.
+@^system dependencies@>
+
+@< Print error location @>=
+begin
+if changing then print('. (change file ') @+ else print('. (');
+print_ln('l.', line:1, ')');
+print(' '); {this space separates the message from future output}
+end
+
+
+@ % sect. 32
+The |jump_out| procedure just cuts across all active
+procedure levels and jumps out of the program. This is the
+only non-local |goto| statement in \MAKEPROG{}. It is used
+when no recovery from a particular error has been provided.
+
+Some \PASCAL\ compilers do not implement non-local |goto| statements.
+@^system dependencies@>
+In such cases the code that appears at label
+|end_of_MAKEPROG| should be copied into the |jump_out|
+procedure, followed by a call to a system procedure that
+terminates the program.
+
+@d fatal_error(#)==begin print_nl(#); error; mark_fatal; jump_out;
+ end
+
+@<Error handling...@>=
+procedure jump_out;
+begin goto end_of_MAKEPROG;
+end;
+
+
+@ % sect. 33
+Sometimes the program's behavior is far different from what
+it should be, and \MAKEPROG{} prints an error message that
+is really for the \MAKEPROG{} maintenance person, not the
+user. In such cases the program says
+|confusion('indication of where we are')|.
+
+@d confusion(#)==fatal_error('! This can''t happen (',#,')')
+@.This can't happen@>
+
+
+
+
+
+@* The kernel. % sect. 34
+
+\noindent Let us now consider the routine |get_line| that
+takes care of merging |change_file| into |doc_file|. The
+|get_line| procedure also updates the line numbers for error
+messages.
+
+@<Globals...@>=
+@!line:integer; {the number of the current line in the current file}
+@!other_line:integer; {the number of the current line in the input file that
+ is not currently being read}
+@!temp_line:integer; {used when interchanging |line| with |other_line|}
+@!limit:0..buf_size; {the last character position occupied in the buffer}
+@!input_has_ended: boolean; {if |true|, there is no more input}
+@!changing: boolean; {if |true|, the current line is from |change_file|}
+
+
+@ % sect. 35
+As we change |changing| from |true| to |false| and back
+again, we must remember to swap the values of |line| and
+|other_line| so that the |err_print| routine will be sure to
+report the correct line number.
+
+@d change_changing==
+ begin changing := not changing;@/
+ temp_line:=other_line; other_line:=line; line:=temp_line;
+ end {$|line| \BA |other_line|$}
+
+
+@ % sect. 36
+When |changing| is |false|, the next line of |change_file|
+is kept in |change_buffer[0..change_limit-1]|, for purposes
+of comparison with the next line of |doc_file|. After the
+change file has been completely input, we set
+|change_limit:=0|, so that no further matches will be made.
+
+@<Globals...@>=
+@!change_buffer:array[0..buf_size] of ASCII_code;
+@!change_limit:0..buf_size; {the last position occupied in |change_buffer|}
+
+
+@ % sect. 37
+Here's a simple function that checks if the two buffers are
+different.
+
+@p function lines_dont_match:boolean;
+label exit;
+var k:0..buf_size; {index into the buffers}
+begin lines_dont_match:=true;
+if change_limit<>limit then return;
+if limit>0 then
+ for k:=0 to limit-1 do if change_buffer[k]<>buffer[k] then return;
+lines_dont_match:=false;
+exit: end;
+
+
+@ % sect. 38
+Procedure |prime_the_change_buffer| sets |change_buffer| in
+preparation for the next matching operation. Since blank
+lines in the change file are not used for matching, we have
+|(change_limit=0)and not changing| if and only if the change
+file is exhausted. This procedure is called only when
+|changing| is true; hence error messages will be reported
+correctly.
+
+@p procedure prime_the_change_buffer;
+label continue, done, exit;
+var k:0..buf_size; {index into the buffers}
+begin change_limit:=0; {this value will be used if the change file ends}
+@<Skip over comment lines in the change file; |return| if end of file@>;
+@<Skip to the next nonblank line; |return| if end of file@>;
+@<Move |buffer| and |limit| to |change_buffer| and |change_limit|@>;
+exit: end;
+
+
+@ % sect. 39
+While looking for a line that begins with \.{@@x} in the
+change file, we allow lines that begin with \.{@@}, as long
+as they don't begin with \.{@@y} or \.{@@z} (which would
+probably indicate that the change file is fouled up).
+
+@<Skip over comment lines in the change file...@>=
+loop@+ begin incr(line);
+ if not input_ln(change_file) then return;
+ if limit<2 then goto continue;
+ if buffer[0]<>"@@" then goto continue;
+ if (buffer[1]>="X")and(buffer[1]<="Z") then
+ buffer[1]:=buffer[1]+"z"-"Z"; {lowercasify}
+ if buffer[1]="x" then goto done;
+ if (buffer[1]="y")or(buffer[1]="z") then
+ err_print('! Where is the matching @@x?');
+@.Where is the match...@>
+continue: end;
+done:
+
+
+@ % sect. 40
+Here we are looking at lines following the \.{@@x}.
+
+@<Skip to the next nonblank line...@>=
+repeat incr(line);
+ if not input_ln(change_file) then
+ begin err_print('! Change file ended after @@x');
+@.Change file ended...@>
+ return;
+ end;
+until limit>0;
+
+
+@ % sect. 41
+@<Move |buffer| and |limit| to |change_buffer| and |change_limit|@>=
+begin change_limit:=limit;
+for k:=0 to limit-1 do change_buffer[k]:=buffer[k];
+end
+
+
+@ % sect. 42
+The following procedure is used to see if the next change
+entry should go into effect; it is called only when
+|changing| is false. The idea is to test whether or not the
+current contents of |buffer| matches the current contents of
+|change_buffer|. If not, there's nothing more to do; but if
+so, a change is called for: All of the text down to the
+\.{@@y} is supposed to match. An error message is issued if
+any discrepancy is found. Then the procedure prepares to
+read the next line from |change_file|.
+
+@p
+procedure check_change; {switches to |change_file| if the buffers match}
+label exit;
+var n:integer; {the number of discrepancies found}
+@!k:0..buf_size; {index into the buffers}
+begin if lines_dont_match then return;
+n:=0;
+loop@+ begin change_changing; {now it's |true|}
+ incr(line);
+ if not input_ln(change_file) then
+ begin err_print('! Change file ended before @@y');@/
+@.Change file ended...@>
+ change_limit:=0; change_changing; {|false| again}
+ return;
+ end;
+ @<If the current line starts with \.{@@y},
+ report any discrepancies and |return|@>;
+ @<Move |buffer| and |limit|...@>;
+ change_changing; {now it's |false|}
+ incr(line);
+ if not input_ln(doc_file) then
+ begin err_print('! CWEB file ended during a change');
+@.CWEB file ended...@>
+ input_has_ended:=true; return;
+ end;
+ if lines_dont_match then incr(n);
+ end;
+exit: end;
+
+
+@ % sect. 43
+@<If the current line starts with \.{@@y}...@>=
+if limit>1 then if buffer[0]="@@" then
+ begin if (buffer[1]>="X")and(buffer[1]<="Z") then
+ buffer[1]:=buffer[1]+"z"-"Z"; {lowercasify}
+ if (buffer[1]="x")or(buffer[1]="z") then
+ err_print('! Where is the matching @@y?')
+@.Where is the match...@>
+ else if buffer[1]="y" then
+ begin if n>0 then
+ err_print('! Hmm... ',n:1,' of the preceding lines failed to match');
+@.Hmm... n of the preceding...@>
+ return;
+ end;
+ end
+
+
+@ % sect. 44
+@< Initialize the input system @>=
+begin line:=0; other_line:=0;@/
+changing:=true; prime_the_change_buffer; change_changing;@/
+limit:=0; buffer[0]:=" "; input_has_ended:=false;
+end
+
+
+@ % sect. 45
+The |get_line| procedure puts the next line of merged input
+into the buffer and updates the other variables
+appropriately. A space is placed at the right end of the
+line. We output points to show the user the progress in
+reading.
+
+@p
+procedure get_line; {inputs the next line}
+ label restart;
+ begin
+restart: if changing then
+ @<Read from |change_file| and maybe turn off |changing|@>;
+ if not changing then
+ begin @<Read from |doc_file| and maybe turn on |changing|@>;
+ if changing then goto restart;
+ end;
+ buffer[limit]:=" ";
+ if (line mod 500) = 0 then
+ begin print(line:1); update_terminal;
+ end
+ else if (line mod 100) = 0 then
+ begin print('.'); update_terminal;
+ end
+ @!debug else begin print('.'); update_terminal; @+ end @+ gubed @;
+ ;@/
+ end;
+
+
+@ % sect. 46
+@<Read from |doc_file|...@>=
+begin incr(line);
+if not input_ln(doc_file) then input_has_ended:=true
+else if change_limit>0 then check_change;
+end
+
+
+@ % sect. 47
+@<Read from |change_file|...@>=
+begin incr(line);
+if not input_ln(change_file) then
+ begin err_print('! Change file ended without @@z');
+@.Change file ended...@>
+ buffer[0]:="@@"; buffer[1]:="z"; limit:=2;
+ end;
+if limit>1 then {check if the change has ended}
+ if buffer[0]="@@" then
+ begin if (buffer[1]>="X")and(buffer[1]<="Z") then
+ buffer[1]:=buffer[1]+"z"-"Z"; {lowercasify}
+ if (buffer[1]="x")or(buffer[1]="y") then
+ err_print('! Where is the matching @@z?')
+@.Where is the match...@>
+ else if buffer[1]="z" then
+ begin prime_the_change_buffer; change_changing;
+ end;
+ end;
+end
+
+
+@ % sect. 48
+At the end of the program, we will tell the user if the
+change file had a line that didn't match any relevant line
+in |doc_file|.
+
+@<Check that all changes have been read@>=
+begin
+if change_limit<>0 then {|changing| is false}
+ begin
+ for limit:=0 to change_limit do buffer[limit] := change_buffer[limit];
+ limit := change_limit; changing := true; line := other_line;
+ err_print('! Change file entry did not match');
+@.Change file entry did not match@>
+ end;
+end
+
+
+@ % sect. 49
+The |put_line| procedure outputs the next line from
+|buffer| to |prog_file|. Perhaps we should give here a
+progress report, too (with asterisks?)
+
+@p
+procedure put_line;
+ var i: 0..buf_size;
+ begin
+ for i:=0 to limit-1 do write(prog_file, xchr[buffer[i]]);
+ write_ln(prog_file);
+ end;
+
+
+
+
+
+@* The main program. % sect. 50
+
+\noindent We have defined some procedures, and it is time to
+use them---here is where \MAKEPROG{} starts, and where it
+ends.
+@^system dependencies@>
+
+@p
+ begin initialize;
+ print_ln(banner); {print a ``banner line''}
+ print_ln(copy_right); print_ln(rights_res); {print a copyright notice}
+ @< Initialize the input system @>;
+ debug print_ln('begin copy');
+ gubed @;
+ @< Copy all program parts to the output @>;
+ debug print_ln('end copy');
+ gubed @;
+ @< Check that all changes... @>;
+end_of_MAKEPROG:
+ @#
+ {here files should be closed if the operating system requires it}
+ @;@#
+ @<Print the job |history|@>;
+ end.
+
+
+@ % sect. 51
+A program part begins after a line that begins with
+\.{\\beginprog} and ends before the next line with
+\.{\\endprog} starting it. If we find the starting line we
+set |state| to |begin_prog|, between to lines |state| has
+the value |inner_prog| and with the ending line |state| is
+set to |out_of_prog|.
+
+@d begin_prog = 0
+@d inner_prog = 1
+@d out_of_prog = 2
+
+@< Glob... @>=
+@!state: begin_prog..out_of_prog;
+
+@ % sect. 52
+@< Set init... @>=
+state := out_of_prog;
+
+
+@ % sect. 53
+After we have read the introducing line for a program part
+which is signaled with |state=begin_prog| we change the
+state to |inner_prog| to start copy the next line;
+
+@< Copy all program... @>=
+begin get_line;
+while not input_has_ended do
+ begin @< Look at the input line and store in |state| the result @>;
+ if state = inner_prog then put_line
+ else if state = begin_prog then state := inner_prog;
+ get_line;
+ end;
+if state = inner_prog then err_print('! Input has ended prematurely');
+@.Input has ended...@>
+end
+
+
+@ % sect. 54
+We first define a few macros to improve the readability of
+the program part behind. After \.{\\beginprog} no letters
+may appear and after \.{\\endprog} either the line is ended
+or white space is to be there. The comparison is facilitated
+by the fact that |buffer[limit]=" "|, i.e.\ the last
+character of a line is always a space.
+
+@d cmp_prog(#) == (buffer[#]="p") and (buffer[#+1]="r") and
+ (buffer[#+2]="o") and (buffer[#+3]="g")
+@d cmp_begin == (buffer[1]="b") and (buffer[2]="e") and (buffer[3]="g") and@|
+ (buffer[4]="i") and (buffer[5]="n") and cmp_prog(6) and@|
+ ((buffer[10]<"A") or (buffer[10]>"Z")) and@|
+ ((buffer[10]<"a") or (buffer[10]>"z"))
+@d cmp_end == (buffer[1]="e") and (buffer[2]="n") and (buffer[3]="d") and
+ cmp_prog(4) and @|
+ ((buffer[8]=" ") or (buffer[8]=tab_mark))
+
+@< Look at the input... @>=
+begin
+if buffer[0] = "\" then
+ if limit >= 10 then
+ begin @+ if cmp_begin then state := begin_prog; @+ end
+ else if limit >= 8 then
+ if cmp_end then state := out_of_prog;
+end
+
+
+@ % sect. 55
+Some implementations may wish to pass the |history| value to the
+operating system so that it can be used to govern whether or not other
+programs are started. Here we simply report the history to the user.
+@^system dependencies@>
+
+@<Print the job |history|@>=
+case history of
+spotless: print_nl('(No errors were found.)');
+harmless_message: print_nl('(Did you see the warning message above?)');
+error_message: print_nl('(Pardon me, but I think I spotted something wrong.)');
+fatal_message: print_nl('(That was a fatal error, my friend.)');
+end {there are no other cases}
+
+
+
+
+
+@* System-dependent changes. % sect. 56
+
+\noindent This module should be replaced, if necessary, by
+changes to the program that are necessary to make
+\MAKEPROG{} work at a particular installation. It is
+usually best to design your change file so that all changes
+to previous modules preserve the module numbering; then
+everybody's version will be consistent with the printed
+program. More extensive changes, which introduce new
+modules, can be inserted here; then only the index itself
+will get a new module number.
+@^system dependencies@>
+
+
+
+
+
+@* Index. % sect. 57
+
+\noindent Here is a cross-reference table for the
+\MAKEPROG{} processor. All modules in which an identifier
+is used are listed with that identifier, except that
+reserved words are indexed only when they appear in format
+definitions, and the appearances of identifiers in module
+names are not indexed. Underlined entries correspond to
+where the identifier was declared. Error messages and a few
+other things like ``system dependencies'' are indexed here
+too.
+
diff --git a/support/makeprog/src/progdoc.doc b/support/makeprog/src/progdoc.doc
new file mode 100644
index 0000000000..d85bd0ca9c
--- /dev/null
+++ b/support/makeprog/src/progdoc.doc
@@ -0,0 +1,668 @@
+% progdoc.doc 21 Sep 90
+%------------------------------------------------------------
+% (c) 1988-1990 by J.Schrod. Copyright conditions see below.
+
+%
+% Macro package for the documentation of programs (and TeX macros)
+% MAKEPROG is needed
+%
+
+%
+% VERSION HISTORY (MSCF -- most significant change first)
+%
+% DATE WHO REMARK
+% 90-09-21 js table of contents and headline added.
+% 89-09-08 js repaired initialization of \char_count.
+% 89-06-30 js Definition of \beginverbatim/\endverbatim.
+% 88-12-05 js first version (for ftp/Bitnet).
+
+% bug reports to:
+%
+% Detig$\,\cdot\,$Schrod \TeX{}sys
+% Joachim Schrod
+% Kranichweg 1
+%
+% D-6074 R\"odermark-Urberach
+% FR Germany
+%
+% Tel. (+6074) 1617
+% Bitnet: XITIJSCH@DDATHD21
+
+% author:
+% js: Joachim Schrod <xitijsch@ddathd21.bitnet>
+% contributors:
+% (-: place enough for your name! :-)
+
+
+% documented with itself...
+\input progdoc
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% local macros
+%
+
+\font\mc=cmr9 % for names like ASCII
+\font\sc=cmcsc10 % caps and small caps 10pt
+
+\def\WEB{{\tt WEB\/}}
+\def\LaTeX{{\rm L\kern-.36em\raise.3ex\hbox{\sc a}\kern-.15em\TeX}}
+\def\GNU{{\mc GNU}}
+
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+
+
+\title{{\tt progdoc} --- A {\tt WEB\/}-like Markup}
+
+
+
+
+
+\chap Introduction.
+
+\WEB{} systems allow the documentation of programs by supporting the
+separation in program fragments which can be collected and rearranged
+afterwards. This allows {\it top-down\/} programming as well as the
+{\it bottom-up\/} design of programs. Each program fragment can be
+documented, usually with \TeX{}. The creation of a new \WEB{} system
+has become easy with the introduction of Spider \WEB{} but even within
+Spider \WEB{} the lexical analysis is bound to languages of the Algol
+family. Building up \WEB{} systems for languages which are line
+oriented or even for ``exotic'' programming languages like \TeX{}
+(with a dynamic lexical, syntactical and semantical structure) remains
+to be difficult.
+
+This macro package was built to allow good documentation for programs
+in languages for which \WEB{} does not exist. It separates a program
+text in sections that can be documented. All sections, collected
+sequentially, will result in the complete program. In each section
+begin and end of the program part are marked with |\beginprog| and
+|\endprog|, this program part will be formatted as is input
+(``verbatim'').
+
+The separation of the sections is done in this version (which is
+based on Plain~\TeX{}) by the macros |\chap| and |\sect|. In the
+documentation part of a section text pieces, e.g.\ names of
+variables, can be inserted verbatim to demonstrate the connection to
+the program text. These parts are included in vertical bars
+(`{\tt\vbar}') while the vertical bar itself can be obtained by
+|\origvert|. Longer text parts can be printed verbatim by enclosing
+them in |\beginverbatim| and |\endverbatim| which behaves like
+|\beginprog| and |\endprog| except that the text between is not
+copied to the program file.
+
+This macro package does not offer the creation of an index because it
+is not known which syntactical tokens the language has that should be
+mentioned in an index. As well the creation of a table of contents
+and of headings would be preferable to allow better orientation in the
+document. Some remarks about future enhancements which should be done
+urgently are set in slanted type.
+
+
+\sect This program is free software; you can redistribute it and/or
+modify it under the terms of the \GNU{} General Public License as
+published by the Free Software Foundation; either version~1, or (at your
+option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+{\bf without any warranty\/}; without even the implied warranty of
+{\bf merchantability\/} or {\bf fitness for a particular purpose}. See
+the \GNU{} General Public License for more details.
+
+You should have received a copy of the \GNU{} General Public License
+along with this program; if not, write to the Free Software Foundation,
+Inc., 675~Mass Ave, Cambridge, MA~02139, USA.
+
+
+\sect We have to realize three parts: (1)~the formatting of rather
+small verbatim texts in a line, (2)~the formatting of larger parts of
+program and (3)~the document structuring elements for the separation
+of the sections.
+
+But before we start we declare some shorthands for category codes. By
+declaring the at sign~(`|@|') as well as the underscore~`(|_|)' as
+letters we can use them in our macros. (I agree with D.~Knuth that
+|\identifier_several_words_long| is more readable than
+|\IdentifierSeveralWordsLong| and in every case better than |\p@@@s|.)
+With the at sign we can use the ``private'' Plain macros and with the
+underscore we can make our own macros more readable. But as we have
+to restore these category codes at the end of this macro file we store
+their former values in the control sequences |\atcode| and |\uscode|.
+This method is better than to use a group because not all macros have
+to be defined global this way.
+
+\beginprog
+\chardef\escape=0
+\chardef\subscript=8
+\chardef\letter=11
+\chardef\other=12
+%\chardef\active=13 % is defined in Plain already
+
+\chardef\atcode=\catcode`\@
+\chardef\uscode=\catcode`\_
+
+\catcode`\@=\letter
+\catcode`\_=\letter
+\endprog
+
+
+
+
+\chap Local Verbatim Formatting.
+
+The main point of every verbatim formatting is the switching of the
+character codes of all characters that have a special meaning for
+\TeX{}. This can be done with the control sequence |\dospecials| that
+applies the control sequence |\do| to all special characters.
+Additionally, every line is regarded as a paragraph without
+indentation. Between two paragraphs, i.e.\ between two lines, no
+extra space is set. Finally all blanks and tab characters shall be
+obeyed and the inter word space after sentence terminators shall not
+be enlarged. The activation of the tab character expansion with
+|\obeytabs| is analog to |\obeyspaces| in {\tt plain.tex\/}.
+
+Verbatim texts are set in monospace, we use (like in \WEB{}) the
+character set with the extended {\mc ASCII}.
+
+\beginprog
+\font\tentex=cmtex10 % typewriter extended ASCII 10pt
+\let\ttex=\tentex % only for PLAIN with base size 10pt
+
+\def\setup_verbatim{%
+ \def\do##1{\catcode`##1\other}\dospecials
+ \parskip\z@skip \parindent\z@
+ \obeylines \obeyspaces \obeytabs \frenchspacing
+ \ttex
+ }
+
+\let\tab=\space
+\begingroup
+ \catcode`\^^I=\active% % Attention: no tabs!
+ \gdef\obeytabs{\catcode`\^^I=\active\def^^I{\tab}}
+ \global\let^^I=\tab% % if an active tab appears in a \write
+\endgroup
+\endprog
+
+\sect After having saved the old meaning of `{\tt\vbar}' in
+|\origvert| and after declaring |\vbar| as a synonym for the character
+that has the code of a vertical bar in the current font, the vertical
+bar can be made active. Then we call |\setup_verbatim|. But the
+newline characters shall not be processed, they shall be treated as
+blank space. This can be done by defining |\par| as |\space|.
+
+The next vertical bar in the input closes the group which becomes an
+(unbreakable) |\hbox| then. The old meanings of the special
+characters and of the vertical bar are restored and \TeX{} is in
+normal (horizontal) mode again.
+
+\beginprog
+\let\origvert=|
+\chardef\vbar=`\|
+
+\catcode`\|=\active
+
+\def|{%
+ \leavevmode
+ \hbox\bgroup
+ \let\par\space \setup_verbatim
+ \let|\egroup
+ }
+\endprog
+
+
+
+
+\chap Program Fragments in Verbatim.
+
+We need macros to format the program fragments without any
+linebreaking. Such a text area shall start with the macro
+|\beginprog| resp.\ |\beginverbatim| and end with |\endprog|
+resp.\ |\endverbatim|. The end macros must stand
+at the very beginning of a line and must be followed by white space
+(blank, tab or newline character). After all these macros
+the rest of the line is ignored.
+
+Two demands must be regarded: There should be no length restrictions
+for the processed text, and the tab characters should be expanded
+so that this macro works on PC's and on VAXes, too.
+
+
+\sect The implementation method is quite simple: We read the next
+line, test, wether the end is reached (by comparing with the end line)
+and otherwise set the line actually read. Every character is
+inspected and tabular characters are expanded.
+
+The verbatim text is started with |\begin_verbatim| which will be
+either called by |\beginprog| or by |\beginverbatim|. These macros
+will also define the contents of the end line.
+
+Whether a line is set or whether the end of the processed area is
+reached is indicated by the switch |\if@print|. At the beginning of
+the |\begin_verbatim| macro most settings are done with
+|\setup_verbatim| (the vertical bar must be handled separately)
+and the rest of the line is ignored. As everything is done within
+a group, the end of the verbatim text can be processed by simply
+closing this group.
+
+For the user it looks as if |\endprog| or |\endverbatim|
+terminates the processing, but
+it just serves for the identification of the end, the true processing
+is done with the internal macro |\end_verbatim|.
+
+\beginprog
+\newif\if@print
+
+\def\begin_verbatim{%
+ \endgraf
+ \bigbreak
+ \begingroup
+ \setup_verbatim \catcode`\|\other
+ \@printtrue
+ \ignore_rest_line
+ }
+\let\end_verbatim=\endgroup % internal command !
+\endprog
+
+
+\sect The first line is ignored, all the other lines are identified
+with |\set_next_line| and processed with |\do_set|. This separation
+in identification and processing allows that the line end character is
+active in the definition only for a short time.
+
+When a line is to be formatted, we first check with |\check_print|
+whether it contains |\endprog|, otherwise it is printed with
+|\print_char|. The printing must be done for every character
+individually because we want to check for tab characters; the
+exact algorithm is described below. Here we just have to note that
+|\print_char| is used with two parameters of which the second one is
+terminated with the token |\end_line|. The first parameter is the first
+character of the line, the second parameter is the rest of the line.
+If the line is empty, the argument of |\do_set| is empty, too; so the
+activation of |\print_char| must be finished with two |\end_line|.
+Then the first |\end_line| is the first argument for |\print_char| and
+the second argument is empty. But if the line did contain something,
+the second |\end_line| is evaluated, for this case it is defined as
+|\relax|.
+
+Finally we call |\set_next_line| again to format the next line. If
+the end is reached, i.e.\ if a line with |\endprog| was found,
+|\set_next_line| is redefined as |\relax|. This can be done because
+the original meaning is restored when the group is closed by
+|\end_verbatim|.
+
+\beginprog
+\begingroup
+ \obeylines% % ^^M is active! ==> every line must end with %
+ \gdef\ignore_rest_line#1^^M{\set_next_line}%
+ \gdef\set_next_line#1^^M{\do_set{#1}}%
+\endgroup
+
+\def\do_set#1{%
+ \endgraf
+ \check_print{#1}%
+ \if@print \indent \print_char#1\end_line\end_line
+ \else \let\set_next_line\end_verbatim
+ \fi
+ \set_next_line
+ }
+\let\end_line=\relax
+\endprog
+
+
+\sect Before we attack the problem of formatting a line, we declare
+|\check_print| that checks the end of the verbatim mode. We have to
+do two things: we must split everything in front of the first blank
+or tab character and compare it with |\endprog|. The splitting is easy
+because the line which is our first argument contains blanks and
+tabulators as active characters. First we call |\cut_at_tab| that
+demands a tab character as separator for its two parameters so that
+everything in the line in front of the first tabulator is part of the
+first parameter. If there is no tab character in the line, we append
+one so that the second parameter is empty. The same trick is used to
+separate the part in front of the first blank character from the
+resulting first part.
+
+The check is done with |\do_check|. We use a separate macro here so
+that we can indent it (in the following definition blanks are active!)
+
+\beginprog
+\begingroup
+\obeyspaces\obeytabs
+\gdef\check_print#1{\cut_at_tab#1^^I\end_line}
+\gdef\cut_at_tab#1^^I#2\end_line{\check_first_part#1 \end_line}% blank !
+\gdef\check_first_part#1 #2\end_line{\do_check{#1}}
+\endgroup
+\endprog
+
+
+\sect |\do_check| compares the line with a sample line that is
+available in |\end_verbatim_line|. This macro will be defined later.
+
+\beginprog
+\def\do_check#1{%
+ \def\@line{#1}%
+ \ifx \@line\end_verbatim_line \@printfalse
+ \fi
+ }
+\endprog
+
+
+\sect Now we can set a line: we start with the first character,
+followed by the rest of the line. Each character is counted in
+|\char_count|. At the beginning of a line |\char_count| is~0, it
+is reset at the end of the line.
+
+\beginprog
+\newcount\char_count \char_count\z@
+
+\def\print_char#1#2\end_line{%
+ \print_first_char{#1}%
+ \print_rest_of_line{#2}%
+ }
+\endprog
+
+
+\sect For each character that is set |\char_count| is incremented.
+If a character is a tabulator, we set with |\print_tab| the required
+amount of blank characters, otherwise the character itself. We must
+compare the character that is stored in |\@char| with a macro whose
+``first-level'' expansion is an active tabulator. For this case we
+declare |\@tab|.
+
+\beginprog
+{\obeytabs\gdef\@tab{^^I}}
+
+\def\print_first_char#1{%
+ \def\@char{#1}%
+ \advance \char_count\@ne
+ \ifx \@char\@tab \print_tab
+ \else \@char
+ \fi
+ }
+\endprog
+
+
+\sect If we want to fill the line with blank spaces up to the next
+column with a number that can be divided by~8, we must be able to
+compute the column number modulo~8, but \TeX{} has no modulo operator.
+So we define the macro |\mod_viii| that computes its argument modulo~8
+and returns the result in the counter |\count_mod_viii|. For the
+computation we use the temporary counter |\count@|.
+
+\beginprog
+\newcount\count_mod_viii
+\def\mod_viii#1{%
+ \count@ #1\relax \count_mod_viii\count@
+ \divide \count@ 8\relax
+ \multiply \count@ 8\relax
+ \advance \count_mod_viii -\count@
+ }
+\endprog
+
+
+\sect Now we can declare |\print_tab|. We must remember that
+|\char_count| was incremented already, if we set only one blank
+character the counter keeps untouched.
+
+\beginprog
+\def\print_tab{%
+ \loop \space \mod_viii\char_count
+ \ifnum \count_mod_viii>\z@
+ \advance \char_count\@ne
+ \repeat
+ }
+\endprog
+
+
+\sect If the rest of the line is empty, we have finished the task.
+|\char_count| is reset to~0 for the next line.
+
+Inside the |\else| part of |\ifx| |\print_char| should not be used
+directly because this costs too much storage of \TeX{}. Instead we
+set a control sequence |\next| that is processed afterwards, depending
+on the result of the comparison. If there is still something to set,
+we use |\print_char| again, otherwise a syntactically similar macro
+that expands to |\relax|.
+
+\beginprog
+\def\print_rest_of_line#1{%
+ \def\@line{#1}%
+ \ifx \@line\empty \char_count\z@
+ \def\next##1\end_line{\relax}%
+ \else \let\next\print_char
+ \fi
+ \next#1\end_line
+ }
+\endprog
+
+
+\sect Now we are ready to define the two ``user accessible'' macros
+|\beginprog| and |\beginverbatim|. They must define the prototyp end
+line |\end_verbatim_line| which will be compared against every line
+in the verbatim text. During the definition of
+|\end_verbatim_line| it must be cared for that the escape character~`|\|'
+is a printable character: A comparison with |\ifx| demands identical
+category codes. As a temporary escape character we use the slash.
+
+\beginprog
+{\catcode`\/=\escape \catcode`\\=\other % / is temporary escape char
+ /gdef/beginprog{%
+ /gdef/end_verbatim_line{\endprog}%
+ /begin_verbatim
+ }
+ /gdef/beginverbatim{%
+ /gdef/end_verbatim_line{\endverbatim}%
+ /begin_verbatim
+ }
+} % here \endgroup can't be used
+\endprog
+
+
+
+
+\chap Document Structuring.
+
+The layout of the document shall be like in \WEB{}; this can be done
+easily in Plain. A document -- which may have a title -- consists of
+sections which are numbered. We distinguish between main sections
+which start a group of sections and between normal sections within a
+group. Main sections have a title, a table of contents with all
+titles is output at the end.
+
+
+\sect The number of the current section is stored in the counter
+|\sectno|.
+
+\beginprog
+\newcount\sectno \sectno=\@ne
+
+\newtoks\title \title{}
+\endprog
+
+
+\sect As usual, the name |\toc_file_name| of the table of contents
+file |\toc_file| is built from the jobname and the extension |toc|.
+We open the file and output a |\relax| so we are save that something
+is in the file and it can be read in later without any difficulties.
+
+In this file lines are written with the main section numbers, their
+titles, and their page numbers, respectively. Every line is marked
+with |\tocline| which is assumed to have the given three parameters.
+Now we define |\tocline| to be |\relax| so that |\write| does not
+expand it.
+
+\beginprog
+\def\toc_file_name{\jobname.toc } % <--- Space!!
+\newwrite\toc_file
+
+\immediate\openout\toc_file=\toc_file_name
+\immediate\write\toc_file{\relax}
+
+\let\tocline=\relax
+\endprog
+
+
+\sect We want a headline with the current section number, the
+document title, the last main section title, and the page number. The
+footline is empty.
+
+To realize this headline every section must |\mark| it's section
+number {\it in front of\/} a potentiel page break (so the number may
+be accessed by |\topmark|) and every main section must define
+|\main_title| to be it's title.
+
+\beginprog
+\headline{%
+ \tenrm
+ \S\topmark \qquad \the\title
+ \hfil
+ \main_title \qquad \tenrm \folio
+ }
+\footline{\hfil}
+\endprog
+
+
+\sect But this does not work the way it should: On the first page
+|\topmark| will be always empty! Here we borrow a trick from
+|webmac.tex|, we insert a first garbage page which will be discarded
+by the output routine.
+
+\beginprog
+\vbox to \vsize{}
+
+\output={%
+ \setbox\z@ \vbox{\unvbox\@cclv}% % throw away the first page
+ \global\output{\plainoutput}% % restore Plain output routine
+ }
+\endprog
+
+
+\sect The main sections are started with the macro |\chap|. It has
+one parameter, the title of the section group. This parameter must
+be terminated by a dot. We start a new page, typeset the title in
+bold face and separate it from the section text with a |\medskip|.
+This text, the first paragraph of the documentation part of the
+section, is formatted without paragraph indentation.
+
+At the beginning of the new page we output the section number, the
+title, and the page number to the contents file. We must take care to
+expand the section number right now because it will be incremented
+and would not be the correct value during the output routine.
+
+The deletion of the paragraph indentation is done with |\everypar|.
+We do not care if |\everypar| is used for something else and delete it
+after usage.
+
+\beginprog
+\def\chap#1.{%
+ \endgraf
+ \mark{\number\sectno}% % gather information for headline
+ \vfill\supereject
+ \begingroup
+ \def\protect##1{\string ##1 }% % <--- Space!!
+ \edef\write_toc_sectno{\write\toc_file{\tocline{\number\sectno}}}%
+ \write_toc_sectno
+ \write\toc_file{{#1}{\folio}}%
+ \endgroup
+ \gdef\main_title{#1}% % more information for headline
+ \noindent {\bf \number\sectno.\quad #1.}%
+ \global\advance \sectno\@ne
+ \endgraf
+ \medskip \nobreak
+ \everypar{% % remove next parindent
+ \setbox0\lastbox
+ \global\everypar{}%
+ }%
+ }
+\endprog
+
+
+\sect Normal sections are started with |\sect|. This macro has no
+parameter. Between two paragraphs we set 2~pica space (if possible)
+and prefer the page breaking. Between the section number and the text
+one quad of space is set.
+
+\begingroup \sl
+The page break manipulation should be more sophisticated.
+\endgroup
+
+\beginprog
+\def\sect{%
+ \endgraf
+ \mark{\number\sectno}% % gather information for headline
+ \vskip 2pc plus 1pc minus 6dd \goodbreak
+ \noindent {\bf \number\sectno.}\quad \ignorespaces
+ \global\advance \sectno\@ne
+ }
+\endprog
+
+
+\sect At the end we add a page with the table of contents. This is
+triggered by |\bye|. If the user does not want this table he may use
+|\byebye|.
+
+\beginprog
+\def\byebye{\par\vfil\supereject\end} % original definition of \bye
+\def\bye{%
+ \endgraf
+ \vfill \supereject
+ \immediate\closeout\toc_file
+ \message{Table of contents:}%
+ \leftskip\z@skip \rightskip\z@skip
+ \parskip\z@skip \parindent\z@ \parfillskip\z@skip
+ \normalbaselines
+ \headline{\hfil}%
+ \footline{\hfil \folio \hfil}%
+ \def\HeaderToc{\rightline{Section\hbox to\thr@@ em{\hss Page}}}%
+ \def\tocline##1##2##3{%
+ \line{%
+ \ignorespaces ##2%
+ \leaders\hbox to .5em{.\hfil}\hfil
+ \ ##1%
+ \hbox to \thr@@ em{\hss ##3}%
+ }%
+ }
+ \pageno\m@ne % table of contents gets roman page numbers
+ \topofcontents % may redefine \HeaderToc and \tocline!
+ \HeaderToc
+ \catcode`\@\letter % @ and _ are letters (for reading private macros)
+ \catcode`\_\letter
+ \input \toc_file_name
+ \catcode`\@\atcode % @ and _ are no more letters
+ \catcode`\_\uscode
+ \botofcontents
+ \byebye % print the contents page(s) and terminate
+ }
+
+\font\titlefont=cmr7 scaled\magstep4 % title on the contents page
+\font\ttitlefont=cmtt10 scaled\magstep2 % typewriter type in title
+\def\topofcontents{
+ \null \vfill
+ \centerline{\let\tt\ttitlefont \titlefont \the\title}
+ \vskip 1cm
+ }
+\def\botofcontents{
+ \vfill\vfill
+ }
+\endprog
+
+
+\sect We are finished and just have to restore the category codes.
+
+\beginprog
+\catcode`\@=\atcode
+\catcode`\_=\uscode
+
+\endinput
+\endprog
+
+
+
+
+
+\bye
+
diff --git a/support/makeprog/src/progdoc.tex b/support/makeprog/src/progdoc.tex
new file mode 100644
index 0000000000..da52668952
--- /dev/null
+++ b/support/makeprog/src/progdoc.tex
@@ -0,0 +1,217 @@
+\chardef\escape=0
+\chardef\subscript=8
+\chardef\letter=11
+\chardef\other=12
+%\chardef\active=13 % is defined in Plain already
+
+\chardef\atcode=\catcode`\@
+\chardef\uscode=\catcode`\_
+
+\catcode`\@=\letter
+\catcode`\_=\letter
+\font\tentex=cmtex10 % typewriter extended ASCII 10pt
+\let\ttex=\tentex % only for PLAIN with base size 10pt
+
+\def\setup_verbatim{%
+ \def\do##1{\catcode`##1\other}\dospecials
+ \parskip\z@skip \parindent\z@
+ \obeylines \obeyspaces \obeytabs \frenchspacing
+ \ttex
+ }
+
+\let\tab=\space
+\begingroup
+ \catcode`\^^I=\active% % Attention: no tabs!
+ \gdef\obeytabs{\catcode`\^^I=\active\def^^I{\tab}}
+ \global\let^^I=\tab% % if an active tab appears in a \write
+\endgroup
+\let\origvert=|
+\chardef\vbar=`\|
+
+\catcode`\|=\active
+
+\def|{%
+ \leavevmode
+ \hbox\bgroup
+ \let\par\space \setup_verbatim
+ \let|\egroup
+ }
+\newif\if@print
+
+\def\begin_verbatim{%
+ \endgraf
+ \bigbreak
+ \begingroup
+ \setup_verbatim \catcode`\|\other
+ \@printtrue
+ \ignore_rest_line
+ }
+\let\end_verbatim=\endgroup % internal command !
+\begingroup
+ \obeylines% % ^^M is active! ==> every line must end with %
+ \gdef\ignore_rest_line#1^^M{\set_next_line}%
+ \gdef\set_next_line#1^^M{\do_set{#1}}%
+\endgroup
+
+\def\do_set#1{%
+ \endgraf
+ \check_print{#1}%
+ \if@print \indent \print_char#1\end_line\end_line
+ \else \let\set_next_line\end_verbatim
+ \fi
+ \set_next_line
+ }
+\let\end_line=\relax
+\begingroup
+\obeyspaces\obeytabs
+\gdef\check_print#1{\cut_at_tab#1^^I\end_line}
+\gdef\cut_at_tab#1^^I#2\end_line{\check_first_part#1 \end_line}% blank !
+\gdef\check_first_part#1 #2\end_line{\do_check{#1}}
+\endgroup
+\def\do_check#1{%
+ \def\@line{#1}%
+ \ifx \@line\end_verbatim_line \@printfalse
+ \fi
+ }
+\newcount\char_count \char_count\z@
+
+\def\print_char#1#2\end_line{%
+ \print_first_char{#1}%
+ \print_rest_of_line{#2}%
+ }
+{\obeytabs\gdef\@tab{^^I}}
+
+\def\print_first_char#1{%
+ \def\@char{#1}%
+ \advance \char_count\@ne
+ \ifx \@char\@tab \print_tab
+ \else \@char
+ \fi
+ }
+\newcount\count_mod_viii
+\def\mod_viii#1{%
+ \count@ #1\relax \count_mod_viii\count@
+ \divide \count@ 8\relax
+ \multiply \count@ 8\relax
+ \advance \count_mod_viii -\count@
+ }
+\def\print_tab{%
+ \loop \space \mod_viii\char_count
+ \ifnum \count_mod_viii>\z@
+ \advance \char_count\@ne
+ \repeat
+ }
+\def\print_rest_of_line#1{%
+ \def\@line{#1}%
+ \ifx \@line\empty \char_count\z@
+ \def\next##1\end_line{\relax}%
+ \else \let\next\print_char
+ \fi
+ \next#1\end_line
+ }
+{\catcode`\/=\escape \catcode`\\=\other % / is temporary escape char
+ /gdef/beginprog{%
+ /gdef/end_verbatim_line{\endprog}%
+ /begin_verbatim
+ }
+ /gdef/beginverbatim{%
+ /gdef/end_verbatim_line{\endverbatim}%
+ /begin_verbatim
+ }
+} % here \endgroup can't be used
+\newcount\sectno \sectno=\@ne
+
+\newtoks\title \title{}
+\def\toc_file_name{\jobname.toc } % <--- Space!!
+\newwrite\toc_file
+
+\immediate\openout\toc_file=\toc_file_name
+\immediate\write\toc_file{\relax}
+
+\let\tocline=\relax
+\headline{%
+ \tenrm
+ \S\topmark \qquad \the\title
+ \hfil
+ \main_title \qquad \tenrm \folio
+ }
+\footline{\hfil}
+\vbox to \vsize{}
+
+\output={%
+ \setbox\z@ \vbox{\unvbox\@cclv}% % throw away the first page
+ \global\output{\plainoutput}% % restore Plain output routine
+ }
+\def\chap#1.{%
+ \endgraf
+ \mark{\number\sectno}% % gather information for headline
+ \vfill\supereject
+ \begingroup
+ \def\protect##1{\string ##1 }% % <--- Space!!
+ \edef\write_toc_sectno{\write\toc_file{\tocline{\number\sectno}}}%
+ \write_toc_sectno
+ \write\toc_file{{#1}{\folio}}%
+ \endgroup
+ \gdef\main_title{#1}% % more information for headline
+ \noindent {\bf \number\sectno.\quad #1.}%
+ \global\advance \sectno\@ne
+ \endgraf
+ \medskip \nobreak
+ \everypar{% % remove next parindent
+ \setbox0\lastbox
+ \global\everypar{}%
+ }%
+ }
+\def\sect{%
+ \endgraf
+ \mark{\number\sectno}% % gather information for headline
+ \vskip 2pc plus 1pc minus 6dd \goodbreak
+ \noindent {\bf \number\sectno.}\quad \ignorespaces
+ \global\advance \sectno\@ne
+ }
+\def\byebye{\par\vfil\supereject\end} % original definition of \bye
+\def\bye{%
+ \endgraf
+ \vfill \supereject
+ \immediate\closeout\toc_file
+ \message{Table of contents:}%
+ \leftskip\z@skip \rightskip\z@skip
+ \parskip\z@skip \parindent\z@ \parfillskip\z@skip
+ \normalbaselines
+ \headline{\hfil}%
+ \footline{\hfil \folio \hfil}%
+ \def\HeaderToc{\rightline{Section\hbox to\thr@@ em{\hss Page}}}%
+ \def\tocline##1##2##3{%
+ \line{%
+ \ignorespaces ##2%
+ \leaders\hbox to .5em{.\hfil}\hfil
+ \ ##1%
+ \hbox to \thr@@ em{\hss ##3}%
+ }%
+ }
+ \pageno\m@ne % table of contents gets roman page numbers
+ \topofcontents % may redefine \HeaderToc and \tocline!
+ \HeaderToc
+ \catcode`\@\letter % @ and _ are letters (for reading private macros)
+ \catcode`\_\letter
+ \input \toc_file_name
+ \catcode`\@\atcode % @ and _ are no more letters
+ \catcode`\_\uscode
+ \botofcontents
+ \byebye % print the contents page(s) and terminate
+ }
+
+\font\titlefont=cmr7 scaled\magstep4 % title on the contents page
+\font\ttitlefont=cmtt10 scaled\magstep2 % typewriter type in title
+\def\topofcontents{
+ \null \vfill
+ \centerline{\let\tt\ttitlefont \titlefont \the\title}
+ \vskip 1cm
+ }
+\def\botofcontents{
+ \vfill\vfill
+ }
+\catcode`\@=\atcode
+\catcode`\_=\uscode
+
+\endinput
diff --git a/support/makeprog/src/progltx.doc b/support/makeprog/src/progltx.doc
new file mode 100644
index 0000000000..fdc6047699
--- /dev/null
+++ b/support/makeprog/src/progltx.doc
@@ -0,0 +1,739 @@
+% This is PROGLTX.DOC as of 25 May 90
+%---------------------------------------------------------
+% (c) 1989,1990 by J.Schrod. copy conditions see below
+
+%
+% Macro package for the documentation of programs
+% LaTeX style option
+% MAKEPROG is needed
+%
+
+%
+% DATE PERSON REMARK
+% 89-11-18 js repaired the handling of `|' (verbatim and \index).
+% 89-10-05 js first version (for TeX89)
+%
+
+% author's current address:
+%
+% Detig$\,\cdot\,$Schrod \TeX{}sys
+% Joachim Schrod
+% Kranichweg 1
+%
+% D-6074 R\"odermark-Urberach
+% FR Germany
+%
+% Tel. (+6074) 1617
+% Bitnet: XITIJSCH@DDATHD21
+
+
+
+% documented with itself...
+\documentstyle[progltx]{article}
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% local macros
+%
+
+\let\mc=\small % for names like GNU
+
+\def\WEB{{\tt WEB\/}}
+\def\GNU{{\mc GNU}}
+
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+\begin{document}
+
+
+\title{
+ Documenting programs in a \WEB{} style\\
+ The {\tt progltx\/} style option
+ }
+\author{\sc Joachim Schrod}
+
+\maketitle
+
+
+\chap Introduction.
+
+\WEB{} systems allow the documentation of programs by supporting the
+separation in program fragments which can be collected and rearranged
+afterwards. This allows {\it top-down\/} programming as well as the
+{\it bottom-up\/} design of programs. Each program fragment can be
+documented, usually with \TeX{}\@. A disadvantadge is that \WEB{}
+actually exists only for a few programming languages (Pascal, C,
+Modula-2). Besides, building up \WEB{} systems for ``exotic''
+programming languages like \TeX{} is very difficult.
+
+This macro package was built to allow good documentation for programs
+in languages for which \WEB{} doesn't exist. It separates a program
+text in sections that can be documented. All sections, collected
+sequentially, will result in the complete program. In every section
+begin and end of the program part are marked with |\beginprog| and
+|\endprog|, this program part will be formatted as it is input
+(``verbatim'').
+
+Originally these macros were written for the usage with Plain \TeX{}
+resp.\ on top of the \WEB{} macro package |webmac.tex|. But often the
+requirement has been told to me that a \LaTeX{} version would be
+useful, too---well, here it is. But even with \LaTeX{} I have decided
+that still |\beginprog| and |\endprog| must be used for the markup of
+the program parts, not |\begin{prog}| or |\end{prog}| which would be
+more ``\LaTeX{}-like.'' The reason behind this is that I didn't want
+to maintain two versions of the {\mc MAKEPROG\/} processor---but {\mc
+MAKEPROG\/} wants to see the non-\LaTeX{}-like macros. But everybody
+is encouraged to change it by themselves (it is {\it very\/} easy).
+
+The user of these macros may use the usual sectioning macros of
+\LaTeX{} for structuring his documentation. Additionally we provide a
+|progdoc|-compatible (i.e.\ \WEB{}-like) markup with the two macros
+|\chap| and |\sect|.
+
+In the documentation part of a section text pieces, e.g.\ names of
+variables, can be inserted verbatim to demonstrate the connection to
+the program text. These parts are included in vertical bars
+(`{\tt\vbar}') This makes this style option extremely useful if your
+identifiers (or your file names) include characters which would be
+special characters for \TeX{} otherwise. (One example of these
+program languages is \TeX{} itself, but just enclose the macro names
+in vertical bars and {\tt \vbar|\relax|\vbar}.)
+
+The macros |\makevertother| and |\makevertactive| are available to
+activate and deactivate the special behaviour of the vertical bar but
+these macros should be needed seldom because the usual cases as the
+usage within |verbatim| and |tabular| environments or |\index| macros
+etc.\ are handled.
+
+If a vertical bar must be used in the original fashion you can use two
+command sequences: |\origvert| holds the meaning of the vertical bar
+at the time this macro file was read in and |\vbar| is the character
+with the {\mc ASCII\/} code of the vertical bar (i.e.~|"EC|) in the
+current font.
+
+The new notion of |\verb| must not be used within parameters of
+macros, e.g.\ in the argument of |\section| etc.---it will result in
+an error message by \TeX{}\@. Furthermore within the preamble of a
+|tabular|, an |array| environment, or the |\multicolumn| command the
+vertical bar has the same meaning as before. (That means within
+|@{|\ldots|}| it is an ordinary character and otherwise it specifies a
+vertical rule between the columns.
+
+This macro package does not offer the automatic creation of an index
+because it is not known which syntactical tokens the language has that
+should be mentioned in an index. But of course all \LaTeX{} stuff like
+|\index|, |\tableofcontents|, etc.\ may be used.
+
+
+\sect This program is free software; you can redistribute it and/or
+modify it under the terms of the \GNU{} General Public License as
+published by the Free Software Foundation; either version~1, or (at your
+option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+{\bf without any warranty\/}; without even the implied warranty of
+{\bf merchantability\/} or {\bf fitness for a particular purpose}. See
+the \GNU{} General Public License for more details.
+
+You should have received a copy of the \GNU{} General Public License
+along with this program; if not, write to the Free Software Foundation,
+Inc., 675~Mass Ave, Cambridge, MA~02139, USA.
+
+
+\sect We have to realize three parts: (1)~the formatting of rather
+small verbatim texts in a line, (2)~the formatting of larger parts of
+program and (3)~the document structuring elements for the separation
+of the sections.
+
+\begin{sloppypar}
+Before we start we declare some shorthands for category codes. By
+declaring the underscore~`(|_|)' as a letter we can use it in our
+macros names. (I agree with D.~Knuth that
+|\identifier_several_words_long| is more readable than
+|\IdentifierSeveralWordsLong| and in every case better than
+|\p@@@s|.) But as we have to restore the category codes at the end
+of this macro file we store its former value in the control
+sequence |\uscode|. This method is better than the usage of a
+group because not all macros have to be defined global this way.
+\end{sloppypar}
+
+\beginprog
+\chardef\escape=0
+\chardef\open=1
+\chardef\close=2
+\chardef\letter=11
+\chardef\other=12
+%\chardef\active=13 % is defined in Plain already
+
+\chardef\uscode=\catcode`\_
+
+\catcode`\_=\letter
+\endprog
+
+
+
+
+\chap Local Verbatim Formatting.
+
+The main point of every verbatim formatting is the switching of the
+character codes of all characters that have a special \TeX{} meaning.
+This can be done with the control sequence |\dospecials| that applies
+the control sequence |\do| to all special characters. Additionally,
+every line is regarded as a paragraph without indentation. Between
+two paragraphs, i.e.\ between two lines, no extra space is set.
+Finally all blanks and tabular characters shall be obeyed and the
+inter word space after sentence terminators shall not be enlarged.
+The activation of the tabular characters with |\obeytabs| is
+equivalent to |\obeyspaces| in {\tt plain.tex}.
+
+\begin{sl}
+As a matter of fact, I would like to use the character set with the
+extended {\mc ASCII} (like in\/ \WEB{}) for setting the verbatim texts
+in monospace. But then I must code many\/ |\@getfont|'s\,\dots
+\end{sl}
+
+\beginprog
+%\font\tentex=cmtex10 % typewriter extended ASCII 10pt
+%\let\ttex=\tentex % only with base size 10pt
+\def\ttex{\tt} % as a substitute
+
+\def\setup_verbatim{%
+ \def\do##1{\catcode`##1\other}\dospecials
+ \parskip\z@skip \parindent\z@
+ \catcode`\`\active \@noligs
+ \obeylines \@vobeyspaces \obeytabs \frenchspacing
+ \ttex
+ }
+
+\let\tab=\space
+\begingroup
+ \catcode`\^^I=\active% % Attention: no tabs!
+ \gdef\obeytabs{\catcode`\^^I=\active\def^^I{\tab}}
+ \global\let^^I=\tab% % if an active tab appears in a \write
+\endgroup
+\endprog
+
+
+\sect After having saved the old meaning of `{\tt\vbar}' in
+|\origvert| and after declaring |\vbar| as a synonym for the character
+that has the code of a vertical bar in the actual font, the vertical
+bar can be made active. Then we call |\setup_verbatim|. But the
+newline characters shall not be processed, they shall be regarded like
+blank space. This can be reached by defining |\par| as |\space|.
+
+The next vertical bar in the input closes the group which becomes an
+(unbreakable) |\hbox| then. The old meanings of the special
+characters and of the vertical bar are restored and \TeX{} is in
+normal (horizontal) mode again.
+
+\beginprog
+\let\origvert=|
+\chardef\vbar=`\|
+
+\def\makebaractive{\catcode`\|\active}
+\def\makebarother{\catcode`\|\other}
+\makebaractive
+
+\def|{%
+ \leavevmode
+ \hbox\bgroup
+ \let\par\space \setup_verbatim
+ \let|\egroup
+ }
+\endprog
+
+
+\sect A problem with this definition of the vertical bar is that
+the bar is not a normal character any more but there exists situations
+where the \LaTeX{} macros assumes this:
+%
+\begin{itemize}
+
+\item In a |verbatim| environment a vertical bar must be typeset if it
+occurs in the input.
+
+\item In a |tabular| or an |array| environment a vertical bar is used
+to denote rules between columns in the table. These environments must
+be started with a parameter which is a ``preamble,'' the same preamble
+construction is used to specify the format of multi-column entries.
+
+\item In an output of an index entry the vertical bar must not result
+in an error message. Usually index entries are typeset in a seperate
+\TeX{} run where |idverb| is not used as a style option and the
+vertical bar is therefore useful. This is no problem in section
+headings or captions etc. Because they take their argument as a
+parameter in every case the vertical bar can never be used there. But
+|\origvert| resp.\ |\vbar| may be used there.
+
+\end{itemize}
+%
+In the next sections we handle each of these problems.
+
+
+\sect Before we start a |verbatim| environment we just redefine the
+vertical bar as an ordinary character. Because this is within the
+environment grouping the end of the environment will reestablish the
+special meaning.
+
+\beginprog
+\let\@@verbatim=\@verbatim
+\def\@verbatim{%
+ \makebarother
+ \@@verbatim
+ }
+\endprog
+
+
+\sect Special care is needed in the |tabular| and the |array|
+environment. Both environments are begun by one macro (|\@tabarray|),
+we redefine it so that the bar can be used in the preamble
+specification. The same problem occurs in |\multicolumn|, it is
+solved the same way. After the preamble construction (with
+|\@mkpream|) the special meaning of the bar can be switched on
+again---this allows the usage of the new meaning in the body of a
+table.
+
+Of course this mean that the ``verbatim identifier'' facility can
+not be used within a preamble of a table. Furthermore it can not
+be used within the |\multicolumn| statement, neither in the
+preamble part (the second parameter) nor within the text part (the
+third parameter).
+
+\beginprog
+\let\@@tabarray=\@tabarray
+\def\@tabarray{%
+ \makebarother
+ \@@tabarray
+ }
+
+\def\multicolumn#1{%
+ \multispan{#1}%
+ \begingroup
+ \makebarother
+ \restof_multicolumn
+ }
+\def\restof_multicolumn#1#2{%
+ \@mkpream{#1}%
+ \def\@sharp{#2}%
+ \let\protect\relax
+ \let\@startpbox\@@startpbox \let\@endpbox\@@endpbox
+ \@arstrut \@preamble
+ \endgroup
+ \ignorespaces
+ }
+
+\let\@@mkpream=\@mkpream
+\def\@mkpream#1{%
+ \@@mkpream{#1}%
+ \makebaractive
+ }
+\endprog
+
+
+\sect Before an index entry is scanned almost all special characters
+are transformed into ordinary characters. The only exceptions are the
+opening and the closing brace because they are needed to delimit the
+argument. This transformation is done with |\@sanitize|, this macro
+must be called within a group. We just append the transformation of
+the vertical bar.
+
+\beginprog
+\begingroup
+ \def\@makeother{\noexpand\@makeother\noexpand}
+ \xdef\@sanitize{\@sanitize\@makeother\|}
+\endgroup
+\endprog
+
+
+
+
+\chap Fragments in Verbatim.
+
+We need macros to format the program fragments without any
+linebreaking. Such a text area shall start with the macro
+|\beginprog| and end with |\endprog|, i.e.\ as a kind of a
+|prog|-environment. The macro |\endprog| must stand at the very
+beginning of a line and must be followed by white space (blank, tab or
+newline character). After |\beginprog| as well as after
+|\endprog| the rest of the line is ignored.
+
+Two demands must be regarded: There should be no length restrictions
+for the processed text, and the tabular characters should be expanded
+so that this macro works on PC's and on VAXes etc., too.
+
+
+\sect The implementation method is quite simple: We read the next
+line, test, wether the end is reached (by comparing with the end line)
+and otherwise set the line actually read. Every character is
+inspected and tabular characters are expanded.
+
+The verbatim text is started with |\begin_verbatim| which will be
+either called by |\beginprog| or by |\beginverbatim|. These macros
+will also define the contents of the end line.
+
+Whether a line is set or whether the end of the processed area is
+reached is indicated by the switch |\if@print|. At the beginning of
+the |\begin_verbatim| macro most settings are done with
+|\setup_verbatim| (the vertical bar must be handled separately)
+and the rest of the line is ignored. As everything is done within
+a group, the end of the verbatim text can be processed by simply
+closing this group.
+
+For the user it looks as if |\endprog| or |\endverbatim|
+terminates the processing, but it just serves for the
+identification of the end, the true processing is done with the
+internal macro |\end_verbatim|.
+
+\beginprog
+\newif\if@print
+
+\def\begin_verbatim{%
+ \endgraf
+ \bigbreak
+ \begingroup
+ \setup_verbatim \makebarother
+ \@printtrue
+ \ignore_rest_line
+ }
+\let\end_verbatim=\endgroup % internal command !
+\endprog
+
+
+\sect {\sloppy
+ The first line is ignored, all the other lines are identified with
+|\set_next_line| and processed with |\do_set|. This separation in
+identification and processing allows that the line end character is
+active in the definition only for a short time.
+ \par}
+
+When a line is to be formatted, we first check with |\check_print|
+wether it contains the end line, otherwise it is printed with
+|\print_char|. The printing must be done for every character
+individually because we want to check for tabular characters; the
+exact algorithm is described below. Here we just have to note that
+|\print_char| is used with two parameters of which the second one is
+finished with the token |\end_line|. The first parameter is the first
+character of the line, the second parameter is the rest of the line.
+If the line is empty, the argument of |\do_set| is empty, too; so the
+activation of |\print_char| must be finished with two |\end_line|.
+Then the first |\end_line| is the first argument for |\print_char| and
+the second argument is empty. But if the line did contain something,
+the second |\end_line| is evaluated, for this case it is defined as
+|\relax|.
+
+At last we call |\set_next_line| again to format the next line. If
+the end is reached, i.e.\ if the sample line was found,
+|\set_next_line| will be redefined as |\relax|. This can be done
+because the original meaning is restored while closing the group
+with |\end_verbatim|.
+
+\beginprog
+\begingroup
+ \obeylines% % ^^M is active! ==> every line must end with %
+ \gdef\ignore_rest_line#1^^M{\set_next_line}%
+ \gdef\set_next_line#1^^M{\do_set{#1}}%
+\endgroup
+
+\def\do_set#1{%
+ \endgraf
+ \check_print{#1}%
+ \if@print \indent \print_char#1\end_line\end_line
+ \else \let\set_next_line\end_verbatim
+ \fi
+ \set_next_line
+ }
+\let\end_line=\relax
+\endprog
+
+
+\sect {\sloppy
+ Before we look at the problem of formatting a line, we declare
+|\check_print| that checks the end of the verbatim mode. We have to
+do two things: we must split everything in front of the first blank
+or tabular character and compare for identity with |\endprog|. The
+splitting is easy because the line which is our first argument
+contains blanks and tabulators as active characters. First we call
+|\cut_at_tab| that demands a tabular character as separator for its
+two pramenters so that everything in the line in front of the first
+tabulator is part of the first parameter. If there is no tabular
+character in the line, we append one so that the second parameter is
+empty. The same trick is used to separate the part in front of the
+first blank character from the resulting first part.
+ \par}
+
+The check is done with |\do_check|. We use a separate macro here so
+that we can indent it (in the following definition blanks are active!)
+
+\beginprog
+\begingroup
+\obeyspaces\obeytabs
+\gdef\check_print#1{\cut_at_tab#1^^I\end_line}
+\gdef\cut_at_tab#1^^I#2\end_line{\check_first_part#1 \end_line}% blank !
+\gdef\check_first_part#1 #2\end_line{\do_check{#1}}
+\endgroup
+\endprog
+
+
+\sect
+\begin{sloppypar}
+|\do_check| compares the line with a sample line that is
+available in |\end_verbatim_line|. This macro will be defined later.
+\end{sloppypar}
+
+\beginprog
+\def\do_check#1{%
+ \def\@line{#1}%
+ \ifx \@line\end_verbatim_line \@printfalse
+ \fi
+ }
+\endprog
+
+
+\sect Now we can set a line: we start with the first character,
+followed by the rest of the line. Each character is counted in
+|\char_count|. At the beginning of a line |\char_count| is~0, this
+is reset at the end of the line.
+
+\beginprog
+\newcount\char_count \char_count\z@
+
+\def\print_char#1#2\end_line{%
+ \print_first_char{#1}%
+ \print_rest_of_line{#2}%
+ }
+\endprog
+
+
+\sect For each character that is set |\char_count| is incremented.
+If a character is a tabulator, we set with |\print_tab| the fitting
+amount of blank characters, otherwise the character itself. We must
+compare the character that is stored in |\@char| with a macro of which
+the ``first-level'' expansion is an active tabulator. For this case
+we declare |\@tab|.
+
+\beginprog
+{\obeytabs\gdef\@tab{^^I}}
+
+\def\print_first_char#1{%
+ \def\@char{#1}%
+ \advance \char_count\@ne
+ \ifx \@char\@tab \print_tab
+ \else \@char
+ \fi
+ }
+\endprog
+
+
+\sect If we want to fill the line with blank spaces up to the next
+column with a number that can be divided by~8, we must be able to
+compute the column number modulo~8, but \TeX{} has no modulo operator.
+So we define the macro |\mod_viii| that computes its argument modulo~8
+and returns the result in the counter |\count_mod_viii|. For the
+computation we need the temporary counter |\count@|.
+
+\beginprog
+\newcount\count_mod_viii
+\def\mod_viii#1{%
+ \count@ #1\relax \count_mod_viii\count@
+ \divide \count@ 8\relax
+ \multiply \count@ 8\relax
+ \advance \count_mod_viii -\count@
+ }
+\endprog
+
+
+\sect Now we can declare |\print_tab|. We must remember that
+|\char_count| was incremented already, if we set only one blank
+character the counter keeps untouched.
+
+\beginprog
+\def\print_tab{%
+ \loop \space \mod_viii\char_count
+ \ifnum \count_mod_viii>\z@
+ \advance \char_count\@ne
+ \repeat
+ }
+\endprog
+
+
+\sect If the rest of the line is empty, we are ready. |\char_count|
+is reset to~0 for the next line.
+
+Inside the |\else| part of |\ifx| |\print_char| should not be used
+directly because this costs too much storage of \TeX{}\@. Instead we
+set a control sequence |\next| that is processed afterwards, depending
+on the result of the comparison. (This tail recursion will be
+discovered by \TeX{} and handled appropriately.) If there is still
+something to set, we use |\print_char| again, otherwise a
+syntactically similar macro that expands to |\relax|.
+
+\beginprog
+\def\print_rest_of_line#1{%
+ \def\@line{#1}%
+ \ifx \@line\empty \char_count\z@
+ \def\next##1\end_line{\relax}%
+ \else \let\next\print_char
+ \fi
+ \next#1\end_line
+ }
+\endprog
+
+
+\sect {\sloppy
+Now we are ready to define the two ``user accessible'' macros
+|\beginprog| and |\beginverbatim|. They must define the prototyp end
+line |\end_verbatim_line| which will be compared against every line
+in the verbatim text. During the definition of
+|\end_verbatim_line| it must be cared for that the escape character~`|\|'
+is a printable character: A comparison with |\ifx| demands identical
+category codes. As a temporary escape character we use the slash.
+\par}
+
+\beginprog
+{\catcode`\/=\escape % / is temporary escape char
+ \catcode`\\=\other
+ /gdef/beginprog{%
+ /gdef/end_verbatim_line{\endprog}%
+ /begin_verbatim
+ }
+ /gdef/beginverbatim{%
+ /gdef/end_verbatim_line{\endverbatim}%
+ /begin_verbatim
+ }
+} % here \endgroup can't be used
+\endprog
+
+
+
+
+\chap Document Structuring.
+
+In addition to the normal \LaTeX{} structuring markups we will
+provide a markup for a layout of the document that is like in
+\WEB{}. This can be done easily. All sections are numbered, the
+number of the next section is stored in the counter |section|. We
+distinguish between main sections which start a group of sections
+and between normal sections within a group.
+
+The main sections are started with the macro |\chap|. It has one
+parameter, the title of the section group. This parameter must be
+terminated by a dot. We start a new page, typeset the title in
+bold face and separate it from the section text with a |\medskip|.
+This text, the documentation part of the section, is formatted
+without paragraph indentation.
+
+If the \WEB{}-like macros are used every section number should be
+output with a following dot. We want to establish this when we use the
+|\chap| or the |\sect| macro the first time. Furthermore the new page
+at the begin of a main section should not be started at the first
+|\chap| because a title may precede it (and the title should not
+be on a seperate page unless explicitely requested). Instead a
+skip of (approximately) 2~pica should be set. To achieve
+both goals a macro |\chap_intro| is defined that defines |\thesection|
+appropriately, skips the 2~pica, and redefines itself to
+|\newpage|---we then just have to call |\chap_intro| at the beginning
+of |\chap|. The same applies to |\sect_intro|.
+
+\beginprog
+\newskip\pre_sect_skip \pre_sect_skip=2pc plus 1pc minus 6pt
+
+\def\chap_intro{%
+ \gdef\thesection{\arabic{section}.}%
+ \gdef\chap_intro{\newpage}%
+ \addvspace{\pre_sect_skip}%
+ }
+
+\def\sect_intro{%
+ \gdef\thesection{\arabic{section}.}%
+ \global\let\sect_intro\relax
+ }
+\endprog
+
+
+\sect Now we will have a look at the {\it wonderful\/} internal
+interface of \LaTeX{}\@. With ``wonderful'' I mean that I'm always
+full of wonder why it was designed in this way. E.g., if anybody
+can explain to me why the coding of the non-indentation of the first
+line in the following paragraph was combined with the coding of
+the skip which will come in front of the section---I will be thankful
+for the rest of my life. Such different things should be kept
+different, i.e., the suppression of the indentation should not be
+hidden in the sign of a skip! The same comment applies to the combined
+coding of the skip below the section heading resp.\ to the right
+of a run-in heading.
+
+\begin{quote} \it
+I want the following layout: no indentation in the following
+paragraph\/ {\rm but no} space in front of the section heading.
+How do I code a value of\/ $\sl -0 pt$?
+\end{quote}
+%
+Well, a work-around is to use a value of $\rm -1\,sp$ because the
+reader will not see this distance---but in my opinions this is no
+good programming style. In this special case I have luck, too:
+the skip is not set anyway, either it is discarded by the preceding
+|\newpage| or it is not added by |\addvspace| because of the preceding
+|\pre_sect_skip|.
+
+\beginprog
+\def\chap#1.{%
+ \chap_intro
+ \@startsection{section}{1}%
+ {\z@}%
+ {\m@ne sp}%
+ {\medskipamount}%
+ {\normalsize\bf}%
+ {#1.}%
+ }
+\endprog
+
+
+\sect Normal sections are started with |\sect|. This macro has no
+parameter. Between two paragraphs we skip |\pre_sect_skip|.
+Between the section number and the text one quad of space is set.
+We have to take care for empty documentation parts where the
+program part (i.e.\ |\beginprog|) will follow immediately. Then
+the program part should begin on a new line and not behind the
+section number. So we provide |\null| as an empty documentation
+part in every case.
+
+Now again the design of |\@startsection| comes in hand: \LaTeX{}
+always leaves a quad after the section number (by the way,
+this is not mentioned in the documentation---you have to look
+in the macros to figure this out). Because our section header
+consists only of the number we have to code a value of $\rm
+-0\,pt$\,\dots
+
+\begin{quote}
+Again: {\it non-orthogonal design is bad design}.
+\end{quote}
+
+\beginprog
+\def\sect{%
+ \sect_intro
+ \@startsection{section}{1}%
+ {\z@}%
+ {\pre_sect_skip}%
+ {\m@ne sp}%
+ {\normalsize\bf}%
+ {\null}%
+ }
+\endprog
+
+
+\sect We are finished and just have to restore the category code.
+
+\beginprog
+\catcode`\_=\uscode
+
+\endinput
+\endprog
+
+
+
+
+
+\end{document}
diff --git a/support/makeprog/src/progltx.sty b/support/makeprog/src/progltx.sty
new file mode 100644
index 0000000000..83a3181c20
--- /dev/null
+++ b/support/makeprog/src/progltx.sty
@@ -0,0 +1,194 @@
+\chardef\escape=0
+\chardef\open=1
+\chardef\close=2
+\chardef\letter=11
+\chardef\other=12
+%\chardef\active=13 % is defined in Plain already
+
+\chardef\uscode=\catcode`\_
+
+\catcode`\_=\letter
+%\font\tentex=cmtex10 % typewriter extended ASCII 10pt
+%\let\ttex=\tentex % only with base size 10pt
+\def\ttex{\tt} % as a substitute
+
+\def\setup_verbatim{%
+ \def\do##1{\catcode`##1\other}\dospecials
+ \parskip\z@skip \parindent\z@
+ \catcode`\`\active \@noligs
+ \obeylines \@vobeyspaces \obeytabs \frenchspacing
+ \ttex
+ }
+
+\let\tab=\space
+\begingroup
+ \catcode`\^^I=\active% % Attention: no tabs!
+ \gdef\obeytabs{\catcode`\^^I=\active\def^^I{\tab}}
+ \global\let^^I=\tab% % if an active tab appears in a \write
+\endgroup
+\let\origvert=|
+\chardef\vbar=`\|
+
+\def\makebaractive{\catcode`\|\active}
+\def\makebarother{\catcode`\|\other}
+\makebaractive
+
+\def|{%
+ \leavevmode
+ \hbox\bgroup
+ \let\par\space \setup_verbatim
+ \let|\egroup
+ }
+\let\@@verbatim=\@verbatim
+\def\@verbatim{%
+ \makebarother
+ \@@verbatim
+ }
+\let\@@tabarray=\@tabarray
+\def\@tabarray{%
+ \makebarother
+ \@@tabarray
+ }
+
+\def\multicolumn#1{%
+ \multispan{#1}%
+ \begingroup
+ \makebarother
+ \restof_multicolumn
+ }
+\def\restof_multicolumn#1#2{%
+ \@mkpream{#1}%
+ \def\@sharp{#2}%
+ \let\protect\relax
+ \let\@startpbox\@@startpbox \let\@endpbox\@@endpbox
+ \@arstrut \@preamble
+ \endgroup
+ \ignorespaces
+ }
+
+\let\@@mkpream=\@mkpream
+\def\@mkpream#1{%
+ \@@mkpream{#1}%
+ \makebaractive
+ }
+\begingroup
+ \def\@makeother{\noexpand\@makeother\noexpand}
+ \xdef\@sanitize{\@sanitize\@makeother\|}
+\endgroup
+\newif\if@print
+
+\def\begin_verbatim{%
+ \endgraf
+ \bigbreak
+ \begingroup
+ \setup_verbatim \makebarother
+ \@printtrue
+ \ignore_rest_line
+ }
+\let\end_verbatim=\endgroup % internal command !
+\begingroup
+ \obeylines% % ^^M is active! ==> every line must end with %
+ \gdef\ignore_rest_line#1^^M{\set_next_line}%
+ \gdef\set_next_line#1^^M{\do_set{#1}}%
+\endgroup
+
+\def\do_set#1{%
+ \endgraf
+ \check_print{#1}%
+ \if@print \indent \print_char#1\end_line\end_line
+ \else \let\set_next_line\end_verbatim
+ \fi
+ \set_next_line
+ }
+\let\end_line=\relax
+\begingroup
+\obeyspaces\obeytabs
+\gdef\check_print#1{\cut_at_tab#1^^I\end_line}
+\gdef\cut_at_tab#1^^I#2\end_line{\check_first_part#1 \end_line}% blank !
+\gdef\check_first_part#1 #2\end_line{\do_check{#1}}
+\endgroup
+\def\do_check#1{%
+ \def\@line{#1}%
+ \ifx \@line\end_verbatim_line \@printfalse
+ \fi
+ }
+\newcount\char_count \char_count\z@
+
+\def\print_char#1#2\end_line{%
+ \print_first_char{#1}%
+ \print_rest_of_line{#2}%
+ }
+{\obeytabs\gdef\@tab{^^I}}
+
+\def\print_first_char#1{%
+ \def\@char{#1}%
+ \advance \char_count\@ne
+ \ifx \@char\@tab \print_tab
+ \else \@char
+ \fi
+ }
+\newcount\count_mod_viii
+\def\mod_viii#1{%
+ \count@ #1\relax \count_mod_viii\count@
+ \divide \count@ 8\relax
+ \multiply \count@ 8\relax
+ \advance \count_mod_viii -\count@
+ }
+\def\print_tab{%
+ \loop \space \mod_viii\char_count
+ \ifnum \count_mod_viii>\z@
+ \advance \char_count\@ne
+ \repeat
+ }
+\def\print_rest_of_line#1{%
+ \def\@line{#1}%
+ \ifx \@line\empty \char_count\z@
+ \def\next##1\end_line{\relax}%
+ \else \let\next\print_char
+ \fi
+ \next#1\end_line
+ }
+{\catcode`\/=\escape % / is temporary escape char
+ \catcode`\\=\other
+ /gdef/beginprog{%
+ /gdef/end_verbatim_line{\endprog}%
+ /begin_verbatim
+ }
+ /gdef/beginverbatim{%
+ /gdef/end_verbatim_line{\endverbatim}%
+ /begin_verbatim
+ }
+} % here \endgroup can't be used
+\newskip\pre_sect_skip \pre_sect_skip=2pc plus 1pc minus 6pt
+
+\def\chap_intro{%
+ \gdef\thesection{\arabic{section}.}%
+ \gdef\chap_intro{\newpage}%
+ \addvspace{\pre_sect_skip}%
+ }
+
+\def\sect_intro{%
+ \gdef\thesection{\arabic{section}.}%
+ \global\let\sect_intro\relax
+ }
+\def\chap#1.{%
+ \chap_intro
+ \@startsection{section}{1}%
+ {\z@}%
+ {\m@ne sp}%
+ {\medskipamount}%
+ {\normalsize\bf}%
+ {#1.}%
+ }
+\def\sect{%
+ \sect_intro
+ \@startsection{section}{1}%
+ {\z@}%
+ {\pre_sect_skip}%
+ {\m@ne sp}%
+ {\normalsize\bf}%
+ {\null}%
+ }
+\catcode`\_=\uscode
+
+\endinput
diff --git a/support/makeprog/src/tex2doc.l b/support/makeprog/src/tex2doc.l
new file mode 100644
index 0000000000..7f0fa9cc0a
--- /dev/null
+++ b/support/makeprog/src/tex2doc.l
@@ -0,0 +1,12 @@
+%{
+/* tex2doc.l 20 Jan 90
+ *-------------------------------------------------------
+ * (c) 1990 by J.Schrod.
+ * Copyright conditions: GNU General Public License
+ */
+%}
+
+%%
+
+^%%%\ ? ;
+^%%%%.*\n ;
diff --git a/support/makeprog/webtoc/convert b/support/makeprog/webtoc/convert
new file mode 100644
index 0000000000..23ffa7ed08
--- /dev/null
+++ b/support/makeprog/webtoc/convert
@@ -0,0 +1,6 @@
+:
+# Convert webware programs to C
+cat web2c.defines $1 \
+ | ../../web2c/web2c -hweb2c.h -c`basename $1 .p` \
+ | ../../web2c/fixwrites > $2
+rm -f stack.stack
diff --git a/support/makeprog/webtoc/makefile b/support/makeprog/webtoc/makefile
new file mode 100644
index 0000000000..012e312506
--- /dev/null
+++ b/support/makeprog/webtoc/makefile
@@ -0,0 +1,49 @@
+#
+# Makefile for TeX82 distribution, subdirectory `webware/makeprog'
+#
+# This file makes MAKEPROG
+#
+# It assumes that a working tangle exists.
+
+
+BINDIR=/usr/local/bin
+SITEDIR=../../common
+
+CFLAGS=-O -Dlink=link_array -I../../common
+LDFLAGS=
+
+.SUFFIXES:
+.SUFFIXES: .o .c .p .ch
+
+.p.c:
+ ./convert $*.p $*.c
+
+.ch.p:
+ tangle $*.web $*.ch
+
+.c.o:
+ $(CC) $(CFLAGS) -c $*.c
+
+default: makeprog
+
+all: makeprog
+
+install: all
+ mv ../bin/makeprog $(BINDIR)
+
+
+# MAKEPROG
+makeprog: makeprog.o makepext.o
+ $(CC) $(LDFLAGS) $(CFLAGS) -o ../../bin/makeprog makeprog.o \
+ makepext.o
+makeprog.o: makeprog.c web2c.h
+makeprog.p: makeprog.web makeprog.ch
+makepext.o: makepext.c $(SITEDIR)/site.h
+
+
+clean:
+ rm -f *.pool
+ rm -f *.o
+
+very_clean: clean
+ rm -f makeprog makeprog.p makeprog.c
diff --git a/support/makeprog/webtoc/makepext.c b/support/makeprog/webtoc/makepext.c
new file mode 100644
index 0000000000..c1d55b2d9e
--- /dev/null
+++ b/support/makeprog/webtoc/makepext.c
@@ -0,0 +1,91 @@
+/*
+ * Hand-coded routines for C TeX.
+ * This module should contain any system-dependent code.
+ */
+
+#define CATCHINT /* Catch ^C's */
+
+#define EXTERN /* Actually instantiate globals here */
+
+#include <signal.h>
+#include <time.h>
+#include <stdio.h>
+#include "site.h"
+
+#define BUF_SIZE 100 /* should agree with tangle.web */
+
+extern char buffer[]; /* 0..BUF_SIZE. Input goes here */
+extern char outbuf[]; /* 0..OUT_BUF_SIZE. Output from here */
+extern char xord[], xchr[]; /* character translation arrays */
+extern int limit;
+
+#ifdef SYSV
+#define index strchr /* Sys V compatibility */
+extern int sprintf();
+#else
+extern char *sprintf();
+#endif
+
+/* C library stuff that we're going to use */
+extern char *strcpy(), *strcat(), *malloc(), *index(), *getenv();
+
+/* Local stuff */
+static int gargc;
+integer argc;
+static char **gargv;
+
+
+#define TRUE 1
+#define FALSE 0
+
+
+/*
+ * Get things going under Unix: set up for rescanning the command line,
+ * then call the main body.
+ */
+main(iargc, iargv)
+int iargc;
+char *iargv[];
+{
+ gargc=argc=iargc;
+ gargv=iargv;
+ main_body();
+}
+
+/* Return the nth argument into the string s (which is indexed starting at 1) */
+argv(n,s)
+integer n;
+char s[];
+{
+ (void) sprintf(s+1, "%s ", gargv[n]);
+}
+
+
+/* Same as in Pascal --- return TRUE if EOF or next char is newline */
+eoln(f)
+FILE *f;
+{
+ register int c;
+
+ if (feof(f)) return(TRUE);
+ c = getc(f);
+ if (c != EOF)
+ (void) ungetc(c, f);
+ return (c == '\n' || c == EOF);
+}
+
+/* Open a file; don't return if error */
+FILE *openf(name, mode)
+char *name, *mode;
+{
+ FILE *result;
+ char *index(), *cp;
+
+ cp = index(name, ' ');
+ if (cp) *cp = '\0';
+ result = fopen(name, mode);
+ if (result) return(result);
+ perror(name);
+ exit(1);
+ /*NOTREACHED*/
+}
diff --git a/support/makeprog/webtoc/makeprog.c b/support/makeprog/webtoc/makeprog.c
new file mode 100644
index 0000000000..d28cc52967
--- /dev/null
+++ b/support/makeprog/webtoc/makeprog.c
@@ -0,0 +1,675 @@
+#include "web2c.h"
+/* 9999 */
+#define bufsize 500
+typedef schar ASCIIcode ;
+typedef file_ptr /* of char */ textfile ;
+schar history ;
+ASCIIcode xord[128] ;
+char xchr[128] ;
+textfile docfile ;
+textfile changefile ;
+textfile progfile ;
+ASCIIcode buffer[bufsize + 1] ;
+integer line ;
+integer otherline ;
+integer templine ;
+integer limit ;
+boolean inputhasended ;
+boolean changing ;
+ASCIIcode changebuffer[bufsize + 1] ;
+integer changelimit ;
+schar state ;
+char docfilename[121], changefilename[121], progfilename[121] ;
+char progextension[121] ;
+
+#include "makeprog.h"
+error () {
+ {
+ if ( changing )
+ (void) Fputs( stdout , ". (change file " ) ;
+ else
+ (void) Fputs( stdout , ". (" ) ;
+ (void) fprintf( stdout , "%s%ld%c\n", "l." , (long)line , ')' ) ;
+ (void) putc( ' ' , stdout );
+ }
+ flush ( stdout ) ;
+}
+scanargs () {
+ integer docdotpos, dotpos, i, a, slashpos ;
+ char c ;
+ char fname[121] ;
+ boolean founddoc, foundchange ;
+ progextension [ 1 ] = 'p' ;
+ progextension [ 2 ] = 'r' ;
+ progextension [ 3 ] = 'o' ;
+ progextension [ 4 ] = 'g' ;
+ progextension [ 5 ] = ' ' ;
+ founddoc = false ;
+ foundchange = false ;
+ {register integer for_end; a = 1 ; for_end = argc - 1 ; if ( a <= for_end)
+ do
+ {
+ argv ( a , fname ) ;
+ if ( fname [ 1 ] != '-' )
+ {
+ if ( ! founddoc )
+ {
+ slashpos = 0 ;
+ dotpos = -1 ;
+ i = 1 ;
+ while ( ( fname [ i ] != ' ' ) && ( i <= 115 ) ) {
+
+ docfilename [ i ] = fname [ i ] ;
+ if ( fname [ i ] == '.' )
+ dotpos = i ;
+ else if ( fname [ i ] == '/' )
+ {
+ slashpos = i ;
+ dotpos = -1 ;
+ }
+ i = i + 1 ;
+ }
+ if ( dotpos == -1 )
+ {
+ dotpos = i ;
+ docfilename [ dotpos ] = '.' ;
+ docfilename [ dotpos + 1 ] = 'd' ;
+ docfilename [ dotpos + 2 ] = 'o' ;
+ docfilename [ dotpos + 3 ] = 'c' ;
+ docfilename [ dotpos + 4 ] = ' ' ;
+ }
+ dotpos = dotpos - slashpos ;
+ {register integer for_end; i = 1 ; for_end = dotpos ; if ( i <=
+ for_end) do
+ {
+ progfilename [ i ] = docfilename [ i + slashpos ] ;
+ }
+ while ( i++ < for_end ) ; }
+ docdotpos = dotpos ;
+ founddoc = true ;
+ }
+ else if ( ! foundchange )
+ {
+ dotpos = -1 ;
+ i = 1 ;
+ while ( ( fname [ i ] != ' ' ) && ( i <= 115 ) ) {
+
+ changefilename [ i ] = fname [ i ] ;
+ if ( fname [ i ] == '.' )
+ dotpos = i ;
+ else if ( fname [ i ] == '/' )
+ dotpos = -1 ;
+ i = i + 1 ;
+ }
+ if ( dotpos == -1 )
+ {
+ dotpos = i ;
+ changefilename [ dotpos ] = '.' ;
+ changefilename [ dotpos + 1 ] = 'c' ;
+ changefilename [ dotpos + 2 ] = 'h' ;
+ changefilename [ dotpos + 3 ] = ' ' ;
+ }
+ foundchange = true ;
+ }
+ else {
+
+ {
+ (void) putc('\n', stdout );
+ (void) Fputs( stdout , "! Usage: makeprog [-progext] docfile[.doc] [changefile[.ch]]" ) ;
+ }
+ error () ;
+ uexit ( 1 ) ;
+ }
+ }
+ else {
+
+ i = 1 ;
+ while ( ( i < 6 ) && ( fname [ i + 1 ] != ' ' ) ) {
+
+ progextension [ i ] = fname [ i + 1 ] ;
+ i = i + 1 ;
+ }
+ progextension [ i ] = ' ' ;
+ if ( i > 5 )
+ {
+ {
+ (void) putc('\n', stdout );
+ (void) Fputs( stdout , "! Usage: makeprog [-progext] docfile[.doc] [changefile[.ch]]" ) ;
+ }
+ error () ;
+ uexit ( 1 ) ;
+ }
+ }
+ }
+ while ( a++ < for_end ) ; }
+ if ( ! founddoc )
+ {
+ {
+ (void) putc('\n', stdout );
+ (void) Fputs( stdout , "! Usage: makeprog [-progext] docfile[.doc] [changefile[.ch]]" ) ;
+ }
+ error () ;
+ uexit ( 1 ) ;
+ }
+ {
+ i = 1 ;
+ if ( progextension [ 1 ] == ' ' )
+ progfilename [ dotpos ] = ' ' ;
+ else while ( progextension [ i ] != ' ' ) {
+
+ progfilename [ docdotpos + i ] = progextension [ i ] ;
+ i = i + 1 ;
+ }
+ }
+ if ( ! foundchange )
+ {
+ changefilename [ 1 ] = '/' ;
+ changefilename [ 2 ] = 'd' ;
+ changefilename [ 3 ] = 'e' ;
+ changefilename [ 4 ] = 'v' ;
+ changefilename [ 5 ] = '/' ;
+ changefilename [ 6 ] = 'n' ;
+ changefilename [ 7 ] = 'u' ;
+ changefilename [ 8 ] = 'l' ;
+ changefilename [ 9 ] = 'l' ;
+ changefilename [ 10 ] = ' ' ;
+ }
+}
+initialize () {
+ schar i ;
+ history = 0 ;
+ xchr [ 32 ] = ' ' ;
+ xchr [ 33 ] = '!' ;
+ xchr [ 34 ] = '"' ;
+ xchr [ 35 ] = '#' ;
+ xchr [ 36 ] = '$' ;
+ xchr [ 37 ] = '%' ;
+ xchr [ 38 ] = '&' ;
+ xchr [ 39 ] = '\'' ;
+ xchr [ 40 ] = '(' ;
+ xchr [ 41 ] = ')' ;
+ xchr [ 42 ] = '*' ;
+ xchr [ 43 ] = '+' ;
+ xchr [ 44 ] = ',' ;
+ xchr [ 45 ] = '-' ;
+ xchr [ 46 ] = '.' ;
+ xchr [ 47 ] = '/' ;
+ xchr [ 48 ] = '0' ;
+ xchr [ 49 ] = '1' ;
+ xchr [ 50 ] = '2' ;
+ xchr [ 51 ] = '3' ;
+ xchr [ 52 ] = '4' ;
+ xchr [ 53 ] = '5' ;
+ xchr [ 54 ] = '6' ;
+ xchr [ 55 ] = '7' ;
+ xchr [ 56 ] = '8' ;
+ xchr [ 57 ] = '9' ;
+ xchr [ 58 ] = ':' ;
+ xchr [ 59 ] = ';' ;
+ xchr [ 60 ] = '<' ;
+ xchr [ 61 ] = '=' ;
+ xchr [ 62 ] = '>' ;
+ xchr [ 63 ] = '?' ;
+ xchr [ 64 ] = '@' ;
+ xchr [ 65 ] = 'A' ;
+ xchr [ 66 ] = 'B' ;
+ xchr [ 67 ] = 'C' ;
+ xchr [ 68 ] = 'D' ;
+ xchr [ 69 ] = 'E' ;
+ xchr [ 70 ] = 'F' ;
+ xchr [ 71 ] = 'G' ;
+ xchr [ 72 ] = 'H' ;
+ xchr [ 73 ] = 'I' ;
+ xchr [ 74 ] = 'J' ;
+ xchr [ 75 ] = 'K' ;
+ xchr [ 76 ] = 'L' ;
+ xchr [ 77 ] = 'M' ;
+ xchr [ 78 ] = 'N' ;
+ xchr [ 79 ] = 'O' ;
+ xchr [ 80 ] = 'P' ;
+ xchr [ 81 ] = 'Q' ;
+ xchr [ 82 ] = 'R' ;
+ xchr [ 83 ] = 'S' ;
+ xchr [ 84 ] = 'T' ;
+ xchr [ 85 ] = 'U' ;
+ xchr [ 86 ] = 'V' ;
+ xchr [ 87 ] = 'W' ;
+ xchr [ 88 ] = 'X' ;
+ xchr [ 89 ] = 'Y' ;
+ xchr [ 90 ] = 'Z' ;
+ xchr [ 91 ] = '[' ;
+ xchr [ 92 ] = '\\' ;
+ xchr [ 93 ] = ']' ;
+ xchr [ 94 ] = '^' ;
+ xchr [ 95 ] = '_' ;
+ xchr [ 96 ] = '`' ;
+ xchr [ 97 ] = 'a' ;
+ xchr [ 98 ] = 'b' ;
+ xchr [ 99 ] = 'c' ;
+ xchr [ 100 ] = 'd' ;
+ xchr [ 101 ] = 'e' ;
+ xchr [ 102 ] = 'f' ;
+ xchr [ 103 ] = 'g' ;
+ xchr [ 104 ] = 'h' ;
+ xchr [ 105 ] = 'i' ;
+ xchr [ 106 ] = 'j' ;
+ xchr [ 107 ] = 'k' ;
+ xchr [ 108 ] = 'l' ;
+ xchr [ 109 ] = 'm' ;
+ xchr [ 110 ] = 'n' ;
+ xchr [ 111 ] = 'o' ;
+ xchr [ 112 ] = 'p' ;
+ xchr [ 113 ] = 'q' ;
+ xchr [ 114 ] = 'r' ;
+ xchr [ 115 ] = 's' ;
+ xchr [ 116 ] = 't' ;
+ xchr [ 117 ] = 'u' ;
+ xchr [ 118 ] = 'v' ;
+ xchr [ 119 ] = 'w' ;
+ xchr [ 120 ] = 'x' ;
+ xchr [ 121 ] = 'y' ;
+ xchr [ 122 ] = 'z' ;
+ xchr [ 123 ] = '{' ;
+ xchr [ 124 ] = '|' ;
+ xchr [ 125 ] = '}' ;
+ xchr [ 126 ] = '~' ;
+ xchr [ 0 ] = ' ' ;
+ xchr [ 127 ] = ' ' ;
+ {register integer for_end; i = 1 ; for_end = 31 ; if ( i <= for_end) do
+ xchr [ i ] = ' ' ;
+ while ( i++ < for_end ) ; }
+ xchr [ 9 ] = chr ( 9 ) ;
+ {register integer for_end; i = 0 ; for_end = 127 ; if ( i <= for_end) do
+ xord [ chr ( i ) ] = 32 ;
+ while ( i++ < for_end ) ; }
+ {register integer for_end; i = 1 ; for_end = 126 ; if ( i <= for_end) do
+ xord [ xchr [ i ] ] = i ;
+ while ( i++ < for_end ) ; }
+ scanargs () ;
+ reset ( docfile , docfilename ) ;
+ reset ( changefile , changefilename ) ;
+ rewrite ( progfile , progfilename ) ;
+ state = 2 ;
+}
+boolean zinputln ( f )
+textfile f ;
+{register boolean Result; integer finallimit ;
+ limit = 0 ;
+ finallimit = 0 ;
+ if ( feof ( f ) )
+ Result = false ;
+ else {
+
+ while ( ! eoln ( f ) ) {
+
+ buffer [ limit ] = xord [ getc ( f ) ] ;
+ limit = limit + 1 ;
+ if ( ( buffer [ limit - 1 ] != 32 ) && ( buffer [ limit - 1 ] != 9 ) )
+ finallimit = limit ;
+ if ( limit == bufsize )
+ {
+ while ( ! eoln ( f ) ) vgetc ( f ) ;
+ limit = limit - 1 ;
+ {
+ (void) putc('\n', stdout );
+ (void) Fputs( stdout , "! Input line too long" ) ;
+ }
+ error () ;
+ history = 2 ;
+ }
+ }
+ readln ( f ) ;
+ limit = finallimit ;
+ Result = true ;
+ }
+ return(Result) ;
+}
+boolean linesdontmatch () {
+ /* 10 */ register boolean Result; integer k ;
+ Result = true ;
+ if ( changelimit != limit )
+ goto lab10 ;
+ if ( limit > 0 )
+ {register integer for_end; k = 0 ; for_end = limit - 1 ; if ( k <= for_end)
+ do
+ if ( changebuffer [ k ] != buffer [ k ] )
+ goto lab10 ;
+ while ( k++ < for_end ) ; }
+ Result = false ;
+ lab10: ;
+ return(Result) ;
+}
+primethechangebuffer () {
+ /* 22 30 10 */ integer k ;
+ changelimit = 0 ;
+ while ( true ) {
+
+ line = line + 1 ;
+ if ( ! inputln ( changefile ) )
+ goto lab10 ;
+ if ( limit < 2 )
+ goto lab22 ;
+ if ( buffer [ 0 ] != 64 )
+ goto lab22 ;
+ if ( ( buffer [ 1 ] >= 88 ) && ( buffer [ 1 ] <= 90 ) )
+ buffer [ 1 ] = buffer [ 1 ] + 32 ;
+ if ( buffer [ 1 ] == 120 )
+ goto lab30 ;
+ if ( ( buffer [ 1 ] == 121 ) || ( buffer [ 1 ] == 122 ) )
+ {
+ {
+ (void) putc('\n', stdout );
+ (void) Fputs( stdout , "! Where is the matching @x?" ) ;
+ }
+ error () ;
+ history = 2 ;
+ }
+ lab22: ;
+ }
+ lab30: ;
+ do {
+ line = line + 1 ;
+ if ( ! inputln ( changefile ) )
+ {
+ {
+ {
+ (void) putc('\n', stdout );
+ (void) Fputs( stdout , "! Change file ended after @x" ) ;
+ }
+ error () ;
+ history = 2 ;
+ }
+ goto lab10 ;
+ }
+ } while ( ! ( limit > 0 ) ) ;
+ {
+ changelimit = limit ;
+ {register integer for_end; k = 0 ; for_end = limit - 1 ; if ( k <=
+ for_end) do
+ changebuffer [ k ] = buffer [ k ] ;
+ while ( k++ < for_end ) ; }
+ }
+ lab10: ;
+}
+checkchange () {
+ /* 10 */ integer n ;
+ integer k ;
+ if ( linesdontmatch () )
+ goto lab10 ;
+ n = 0 ;
+ while ( true ) {
+
+ {
+ changing = ! changing ;
+ templine = otherline ;
+ otherline = line ;
+ line = templine ;
+ }
+ line = line + 1 ;
+ if ( ! inputln ( changefile ) )
+ {
+ {
+ {
+ (void) putc('\n', stdout );
+ (void) Fputs( stdout , "! Change file ended before @y" ) ;
+ }
+ error () ;
+ history = 2 ;
+ }
+ changelimit = 0 ;
+ {
+ changing = ! changing ;
+ templine = otherline ;
+ otherline = line ;
+ line = templine ;
+ }
+ goto lab10 ;
+ }
+ if ( limit > 1 )
+ if ( buffer [ 0 ] == 64 )
+ {
+ if ( ( buffer [ 1 ] >= 88 ) && ( buffer [ 1 ] <= 90 ) )
+ buffer [ 1 ] = buffer [ 1 ] + 32 ;
+ if ( ( buffer [ 1 ] == 120 ) || ( buffer [ 1 ] == 122 ) )
+ {
+ {
+ (void) putc('\n', stdout );
+ (void) Fputs( stdout , "! Where is the matching @y?" ) ;
+ }
+ error () ;
+ history = 2 ;
+ }
+ else if ( buffer [ 1 ] == 121 )
+ {
+ if ( n > 0 )
+ {
+ {
+ (void) putc('\n', stdout );
+ (void) fprintf( stdout , "%s%ld%s", "! Hmm... " , (long)n , " of the preceding lines failed to match" ) ;
+ }
+ error () ;
+ history = 2 ;
+ }
+ goto lab10 ;
+ }
+ }
+ {
+ changelimit = limit ;
+ {register integer for_end; k = 0 ; for_end = limit - 1 ; if ( k <=
+ for_end) do
+ changebuffer [ k ] = buffer [ k ] ;
+ while ( k++ < for_end ) ; }
+ }
+ {
+ changing = ! changing ;
+ templine = otherline ;
+ otherline = line ;
+ line = templine ;
+ }
+ line = line + 1 ;
+ if ( ! inputln ( docfile ) )
+ {
+ {
+ {
+ (void) putc('\n', stdout );
+ (void) Fputs( stdout , "! CWEB file ended during a change" ) ;
+ }
+ error () ;
+ history = 2 ;
+ }
+ inputhasended = true ;
+ goto lab10 ;
+ }
+ if ( linesdontmatch () )
+ n = n + 1 ;
+ }
+ lab10: ;
+}
+getline () {
+ /* 20 */ lab20: if ( changing )
+ {
+ line = line + 1 ;
+ if ( ! inputln ( changefile ) )
+ {
+ {
+ {
+ (void) putc('\n', stdout );
+ (void) Fputs( stdout , "! Change file ended without @z" ) ;
+ }
+ error () ;
+ history = 2 ;
+ }
+ buffer [ 0 ] = 64 ;
+ buffer [ 1 ] = 122 ;
+ limit = 2 ;
+ }
+ if ( limit > 1 )
+ if ( buffer [ 0 ] == 64 )
+ {
+ if ( ( buffer [ 1 ] >= 88 ) && ( buffer [ 1 ] <= 90 ) )
+ buffer [ 1 ] = buffer [ 1 ] + 32 ;
+ if ( ( buffer [ 1 ] == 120 ) || ( buffer [ 1 ] == 121 ) )
+ {
+ {
+ (void) putc('\n', stdout );
+ (void) Fputs( stdout , "! Where is the matching @z?" ) ;
+ }
+ error () ;
+ history = 2 ;
+ }
+ else if ( buffer [ 1 ] == 122 )
+ {
+ primethechangebuffer () ;
+ {
+ changing = ! changing ;
+ templine = otherline ;
+ otherline = line ;
+ line = templine ;
+ }
+ }
+ }
+ }
+ if ( ! changing )
+ {
+ {
+ line = line + 1 ;
+ if ( ! inputln ( docfile ) )
+ inputhasended = true ;
+ else if ( changelimit > 0 )
+ checkchange () ;
+ }
+ if ( changing )
+ goto lab20 ;
+ }
+ buffer [ limit ] = 32 ;
+ if ( ( line % 500 ) == 0 )
+ {
+ (void) fprintf( stdout , "%ld", (long)line ) ;
+ flush ( stdout ) ;
+ }
+ else if ( ( line % 100 ) == 0 )
+ {
+ (void) putc( '.' , stdout );
+ flush ( stdout ) ;
+ }
+}
+putline () {
+ integer i ;
+ {register integer for_end; i = 0 ; for_end = limit - 1 ; if ( i <= for_end)
+ do
+ (void) putc( xchr [ buffer [ i ] ] , progfile );
+ while ( i++ < for_end ) ; }
+ (void) putc('\n', progfile );
+}
+main_body() {
+
+ initialize () ;
+ (void) fprintf( stdout , "%s\n", "This is MAKEPROG, C Version 1.0.1." ) ;
+ (void) fprintf( stdout , "%s\n", " (c) 1988,1990 by J.Schrod." ) ;
+ (void) fprintf( stdout , "%s\n", " All rights reserved." ) ;
+ {
+ line = 0 ;
+ otherline = 0 ;
+ changing = true ;
+ primethechangebuffer () ;
+ {
+ changing = ! changing ;
+ templine = otherline ;
+ otherline = line ;
+ line = templine ;
+ }
+ limit = 0 ;
+ buffer [ 0 ] = 32 ;
+ inputhasended = false ;
+ }
+ {
+ getline () ;
+ while ( ! inputhasended ) {
+
+ {
+ if ( buffer [ 0 ] == 92 )
+ if ( limit >= 10 )
+ {
+ if ( ( buffer [ 1 ] == 98 ) && ( buffer [ 2 ] == 101 ) && ( buffer [
+ 3 ] == 103 ) && ( buffer [ 4 ] == 105 ) && ( buffer [ 5 ] == 110 )
+ && ( buffer [ 6 ] == 112 ) && ( buffer [ 7 ] == 114 ) && ( buffer [
+ 8 ] == 111 ) && ( buffer [ 9 ] == 103 ) && ( ( buffer [ 10 ] < 65 )
+ || ( buffer [ 10 ] > 90 ) ) && ( ( buffer [ 10 ] < 97 ) || ( buffer
+ [ 10 ] > 122 ) ) )
+ state = 0 ;
+ }
+ else if ( limit >= 8 )
+ if ( ( buffer [ 1 ] == 101 ) && ( buffer [ 2 ] == 110 ) && ( buffer [
+ 3 ] == 100 ) && ( buffer [ 4 ] == 112 ) && ( buffer [ 5 ] == 114 ) &&
+ ( buffer [ 6 ] == 111 ) && ( buffer [ 7 ] == 103 ) && ( ( buffer [ 8 ]
+ == 32 ) || ( buffer [ 8 ] == 9 ) ) )
+ state = 2 ;
+ }
+ if ( state == 1 )
+ putline () ;
+ else if ( state == 0 )
+ state = 1 ;
+ getline () ;
+ }
+ if ( state == 1 )
+ {
+ {
+ (void) putc('\n', stdout );
+ (void) Fputs( stdout , "! Input has ended prematurely" ) ;
+ }
+ error () ;
+ history = 2 ;
+ }
+ }
+ {
+ if ( changelimit != 0 )
+ {
+ {register integer for_end; limit = 0 ; for_end = changelimit ; if (
+ limit <= for_end) do
+ buffer [ limit ] = changebuffer [ limit ] ;
+ while ( limit++ < for_end ) ; }
+ limit = changelimit ;
+ changing = true ;
+ line = otherline ;
+ {
+ {
+ (void) putc('\n', stdout );
+ (void) Fputs( stdout , "! Change file entry did not match" ) ;
+ }
+ error () ;
+ history = 2 ;
+ }
+ }
+ }
+ lab9999: switch ( history )
+ {case 0 :
+ {
+ (void) putc('\n', stdout );
+ (void) Fputs( stdout , "(No errors were found.)" ) ;
+ }
+ break ;
+ case 1 :
+ {
+ (void) putc('\n', stdout );
+ (void) Fputs( stdout , "(Did you see the warning message above?)" ) ;
+ }
+ break ;
+ case 2 :
+ {
+ (void) putc('\n', stdout );
+ (void) Fputs( stdout , "(Pardon me, but I think I spotted something wrong.)" )
+ ;
+ }
+ break ;
+ case 3 :
+ {
+ (void) putc('\n', stdout );
+ (void) Fputs( stdout , "(That was a fatal error, my friend.)" ) ;
+ }
+ break ;
+ }
+ (void) putc('\n', stdout );
+ if ( ( history != 0 ) && ( history != 1 ) )
+ exit ( 1 ) ;
+ else exit ( 0 ) ;
+}
diff --git a/support/makeprog/webtoc/makeprog.ch b/support/makeprog/webtoc/makeprog.ch
new file mode 100644
index 0000000000..708e176efd
--- /dev/null
+++ b/support/makeprog/webtoc/makeprog.ch
@@ -0,0 +1,475 @@
+% Change file for the MAKEPROG processor, for use with WEB to C.
+% This file was created for TANGLE by Howard Trickey and Pavel Curtis.
+% Modified for MAKEPROG by Klaus Guntermann at THD
+
+% History:
+% 10/9/82 (HT) Original version
+% 11/29 (HT) New version, with conversion to lowercase handled properly
+% Also, new control sequence:
+% @=...text...@> Put ...text... verbatim on a line
+% by itself in the Pascal output.
+% (argument must fit on one line)
+% This control sequence facilitates putting #include "gcons.h"
+% (for example) in files meant for the pc compiler.
+% Also, changed command line usage, so that the absence of a
+% change file implies no change file, rather than one with the
+% same name as the web file, with .ch at the end.
+% 1/15/83 (HT) Changed to work with version 1.2, which incorporates the
+% above change (though unbundling the output line breaking),
+% so mainly had to remove stuff.
+% 2/17 (HT) Fixed bug that caused 0-9 in identifiers to be converted to
+% Q-Y on output.
+% 3/18 (HT) Brought up to work with Version 1.5. Added -r command line
+% flag to cause a .rpl file to be written with all the lines
+% of the .web file that were replaced because of the .ch file
+% (useful for comparing with previous .rpl files, to see if a
+% change file will still work with a new version of a .web file)
+% Also, made it write a newline just before exit.
+% 4/12 (PC) Merged with Pavel's version, including adding a call to exit()
+% at the end depending upon the value of history.
+% 4/16 (PC) Brought up to date with version 1.5 released April, 1983.
+% 6/28 (HWT) Brought up to date with version 1.7 released June, 1983.
+% With new change file format, the -r option is now unnecessary.
+% 7/17 (HWT) Brought up to date with version 2.0 released July, 1983.
+% 12/18 (ETM) Brought up to date with version 2.5 released November, 1983.
+% 11/7/84 (ETM) Brought up to date with version 2.6.
+% 12/15/85 (ETM) Brought up to date with version 2.8.
+% 3/ 7/88 (ETM) Converted for use with WEB2C
+% 04/07/89 (-kg) Changed for MAKEPROG
+
+% NOTE: The module numbers refer to the red-covered listing (Version 2).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [0] WEAVE: print only changes
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ x
+\pageno=\contentspagenumber \advance\pageno by 1
+ y
+\pageno=\contentspagenumber \advance\pageno by 1
+\let\maybe=\iffalse
+\def\title{TANGLE changes C}
+ z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [1] Change banner message
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@d banner=='This is MAKEPROG, Version 1.0.1.'
+@y
+@d banner=='This is MAKEPROG, C Version 1.0.1.'
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [2] add input and output, remove other files, add ref to scan_args,
+% [2] and #include external definition for exit().
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@d end_of_MAKEPROG = 9999 {go here to wrap it up}
+
+@p @t\4@>@<Compiler directives@>@/
+program MAKEPROG(@!doc_file,@!change_file,@!prog_file);
+label end_of_MAKEPROG; {go here to finish}
+const @<Constants in the outer block@>@;
+type @<Types in the outer block@>@;
+var @<Globals in the outer block@>@;
+@t\4@>@<Error handling procedures@>@;
+@y
+@d end_of_MAKEPROG = 9999 {go here to wrap it up}
+@d eof==feof
+
+@p @t\4@>@<Compiler directives@>@/
+program MAKEPROG;
+label end_of_MAKEPROG; {go here to finish}
+const @<Constants in the outer block@>@;
+type @<Types in the outer block@>@;
+var @<Globals in the outer block@>@;
+@t\4@>@<Error handling procedures@>@;
+@<Declaration of |scan_args|@>@/
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [4] compiler options
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@{@&@=$D-@> @} {no debug overhead}
+@!debug @{@&@=$D+@> @}@+ gubed @; {but turn everything on when debugging}
+@y
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [17] Allow tabs in input and output files
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+\MAKEPROG{} are allowed to have in their input files,
+provided that unsuitable characters do not correspond to
+special codes like |carriage_return| that are listed above.
+
+@<Set init...@>=
+for i:=1 to " "-1 do xchr[i]:=' ';
+@y
+\MAKEPROG{} are allowed to have in their input files,
+provided that unsuitable characters do not correspond to
+special codes like |carriage_return| that are listed above.
+Here we add the tab character to the untranslated ones.
+@<Set init...@>=
+for i:=1 to " "-1 do xchr[i]:=' ';
+xchr[tab_mark]:=chr(tab_mark);
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [20] terminal output: use standard i/o
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@d print(#)==write(term_out,#) {`|print|' means write on the terminal}
+@y
+@d term_out==stdout
+@d print(#)==write(term_out,#) {`|print|' means write on the terminal}
+@z
+
+@x
+@<Globals...@>=
+@!term_out:text_file; {the terminal as an output file}
+@y
+
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [21] init terminal
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+Different systems have different ways of specifying that the
+output on a certain file will appear on the user's terminal.
+Here is one way to do this on the \PASCAL{} system that was
+used in \.{TANGLE}'s initial development.
+@^system dependencies@>
+
+@<Set init...@>=
+rewrite(term_out,'TTY:'); {send |term_out| output to the terminal}
+@y
+Different systems have different ways of specifying that the output on a
+certain file will appear on the user's terminal.
+@^system dependencies@>
+
+@<Set init...@>=
+ {Nothing need be done C}
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [22] flush terminal buffer
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@d update_terminal == break(term_out) {empty the terminal output buffer}
+@y
+@d update_terminal == flush(term_out) {empty the terminal output buffer}
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [24] open input files
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+The following code opens the input files. Since these files
+were listed in the program header, we assume that the
+\PASCAL\ runtime system has already checked that suitable
+file names have been given; therefore no additional error
+checking needs to be done.
+@^system dependencies@>
+
+@< Set init... @>=
+reset(doc_file); reset(change_file);
+@y
+The following code opens the input files.
+Use the |scan_args| procedure to fill the global file names,
+according to the names given on the command line.
+These globals, and the |scan_args| procedure will be defined at the end
+where they won't disturb the module numbering.
+@^system dependencies@>
+
+@< Set init... @>=
+scan_args;
+reset(doc_file,doc_file_name); reset(change_file,change_file_name);
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [26] open output files
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+The following code opens |prog_file|. Since this file is
+listed in the program header, we assume that the \PASCAL\
+runtime system has checked that a suitable external file
+name have been given.
+@^system dependencies@>
+
+@<Set init...@>=
+rewrite(prog_file);
+@y
+The following code opens |prog_file|.
+@^system dependencies@>
+
+@<Set init...@>=
+rewrite(prog_file,prog_file_name);
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Fix f^
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+ if eof(f) then input_ln:=false
+ else begin
+ while not eoln(f) do
+ begin buffer[limit]:=xord[f^]; get(f);
+ incr(limit);
+ if (buffer[limit-1]<>" ") and (buffer[limit-1]<>tab_mark) then
+ final_limit:=limit;
+ if limit=buf_size then
+ begin while not eoln(f) do get(f);
+@y
+if eof(f) then input_ln:=false
+else begin while not eoln(f) do
+ begin buffer[limit]:=xord[getc(f)];
+ incr(limit);
+ if (buffer[limit-1]<>" ") and (buffer[limit-1]<>tab_mark) then
+ final_limit:=limit;
+ if limit=buf_size then
+ begin while not eoln(f) do vgetc(f);
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Fix jump_out
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@d fatal_error(#)==begin print_nl(#); error; mark_fatal; jump_out;
+ end
+
+@<Error handling...@>=
+procedure jump_out;
+begin goto end_of_MAKEPROG;
+end;
+@y
+@d jump_out==uexit(1)
+@d fatal_error(#)==begin new_line; print(#); error; mark_fatal; uexit(1);
+ end
+@z
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [182] write newline just before exit; use value of |history|
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+\noindent We have defined some procedures, and it is time to
+use them---here is where \MAKEPROG{} starts, and where it
+ends.
+@^system dependencies@>
+@y
+\noindent We have defined some procedures, and it is time to
+use them---here is where \MAKEPROG{} starts, and where it
+ends.
+@^system dependencies@>
+
+@d UNIXexit==e@&x@&i@&t
+@z
+
+@x
+ @<Print the job |history|@>;
+@y
+ @<Print the job |history|@>;
+ new_line;
+ if (history <> spotless) and (history <> harmless_message) then
+ UNIXexit(1)
+ else
+ UNIXexit(0);
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [188] system dependent changes--the |scan_args| procedure.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+\noindent This module should be replaced, if necessary, by
+changes to the program that are necessary to make
+\MAKEPROG{} work at a particular installation. It is
+usually best to design your change file so that all changes
+to previous modules preserve the module numbering; then
+everybody's version will be consistent with the printed
+program. More extensive changes, which introduce new
+modules, can be inserted here; then only the index itself
+will get a new module number.
+@^system dependencies@>
+@y
+@^system dependencies@>
+
+The user calls \.{MAKEPROG} with arguments on the command line.
+These are either file names or flags (beginning with '-').
+The following globals are for communicating the user's desires to the rest
+of the program. The various |file_name| variables contain strings with
+the full names of those files, as UNIX knows them.
+
+There are no flags that affect \.{MAKEPROG} at the moment.
+
+@d max_file_name_length=120
+@d max_extension=5
+
+@<Globals...@>=
+@!doc_file_name,@!change_file_name,@!prog_file_name:
+ array[1..max_file_name_length] of char;
+@!prog_extension: array[1..max_file_name_length] of char;
+
+@ The |scan_args| procedure looks at the command line arguments and sets
+the |file_name| variables accordingly.
+At least one file name must be present: the \.{DOC} file. It may have
+an extension, or it may omit it to get |'.doc'| added.
+The output file name is formed by replacing the \.{DOC} file
+name extension by |'.prg'|.
+The output file will be created in the current directory.
+
+If there is another file name present among the arguments, it is the
+change file, again either with an extension or without one to get |'.ch'|
+An omitted change file argument means that |'/dev/null'| should be used,
+when no changes are desired.
+
+@<Declaration of |scan_args|@>=
+procedure scan_args;
+var doc_dot_pos,dot_pos,i,a,slash_pos: integer; {indices}
+c: char;
+@!fname: array[1..max_file_name_length] of char; {temporary argument holder}
+@!found_doc,@!found_change: boolean; {|true| when those file names have
+ been seen}
+begin
+prog_extension[1]:='p';
+prog_extension[2]:='r';
+prog_extension[3]:='o';
+prog_extension[4]:='g';
+prog_extension[5]:=' ';
+found_doc:=false;
+found_change:=false;
+for a:=1 to argc-1 do begin
+ argv(a,fname); {put argument number |a| into |fname|}
+ if fname[1]<>'-' then begin
+ if not found_doc then
+ @<Get |doc_file_name| and |prog_file_name|
+ variables from |fname|@>
+ else if not found_change then
+ @<Get |change_file_name| from |fname|@>
+ else @<Print usage error message and quit@>;
+ end
+ else @<Handle flag argument in |fname|@>;
+ end;
+if not found_doc then @<Print usage error message and quit@>;
+@<Add the proper extension@>;
+if not found_change then @<Set up null change file@>;
+end;
+
+@ Use all of |fname| for the |doc_file_name| if there is a |'.'| in it,
+otherwise add |'.doc'|.
+The other file names come from adding things after the dot.
+If the name contained directory specifications, we reset the
+dot occurred flag and do not use the directory part of the name
+for the output files.
+The |argv| procedure will not put more than
+|max_file_name_length-max_extension|
+characters into |fname|, and this leaves enough room in the |file_name|
+variables to add the extensions.
+
+The end of a file name is marked with a |' '|, the convention assumed by
+the |reset| and |rewrite| procedures.
+
+@<Get |doc_file_name|...@>=
+begin
+slash_pos:=0;
+dot_pos:=-1;
+i:=1;
+while (fname[i]<>' ') and (i<=max_file_name_length-max_extension) do begin
+ doc_file_name[i]:=fname[i];
+ if fname[i]='.' then dot_pos:=i else
+ if fname[i]='/' then begin
+ slash_pos:=i; dot_pos:=-1; {reset}
+ end;
+ incr(i);
+ end;
+if dot_pos=-1 then begin
+ dot_pos:=i;
+ doc_file_name[dot_pos]:='.';
+ doc_file_name[dot_pos+1]:='d';
+ doc_file_name[dot_pos+2]:='o';
+ doc_file_name[dot_pos+3]:='c';
+ doc_file_name[dot_pos+4]:=' ';
+ end;
+dot_pos:=dot_pos-slash_pos; {may be unchanged if no slash}
+for i:=1 to dot_pos do begin
+ prog_file_name[i]:=
+ doc_file_name[i+slash_pos];
+ end;
+doc_dot_pos:=dot_pos;
+found_doc:=true;
+end
+
+@ This section must be called when the doc file was found
+and the doc dot position is determined.
+@<Add the proper extension@>=
+begin
+i:=1;
+if prog_extension[1]=' ' then prog_file_name[dot_pos]:=' '
+else
+while prog_extension[i]<>' ' do
+begin prog_file_name[doc_dot_pos+i]:=prog_extension[i];
+ i:=i+1;
+end;
+end
+
+@ @<Get |change_file_name|...@>=
+begin
+dot_pos:=-1;
+i:=1;
+while (fname[i]<>' ') and (i<=max_file_name_length-max_extension)
+do begin
+ change_file_name[i]:=fname[i];
+ if fname[i]='.' then dot_pos:=i else
+ if fname[i]='/' then dot_pos:=-1;
+ incr(i);
+ end;
+if dot_pos=-1 then begin
+ dot_pos:=i;
+ change_file_name[dot_pos]:='.';
+ change_file_name[dot_pos+1]:='c';
+ change_file_name[dot_pos+2]:='h';
+ change_file_name[dot_pos+3]:=' ';
+ end;
+found_change:=true;
+end
+
+@ @<Set up null...@>=
+begin
+ change_file_name[1]:='/';
+ change_file_name[2]:='d';
+ change_file_name[3]:='e';
+ change_file_name[4]:='v';
+ change_file_name[5]:='/';
+ change_file_name[6]:='n';
+ change_file_name[7]:='u';
+ change_file_name[8]:='l';
+ change_file_name[9]:='l';
+ change_file_name[10]:=' ';
+end
+
+@ \.{MAKEPROG} accepts the intended extension of a created file as an
+option to overwrite the default extension 'prog'.
+
+@<Handle flag...@>=
+begin
+ i:=1;
+ while (i<max_extension+1) and (fname[i+1]<>' ') do
+ begin
+ prog_extension[i]:=fname[i+1];
+ i:=i+1;
+ end;
+ prog_extension[i]:=' ';
+ if i>max_extension then
+ @<Print usage error message and quit@>;
+end
+
+@ @<Print usage error message and quit@>=
+begin
+print_nl('! Usage: makeprog [-progext] docfile[.doc] [changefile[.ch]]');
+error;
+jump_out;
+end
+
+@z
diff --git a/support/makeprog/webtoc/makeprog.h b/support/makeprog/webtoc/makeprog.h
new file mode 100644
index 0000000000..b360edeb59
--- /dev/null
+++ b/support/makeprog/webtoc/makeprog.h
@@ -0,0 +1,3 @@
+#define inputln(a) zinputln((textfile)(a))
+boolean zinputln();
+boolean linesdontmatch();
diff --git a/support/makeprog/webtoc/web2c.def b/support/makeprog/webtoc/web2c.def
new file mode 100644
index 0000000000..2321a39bd2
--- /dev/null
+++ b/support/makeprog/webtoc/web2c.def
@@ -0,0 +1,100 @@
+@define @field b0;
+@define @field b1;
+@define @field b2;
+@define @field b3;
+@define @field gr;
+@define @field hh;
+@define @field int;
+@define @field lh;
+@define @field qqqq;
+@define @field rh;
+@define procedure vgetc();
+@define function abs();
+@define function aopenin();
+@define function aopenout();
+@define function bopenin();
+@define function bopenout();
+@define function chr();
+@define function ord();
+@define function feof();
+@define function eoln();
+@define function fabs();
+@define function getc();
+@define function makefraction();
+@define function odd();
+@define function round();
+@define function takefraction();
+@define function testaccess();
+@define function toint();
+@define function trunc();
+@define function wopenin();
+@define function wopenout();
+@define procedure aclose();
+@define procedure argv();
+@define procedure bclose();
+@define procedure bgetname();
+@define procedure bwrite2bytes();
+@define procedure bwrite4bytes();
+@define procedure bwritebuf();
+@define procedure bwritebyte();
+@define procedure calledit();
+@define procedure clearterminal;
+@define procedure close();
+@define procedure dateandtime();
+@define procedure decr();
+@define procedure dumpcore;
+@define procedure dumpthings();
+@define procedure exit();
+@define procedure fflush();
+@define procedure flush();
+@define procedure fwrite();
+@define procedure getfmthh();
+@define procedure getfmtint();
+@define procedure getfmtqqqq();
+@define procedure getfmtword();
+@define procedure incr();
+@define procedure lineread();
+@define procedure linewrite();
+@define procedure putfmthh();
+@define procedure putfmtint();
+@define procedure putfmtqqqq();
+@define procedure putfmtword();
+@define procedure read();
+@define procedure readln();
+@define procedure reset();
+@define procedure rewrite();
+@define procedure setpaths;
+@define procedure termflush();
+@define procedure topenin;
+@define procedure uexit();
+@define procedure undumpthings();
+@define procedure vstrcpy();
+@define procedure wakeupterminal;
+@define procedure wclose();
+@define procedure write();
+@define procedure writedvi();
+@define procedure writeln();
+@define type boolean = 0..1;
+@define type ccharpointer;
+@define type char = 0..127;
+@define type integer;
+@define type real;
+@define type text;
+@define var argc;
+@define var false;
+@define var fmtpathspec;
+@define var fontpathspec;
+@define var stdin;
+@define var inputpathspec;
+@define var stdout;
+@define var poolpathspec;
+@define var readpathspec;
+@define var true;
+@define function testeof();
+@define procedure zfseek();
+@define function ftell();
+@define function eof();
+@define procedure printreal();
+@define procedure putbyte();
+@define function inputint();
+@define procedure input3ints();
diff --git a/support/makeprog/webtoc/web2c.h b/support/makeprog/webtoc/web2c.h
new file mode 100644
index 0000000000..d7157af264
--- /dev/null
+++ b/support/makeprog/webtoc/web2c.h
@@ -0,0 +1,52 @@
+/*
+ * Main include file for tangle etc. in C
+ *
+ * Tim Morgan 2/11/88
+ */
+
+#include <stdio.h>
+#include "site.h"
+
+/*
+ * Global routines implemented as macros, plus some type coercion stuff.
+ */
+
+#define odd(x) ((x) % 2)
+#define putbyte(x,f) putc(((x)&255), f)
+#define round(x) zround((double)(x))
+#define incr(x) ++x
+#define decr(x) --x
+#define trunc(x) ( (integer) (x) )
+#define readln(f) while (!feof(f) && getc(f) != '\n')
+#define read(f, b) b = getc(f)
+#define input3ints(a,b,c) zinput_3ints(&a, &b, &c)
+#define zfseek(f,n,w) (void) fseek(f, (long) n, (int) w)
+#define eof(f) feof(f)
+#define abs(x) ((x>=0)?(x):(-(x)))
+#define fabs(x) ((x>=0.0)?(x):(-(x)))
+#define Fputs(stream, s) (void) fputs(s, stream)
+#define rewrite(f,n) f = openf(n+1, "w")
+#define reset(f,n) f = openf(n+1, "r")
+#define flush(f) (void) fflush(f)
+#define true 1
+#define false 0
+#define chr(x) (x)
+#define ord(x) (x)
+#define vgetc(f) (void) getc(f)
+#define uexit(x) exit(x)
+
+FILE *openf();
+
+/*
+ * Global Types
+ */
+typedef FILE *text, *file_ptr;
+typedef char *ccharpointer;
+
+/*
+ * Global Data and Datastructures
+ */
+
+extern integer argc;
+extern integer zround();
+extern integer inputint();