4-Aug-87 23:16:27-PDT,14596;000000000000 Return-Path: Date: 04. August 1987, 17:04:55 (CET) From: XITIJSCH%DDATHD21.BITNET@forsythe.stanford.edu Subject: Re: footnote numbering To: TEXHAX@score.stanford.edu In the TeXhax issue #60 Malcolm Brown asked for a possibility to number footnotes subsequently on each page. He didn't state if he needs this possibility, i.e. these macros, in a special environment. In my eyes this is a nice small exercise to show the development of TeX macros and therefore I send you this contribution. First I introduce a macro set to number footnotes subsequently on each page. This macro set is written with the concept of literate programming in mind and is portable in the manner that few changes have to be made to the macros to get them running with every macro package that uses the PLAIN definitions (LaTeX does). The macro set has been tested with PLAIN TeX, LaTeX and an other macro package of my own, always with correct results. But I have only spent a few hours to write and test the macros, so don't blame me if errors occur. After introducing the macro set I close with some remarks on TeX macro development, i.e. in TeX programming and I also describe possible improvements to the macros and an other solution strategy using LaTeX. ---------------------------------------------- macro set for numbering footnotes on each page ---------- cut here ------------------------------------------------------ % % 1. (@*) Introduction. % % This macro set numbers footnotes subsequently on each page. % It was written by J. Schrod on August 1, 1987. % A footnote is typeset by the command \footnote. This command % has one parameter, the text of the footnote. The macro % package assumes that the conventions set up by PLAIN are in % effect and is written primarily for use with PLAIN. With two minor % changes it runs with LaTeX, but in LaTeX better approaches % are available. Every place in the macro set where the used % macro package is important has the line % % @~ system dependencies @> % % added (WEB lives!). We use the private macros of PLAIN % and for that reason we catcode the character `@' to letter. \begingroup % to get the catcode change local \catcode`\@=11 % 2. But let's regard first the implementation strategy. Because % the contents of one page is determined at (nearly) random places % with an asynchronous invogation of the output routine, we can not % give numbers to every footnote subsequently between output and % output: a footnote at the top of a page will perhaps get a number % before the output is triggered and there is no way to change % this number. The problem is like forward references to text % places and it is solved in a similar fashion. We need two TeX runs % to get the numbering right but this is acceptable (who's got a % finished text after one run?!). In the first run we gather up in % a file the information where the footnotes are standing and in % the second run we use this information. % 3. This leads to our first code, the initialization of the % macro set. We need a file descriptor, \foot@file, which we % use for the file interaction. The name of the file is built % from the jobname and the suffix `.fot' (I hope that no macro % package uses this suffix). % @~ system dependencies @> % % The \init@footnote macro reads the contents of the footnote % file if it exists (\ifeof returns true if the file doesn't % exist). The description of the reading of this file % (\read@foot@file) is deferred until we know the structure % of the contents. After reading, the file is closed and we % can open it for writing. For security, i.e. to have a defined % minimal contents, we immediately write \relax to the file. % In the end the macro defines itself to \relax to allow calling % it again. % % Please note here the placement of `%' chars. Because we don't % know if this macro is used only in vertical mode, % (italics on) % every line not ending with a macro name is ended by a %. % (italics off) \newwrite\foot@file \gdef\foot@file@name{\jobname.fot \relax} \gdef\init@footnote{% \openin\foot@file=\foot@file@name \ifeof\foot@file \closein\foot@file \else \closein\foot@file \read@foot@file \fi \immediate\openout\foot@file=\foot@file@name \immediate\write\foot@file{\relax}% \let\init@footnote=\relax } % 4. Now comes the first real macro package dependent part. % We want to set the footnote with a number in the superscript % position (or with a corresponding symbol for that number). This % is done with the macro \@footnote, which gets the number as its % parameter. Below are the definitions for PLAIN TeX and LaTeX, % the LaTeX part is commented out. To activate it, simply comment % the PLAIN part out and remove the other `%'-signs. % % I think here is the place to state that I'm no LaTeX wizard. % I don't know if there are any other (better) ways to get the % footnote. \let\@@footnote=\footnote % original meaning of \footnote \gdef\@footnote#1{% % set footnote with mark #1 (PLAIN) \@@footnote{\hbox{$~{#1}$}}% } %\gdef\@footnote#1{% % set footnote with mark #1 (LaTeX) % \xdef\@thefnmark{#1}\@footnotemark\@footnotetext % } % % 5. (@*) Realisation. % % We must identify all footnotes if we write their numbers to % the footnote file, so each footnote gets an unary name % built with the counter \footno. The name is `f@', % where is the footnote name number. This name % building scheme has several disadvantages, e.g. the insertion % of a new footnote destroys the knowledge of the former run % about the following footnotes. In the beginning of every % footnote \init@footnote is called to guarantee that the % handling is initialized (this especially means that the % footnote numbers are read in by the first footnote). \newcount\footno % for generating footnote mark names \newcount\@footno % numbers of footnotes % 6. It remains an open problem how to get the numbers there. % The footnote numbering must be initialized to zero in the % output routine and every footnote must increment this footnote % number. The only thing that is expanded during the output % process is the output routine itself and the \write's, but % the expanded tokens of \write are written out, not interpreted. % Well, the idea is simple: We defer the counting to the second % run and write the instructions that do this to the file. The % counting is then done while reading the footnote file. % % That means that the output routine adds entries like % \@footno = 0 % and every footnote adds an entry that looks like % \advance\@footno by 1 \xdef\csname f@ \endcsname{\number\@footno} % where is replaced by the current footnote name number. % The expansion of \footno must be made in \footnote, therefore % we first define the macro \@dowrite which contains the \write % and the expanded tokens which are to be put out. Every token % that should not be expanded is prefixed by \string (resulting % in character tokens that represent the token name) and a \space % must be inserted to separate \csname from f. % % After writing the entry to the footnote file the \footnote % macro defines the footnote mark to `?' if it is not already % defined (from a previous run). To build the token name first % and test afterwards an \expandafter is needed. At the end the % \@footnote command is issued. \gdef\footnote{% \init@footnote \global\advance\footno by \@ne \edef\@dowrite{% \write\foot@file{% \string\advance\@footno\@ne \string\expandafter\xdef \string\csname\space f@\number\footno \endcsname{% \string\number\@footno }% }% }% \@dowrite \expandafter\ifx \csname f@\number\footno \endcsname \relax \expandafter\gdef \csname f@\number\footno \endcsname {?}% \fi \@footnote{\csname f@\number\footno \endcsname}% } % 7. Now let's look at the intervention in the output routine. The % goal is to be (almost) independent from the used output routine. % This is done by forming a layer around the originial output routine, % but relies on the fact that the output routine is not altered % by itself. For macro packages doing so an expansion of the % output routine has to be made. % @~ system dependencies @> % % Output routines serve for two purposes: they put out text % to the file and they collect information. Usually macro packages % communicate with the output routine by inserting special % penalties. This macro set assumes that penalties above % -\@maxpenalty are used to output text and penalties below % -\@maxpenalty do other things (look at LATEX.TEX if you % wonder what one can do in the output routine...). For every % macro package \@maxpenalty has to be adjusted. If the precondition % of one range of penalties for text output doesn't hold the % following algorithm has to be altered. As with the definition % of \@footnote, both the values for PLAIN TeX and for LaTeX are % given, the LaTeX value is commented out. % @~ system dependencies @> \mathchardef\@maxpenalty=20000 % maximal used penalty for text pages (PLAIN) %\mathchardef\@maxpenalty=10000 % maximal used penalty for text pages (LaTeX) % 8. We must insert a \write in front of the output. There are two % ways to do this. (1) We can shipout a box copy with the \write % in it before the rest of the box (but this must be done in one % shipout or an empty page will result). This approach needs deep % intervention in the original output routine and is therefore not % used. (2) We can trigger the output routine two times for each % page. The first time we insert the \write, put the page back to % the page builder and insert a special penalty, -\foot@penalty, % which must be less than -\@maxpenalty and which must not be used % by the macro package. The value 20001 is suitable for PLAIN TeX % and LaTeX. % @~ system dependencies @> % The next time the \outputpenalty of the first time is restored % and the original output routine is called. This handling is only % done if text output appears, otherwise the original output routine % is called directly. The following output routine evolves: % % \output={ % \ifnum \outputpenalty < -\@maxpenalty % \perhaps@restore@penalty % % \else % \global\@utputpenalty = \outputpenalty % \write\foot@file{ \@footno = 0 } % \unvbox 255 % \penalty -\foot@penalty % \fi % } % % is the contents of the output token register % before executing the statement below. To insert it in the new % contents of the output register, the old output register must % be evaluated before the assignment is done. We use \expandafter % to skip over all preceding tokens. \newcount\@utputpenalty % save register for \outputpenalty \mathchardef\foot@penalty=20001 % penalty not used in macro package \output=\expandafter{% \expandafter\ifnum \expandafter\outputpenalty \expandafter<% \expandafter-\expandafter\@maxpenalty \expandafter\perhaps@restore@penalty \the\output \else \global\@utputpenalty=\outputpenalty \write\foot@file{\@footno\z@}% \nobreak \unvbox\@cclv \penalty -\foot@penalty \fi } \gdef\perhaps@restore@penalty{% \ifnum \outputpenalty=-\foot@penalty \global\outputpenalty=\@utputpenalty \fi } % 9. The last section is the reading of the footnote file. We have % to read in macros with names containing `@' characters. This % will be done in horizontal mode, so we have to ignore lineends % to discard undesired spaces. \gdef\read@foot@file{% \begingroup \catcode`\@=11 \catcode`\~~M=9 \relax \input \foot@file@name \endgroup } \catcode`\@=12 \endgroup ---------- cut here ------------------------------------------------------ For the use of the above macro set the following fact must be obeyed: IT IS STATED EXPLICITLY THAT THE COMMENTS ARE AN INTEGRAL PART OF THIS MACRO SET. IF THE MACRO SET IS ALTERED THE COMMENTS HAVE TO BE ALTERED, TOO. THEY MUST NOT BE DELETED. The writing of TeX macros is a task of programming. The computer science community has struggled for years to encourage structured program development. The idea of literate programming is promoted more and more (e.g. in the CACM). WHY DO WE THROW ALL THIS AWAY WHEN TeX MACROS ARE WRITTEN?? It is my opinion that the only satisfactory way to write TeX macros which can be maintained is to use the principles of literate programming: describing the macros for a human reader, not for TeX. (Perhaps the time will come, when we get a TeX-WEB.) It could be said very much about this topic, but back to the macros. They are not fully developed, some features are still missing, e.g. warnings when new footnotes are inserted or when footnote numbers have been changed. Other improvements can be made on the construction of the footnote names. By involving section numbers or analogous numbers the ``running away'' of the footnote numbers (caused by the insertion of a new footnote) can be limited. Scanning through the LaTeX source it seems to me that the same realization idea can be implemented by writing appropriate \newlabel commands to the auxiliary file and referencing them. But I'm not sure---perhaps L.Lamport can state a comment. Well, this has become a rather long piece. I hope, it helps you. Joachim Schrod ---------------------------------------------------------------- TH Darmstadt Institut fuer Theoretische Informatik Joachim Schrod Alexanderstr. 24 D-6100 Darmstadt West Germany -------