summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/dialogl/grabhedr.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/dialogl/grabhedr.dtx')
-rw-r--r--macros/latex/contrib/dialogl/grabhedr.dtx513
1 files changed, 513 insertions, 0 deletions
diff --git a/macros/latex/contrib/dialogl/grabhedr.dtx b/macros/latex/contrib/dialogl/grabhedr.dtx
new file mode 100644
index 0000000000..8feaf33734
--- /dev/null
+++ b/macros/latex/contrib/dialogl/grabhedr.dtx
@@ -0,0 +1,513 @@
+%%% ====================================================================
+%%% @LaTeX-style-file{
+%%% filename = "grabhedr.dtx",
+%%% version = "1.99a",
+%%% date = "2013/01/24",
+%%% author = "Michael Downes",
+%%% copyright = "This file is part of the dialogl package, released
+%%% under the LPPL; see dialogl.ins for details."
+%%% keywords = "TeX, file header,
+%%% supported = "no",
+%%% abstract = "This file defines a macro \inputfwh
+%%% to be used instead of \input, to allow TeX to grab
+%%% information from standardized file headers in the form
+%%% proposed by Nelson Beebe during his term as president of the
+%%% TeX Users Group. Of which all this here is an example.",
+%%% }
+%%% ====================================================================
+%
+% \iffalse
+%<*driver>
+\input{dia-driv.tex}
+%</driver>
+% \fi
+%
+% \section{Introduction}
+% This file defines a function \cw{inputfwh} to be used instead of
+% \cw{input}, to allow \tex/ to grab information from standardized
+% file headers in the form proposed by Nelson Beebe during his term
+% as president of the \tex/ Users Group. Usage:
+%\begin{usage}
+%\inputfwh{file.nam}
+%\end{usage}
+% Functions \cw{localcatcodes} and \cw{restorecatcodes} for
+% managing catcode changes are also defined herein, as well as a
+% handful of utility functions, many of them borrowed from
+% \fn{latex.tex}: \cw{@empty}, \cw{@gobble}, \cw{@gobbletwo},
+% \cw{@car}, \cw{@@input}, \cw{toks@}, \cw{afterfi},
+% \cw{fileversiondate}, \cw{trap.input}.
+%
+% The use of \cw{inputfwh}, \cw{fileversiondate}, and
+% \cw{trap.input} as illustrated in \fn{dialog.sty} is cumbersome
+% klugery that in fact would better be handled by appropriate
+% functionality built into the format file. But none of the major
+% formats have anything along these lines yet. (It would also help
+% if \tex/ made the current input file name accessible, like
+% \cw{inputlineno}.)
+%
+% \StopEventually{}
+%
+% \section{Implementation}
+% Standard package identification:
+% \begin{macrocode}
+%<*2e>
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage{grabhedr}[1994/11/08 v0.9j]
+%</2e>
+% \end{macrocode}
+%
+% By enclosing this entire file in a group, saving and restoring
+% catcodes `by hand' is rendered unnecessary. This is perhaps the
+% best way to locally change catcodes, better than the
+% \cw{localcatcodes} function defined below. But it tends to be
+% inconvenient for the \tex/ programmer: every time you add
+% something you have to remember to make it global; if you're like
+% me, you end up making every change twice, with an abortive test
+% run of \tex/ in between, in which you discover that a certain
+% control sequence is undefined because you didn't assign it
+% globally. (Using \cw{globaldefs} = 1 is dangerous in my experience;
+% you have to take care not to accidentally change any variables that
+% you don't want to be changed globally.)
+% \begin{macrocode}
+\begingroup
+% \end{macrocode}
+% Inside this group, enforce normal catcodes. All definitions must
+% be global in order to persist beyond the \cw{endgroup}.
+% \begin{macrocode}
+\catcode96 12 % left quote
+\catcode`\= 12
+\catcode`\{=1 \catcode`\}=2 \catcode`\#=6
+\catcode`\$=3 \catcode`\~=13 \catcode`\^=7
+\catcode`\_=8 \catcode`\^^M=5 \catcode`\"=12
+% \end{macrocode}
+% Make \qc{\@} a letter for use in `private' control sequences.
+% \begin{macrocode}
+\catcode`\@=11
+% \end{macrocode}
+%
+% \section{Preliminaries}
+% For \cw{@empty}, \cw{@gobble}, \ldots{} we use the \latex/ names so
+% that if \fn{grabhedr.sty} is used with \latex/ we won't waste hash
+% table and string pool space.
+%
+% \begin{macro}{\@empty}
+% Empty macro, for \cw{ifx} tests or initialization of variables.
+% \begin{macrocode}
+\gdef\@empty{}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@gobble}
+% \begin{macro}{\@gobbletwo}
+% \begin{macro}{\@gobblethree}
+% Functions for gobbling unwanted tokens.
+% \begin{macrocode}
+\long\gdef\@gobble#1{}
+\long\gdef\@gobbletwo#1#2{}
+\long\gdef\@gobblethree#1#2#3{}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@car}
+% The function \cw{@car}, though not really needed by
+% \fn{grabhedr.sty}, is needed by the principal customers of
+% \fn{grabhedr.sty} (e.g., \fn{dialog.sty}).
+% \begin{macrocode}
+\long\gdef\@car#1#2\@nil{#1}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@input}
+% To define \cw{@@input} as in \latex/ we want to let it equal to
+% the primitive \cw{input}. But if a \latex/ format is being used
+% we don't want to execute that assignment because by now
+% \cw{input} has changed its meaning. And if some other format is
+% being used it behooves us to check, before defining \cw{@@input},
+% whether \cw{input} still has its primitive meaning. Otherwise
+% there's a good chance \cw{inputfwh} will fail to work properly.
+% \begin{macrocode}
+\ifx\UndEFiNed\@@input % LaTeX not loaded.
+% \end{macrocode}
+% This code shows a fairly easy way to check whether the meaning of a
+% primitive control sequence is still the original meaning.
+% \begin{macrocode}
+ \edef\0{\meaning\input}\edef\1{\string\input}%
+ \ifx\0\1%
+ \global\let\@@input\input
+ \else
+ \errhelp{%
+Grabhedr.sty needs to know the name of the
+\input primitive in order to define \inputfwh
+properly. Consult a TeXnician for help.}
+ \errmessage{%
+ Non-primitive \noexpand\input detected}%
+ \fi
+\fi
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\toks@}
+% Scratch token register.
+% \begin{macrocode}
+\global\toksdef\toks@=0
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\afterfi}
+% Sonja Maus's function for throwing code over the \cw{fi} (``An
+% Expansion Power Lemma'', \TUB{} vol 12 no 2 June 1991). (Except
+% that she called this function \cw{beforefi}.)
+%
+% \begin{macrocode}
+\long\gdef\afterfi#1\fi{\fi#1}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\nx@}
+% We will be using \cw{noexpand} a lot; this abbreviation improves
+% the readability of the code.
+% \begin{macrocode}
+\global\let\nx@\noexpand
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\xp@}
+% Another convenient abbreviation.
+% \begin{macrocode}
+\global\let\xp@\expandafter
+% \end{macrocode}
+% \end{macro}
+%
+% \section{Reading standard file headers}
+% The function \cw{inputfwh} (`input file with header') inputs
+% the given file, checking first to see if it starts with a
+% standardized file header; if so, the filename, version and date
+% are scanned for and stored in a control sequence.
+%
+% For maximum robustness, we strive to rely on the fewest possible
+% assumptions about what the file that is about to be input might
+% contain.
+%
+% Assumption 1: Percent character \qc{\%} has category 14. I.e., if
+% the first line of the file to be input starts with \qc{\%}, it is
+% OK to throw away that line.
+%
+% \begin{macro}{\@percentchar}
+% \begin{macrocode}
+\begingroup \lccode`\.=`\%%
+\lowercase{\gdef\@percentchar{.}}%
+\endgroup
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\fileversiondate}
+% The function \cw{fileversiondate} is not only a useful support
+% function for \cw{inputfwh}, it can also be used by itself at the
+% beginning of a file to set file name, version, and date correctly
+% even if the file is input by some means other than
+% \cw{inputfwh}\Dash assuming that the arguments of the
+% \cw{fileversiondate} command are kept properly up to date.
+% \begin{macrocode}
+\gdef\fileversiondate#1#2#3{%
+ \xp@\xdef\csname#1\endcsname{#2 (#3)}%
+ \def\filename{#1}\def\fileversion{#2}%
+ \def\filedate{#3}%
+ \message{#1 \csname#1\endcsname}%
+}
+% \end{macrocode}
+% And now apply \cw{fileversiondate} to this file.
+% \begin{macrocode}
+%<*209>
+\fileversiondate{grabhedr.sty}{0.9j}{1994/11/08}
+%</209>
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@filehdrstart}
+% \fn{filehdr.el} by default adds a string of equal signs (with an
+% initial comment prefix) at the very top of a file header. This
+% string must be scanned away first before we can start looking for
+% the real information of the file header.
+% \begin{macrocode}
+\xdef\@filehdrstart{%
+ \@percentchar\@percentchar\@percentchar\space
+ ==================================%
+ ==================================}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@scanfileheader}
+% The purpose of this function is just to scan up to the opening
+% brace that marks the beginning of the file header body.
+% Everything before that is ignored, not needed for our present
+% purposes.
+% \begin{macrocode}
+\gdef\@scanfileheader#1@#2#{\@xscanfileheader}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@xscanfileheader}
+% Throw in some dummy values of version and date at the end so that
+% all we require from a file header is that the filename field must
+% be present.
+% \begin{macrocode}
+\long\gdef\@xscanfileheader#1{%
+ \@yscanfileheader#1{} version = "??",
+ date = "??",\@yscanfileheader}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@yscanfileheader}
+% This function assumes that filename, version, and date of a file
+% are listed in that order (but not necessarily adjacent). It's
+% possible for the version and date to be missing, or out of order,
+% but the corresponding \tex/ variables \cw{fileversion} and
+% \cw{filedate} will not get set properly unless the order is:
+% filename, [\ldots,] version, [\ldots,] date. Trying to handle
+% different orderings would be desirable but I haven't yet been
+% struck by a suitable flash of insight on how to do it without
+% grubby, time-consuming picking apart of the entire file header.
+% \begin{macrocode}
+\long\gdef\@yscanfileheader
+ #1 filename = "#2",#3 version = "#4",%
+ #5 date = "#6",#7\@yscanfileheader{%
+ \endgroup
+ \csname fileversiondate\endcsname{#2}{#4}{#6}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@readfirstheaderline}
+% This function has to look at the first line of the file to see if
+% it has the expected form for the first line of a file header.
+% \begin{macrocode}
+\begingroup
+\lccode`\$=`\^^M
+\lowercase{\gdef\@readfirstheaderline#1$}{%
+ \toks@{#1}%
+ \edef\@tempa{\@percentchar\the\toks@}%
+ \ifx\@tempa\@filehdrstart
+ \endgroup \begingroup
+ \catcode`\%=9 \catcode`\^^M=5 \catcode`\@=11
+% \end{macrocode}
+% Double quote and equals sign need to be category 12 in order for
+% the parameter matching of \cw{@xscanfileheader} to work, and
+% space needs its normal catcode of 10.
+% \begin{macrocode}
+ \catcode`\ =10 \catcode`\==12 \catcode`\"=12
+ \xp@\@scanfileheader
+ \else
+ \message{(* Missing file header? *)}%
+ \afterfi\endgroup
+ \fi}
+\endgroup
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@xinputfwh}
+% An auxiliary function.
+% \begin{macrocode}
+\gdef\@xinputfwh{%
+ \ifx\next\@readfirstheaderline
+% \end{macrocode}
+% Sanitize a few characters. Otherwise an unmatched brace or other
+% special character might cause a problem in the process of reading
+% the first line as a macro argument.
+% \begin{macrocode}
+ \catcode`\%=12 \catcode`\{=12 \catcode`\}=12
+ \catcode`\\=12 \catcode`\^^L=12
+ \catcode`\^=12
+% Unique terminator token for the first line.
+ \catcode`\^^M=3\relax
+ \else \endgroup\fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@inputfwh}
+% Auxiliary function, carries out the necessary \cw{futurelet}.
+% \begin{macrocode}
+\gdef\@inputfwh{\futurelet\next\@xinputfwh}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\inputfwh}
+% Strategy for (almost) bulletproof reading of the first line of
+% the input file is like this: Give the percent sign a special
+% catcode, then use \cw{futurelet} to freeze the catcode of the
+% first token in the input file. If the first token is {\em not\/}
+% a percent character, then fine, just close the group wherein the
+% percent character had its special catcode, and proceed with
+% normal input; the first token will have its proper catcode
+% because we did not change anything except the percent character.
+% Otherwise, we still proceed with `normal' input execution, but by
+% making \qc{\%} active and defining it suitably, we can carry out
+% further tests to see if the first file line has the expected form
+% (three percent signs plus lots of equal signs).
+% \begin{macrocode}
+\gdef\inputfwh#1{%
+ \begingroup\catcode`\%=\active
+ \endlinechar`\^^M\relax
+ \lccode`\~=`\%\relax
+ \lowercase{\let~}\@readfirstheaderline
+ \xp@\@inputfwh\@@input #1\relax
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \section{Managing catcode changes}
+%
+% A survey of other methods for saving and restoring catcodes would
+% be more work than I have time for at the moment. The method
+% given here is the best one I know (other methods use up one extra
+% control sequence name per file, or don't robustly
+% handle multiple levels of file nesting).
+%
+% \begin{macro}{\localcatcodes}
+% The \cw{localcatcodes} function changes catcodes according to the
+% character/catcode pairs given in its argument, saving the
+% previous catcode values of those characters on a stack so that
+% they can be retrieved later with \cw{restorecatcodes}. Example:
+%\begin{usage}
+%\localcatcodes{\@{11}\"\active}
+%\end{usage}
+% to change the catcode of \cs{\@} to 11 (letter) and the catcode
+% of \qc{\"} to 13 (active). In \plaintex/ you'd better be careful
+% to use \qc{\+} instead of \cs{\+} in the argument of
+% \cw{localcatcodes} because of the outerness of \cs{\+}.
+%
+% This function works by using token registers 0 and 4
+% to accumulate catcode assignment statements: in \cw{toks0} we put
+% the statements necessary to restore catcodes to their previous
+% values, while in \cw{toks 4} we put the statements necessary to
+% set catcodes to their new values.
+% \begin{macrocode}
+\gdef\localcatcodes#1{%
+ \ifx\@empty\@catcodestack
+ \gdef\@catcodestack{{}}%
+ \fi
+ \def\do##1##2{%
+ \ifnum##2>\z@
+ \catcode\number`##1 \space
+ \number\catcode`##1\relax
+ \expandafter\do\fi}%
+ \xdef\@catcodestack{{\do#1\relax\m@ne}%
+ \@catcodestack}%
+ \def\do##1##2{\catcode`##1 ##2\relax\do}%
+ \do#1\ {\catcode32\let\do}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@catcodestack}
+% Init the stack with an empty element; otherwise popping the
+% next-to-last element would wrongly remove braces from the last
+% element. But as a matter of fact we could just as well initialize
+% \cw{@catcodestack} to empty because \cw{localcatcodes} is careful
+% to add an empty final element if necessary.
+% \begin{macrocode}
+\gdef\@catcodestack{{}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\restorecatcodes}
+% The function \cw{restorecatcodes} has to pop the stack and
+% execute the popped code.
+% \begin{macrocode}
+\gdef\restorecatcodes{%
+ \begingroup
+ \ifx\@empty\@catcodestack
+ \errmessage{Can't pop catcodes;
+ \nx@\@catcodestack = empty}%
+ \endgroup
+ \else
+ \def\do##1##2\do{%
+ \gdef\@catcodestack{##2}%
+% \end{macrocode}
+% Notice the placement of \arg{1} after the \cw{endgroup}, so that
+% the catcode assignments are local assignments.
+% \begin{macrocode}
+ \endgroup##1}%
+ \xp@\do\@catcodestack\do
+ \fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \section{Trapping redundant input statements}
+% The utility \fn{listout.tex} calls \fn{menus.sty}, which calls
+% \fn{dialog.sty}, and all three of these files start by loading
+% \fn{grabhedr.sty} in order to take advantage of its functions
+% \cw{fileversiondate}, \cw{localcatcodes}, and \cw{inputfwh}. But
+% consequently, when \fn{listout.tex} is used there will be two
+% redundant attempts to load \fn{grabhedr.sty}. The straightforward
+% way to avoid the redundant input attempts would be to surround
+% them with an \cw{ifx} test:
+%
+%^^V \ifx\undefined\fileversiondate
+%^^V \input grabhedr.sty \relax
+%^^V \fileversiondate{foo.bar}{0.9e}{10-Jun-1993}
+%^^V \fi
+%
+% This method has a few drawbacks, however: (1)~the conditional
+% remains open throughout the processing of everything in
+% \fn{grabhedr.sty} and the \cw{fileversiondate} statement, which
+% makes any \cw{else} or \cw{fi} mismatch problems harder to debug;
+% (2)~if \cw{undefined} becomes accidentally defined the \cw{ifx}
+% test will fail; (3)~choosing the right control sequence to test
+% against \cw{undefined} requires a little care.
+%
+% In a situation where we know that the file to be input has had
+% \cw{fileversiondate} applied to it, if it was already input, then
+% we have a failsafe control sequence that we can test to find out
+% whether the file has already been input\Dash the name
+% of the file. Assuming a standard form for the input statement
+% (one that will work with either plain \tex/ or \latex/, and makes
+% as few assumptions as possible), we can write a function that
+% will trap input statements and execute them only if the given
+% file has not yet been loaded:
+%
+%^^V \csname trap.input\endcsname
+%^^V \input grabhedr.sty \relax
+%^^V \fileversiondate{foo.bar}{1.2}{1993-Jun-07}
+%
+% \begin{macro}{\trap.input}
+% The function \cw{trap.input} scans for an input statement in
+% canonical form and executes it if and only if the file has not yet
+% been input (more precisely, if the control sequence consisting of
+% the file name is undefined, which means that it has not had
+% \cw{fileversiondate} applied to it). The canonical form
+% that I consider to be the best is \cw{input} \meta{full file
+% name}{\tt\char32 }\cw{relax}. Having the \cw{relax} means that the
+% input statement will not try to expand beyond the end of the line
+% if \cw{endlinechar} is catcoded to 9 (ignore), as is done rather
+% frequently now by progressive \tex/ programmers. The \cw{relax}
+% would ordinarily render the space after the file name unnecessary,
+% but I prefer leaving the space in to avoid interfering with
+% redefinitions of \cw{input} to take a space-delimited argument
+% that are occasionally done to achieve other special effects (see,
+% for example, ``Organizing a large collection of stylefiles'', by
+% Angelika Binding, {\sl Cahiers GUTenberg}, num\'ero 10--11,
+% septembre 1991, p.~175.) \latex/'s argument form
+% \cw{input}\verb"{...}" cannot, unfortunately, be the
+% canonical form if \plaintex/ compatibility is required.
+% \begin{macrocode}
+\expandafter\gdef\csname trap.input\endcsname
+ \input#1 \relax{%
+ \expandafter\ifx\csname#1\endcsname\relax
+ \afterfi\inputfwh{#1}\relax
+ \fi}
+% \end{macrocode}
+% \end{macro}
+%
+% End the group that encloses this entire file, and then call
+% \cw{endinput}.
+% \begin{macrocode}
+\endgroup
+\endinput
+% \end{macrocode}
+%
+% \CheckSum{294}
+% \Finale