summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/dialogl/menus.dtx
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2006-01-11 23:52:18 +0000
committerKarl Berry <karl@freefriends.org>2006-01-11 23:52:18 +0000
commit1f54ab95d3bb8c747b233a9ab8872888ca651196 (patch)
tree9f817b694e339e83415f09065d6fe9e1c103b59e /Master/texmf-dist/source/latex/dialogl/menus.dtx
parenta960cca89bd1f229a66abc1203bea35c288d636d (diff)
trunk/Master/texmf-dist/source/latex/dialogl
git-svn-id: svn://tug.org/texlive/trunk@222 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/dialogl/menus.dtx')
-rw-r--r--Master/texmf-dist/source/latex/dialogl/menus.dtx989
1 files changed, 989 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/dialogl/menus.dtx b/Master/texmf-dist/source/latex/dialogl/menus.dtx
new file mode 100644
index 00000000000..b0f03f5f1ec
--- /dev/null
+++ b/Master/texmf-dist/source/latex/dialogl/menus.dtx
@@ -0,0 +1,989 @@
+%%% ====================================================================
+%%% @LaTeX-style-file{
+%%% filename = "menus.sty",
+%%% version = "0.9x",
+%%% date = "1994/11/08",
+%%% time = "13:32:59 EST",
+%%% checksum = "38585 989 4295 33156",
+%%% keywords = "TeX, menus",
+%%% author = "Michael Downes",
+%%% email = "mjd@math.ams.org (Internet)",
+%%% supported = "yes",
+%%% abstract = "This file provides functions for writing
+%%% messages and menus on screen, and reading user responses. It
+%%% can be used with LaTeX as a documentstyle option, or in
+%%% other forms of TeX by a standard \input statement.",
+%%% docstring = "The checksum field above contains a CRC-16
+%%% checksum as the first value, followed by the equivalent of
+%%% the standard UNIX wc (word count) utility output of lines,
+%%% words, and characters. This is produced by Robert Solovay's
+%%% checksum utility.",
+%%% }
+%%% ====================================================================
+%
+% \iffalse
+%<*driver>
+\input{dia-driv.tex}
+%</driver>
+% \fi
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \section{Function descriptions}
+%
+%\begin{usage}
+%\fmenu\foobar{
+% <preliminary text>
+%}{
+% <menu lines>
+%}{
+% <following text>
+%}
+%\end{usage}
+% Defines \cw{foobar} as a function that puts the preliminary text,
+% the menu lines (list of choices), and the after text on screen.
+% Normal usage:
+%
+%^^V \foobar % print the menu on screen
+%^^V \readline{}\reply % read the answer
+%
+% (See the description of \cw{readline} in \fn{dialog.doc}.) In the
+% various text parts all special characters have category 12 except
+% for braces, as with \cw{mesj}. Note the recommended placement of
+% the braces: no closing brace falls at the end of a line, except
+% the very last one. Because of the special catcodes in effect when
+% reading the final three arguments, a \ctrl{M} or \qc{\%} between
+% arguments would be read as an active character or category-12
+% character respectively, instead of being ignored. But actually,
+% after some rather difficult programming, I managed to make it
+% possible to write just about anything (except brace characters)
+% between the arguments and have it be ignored, so the recommended
+% style is not mandatory. The first and last newline of each
+% argument are stripped off anyway in order to produce consistent
+% clean connections with \cw{menuprefix} etc.; see below.
+%
+% Menu functions created by \cw{fmenu} are allowed optionally to
+% have arguments, like functions created with \cw{fmesj} (from
+% \fn{dialog.sty}), so that pieces of text can be inserted at the
+% time of use. This makes it possible for several similar menus to
+% share the same menu function if there are only minor variations
+% between them.
+%
+%\begin{usage}
+%\menuprefix, \menusuffix
+%\inmenuA, \inmenuB
+%\end{usage}
+% The text \cw{menuprefix} will be added at the beginning of each
+% menu; \cw{menusuffix} will be added at the end. The text
+% \cw{inmenuA} and \cw{inmenuB} will be added between the first and
+% second, respectively second and third parts of the menu; their
+% default values produce a blank line on screen. (But
+% \cw{inmenuA} will be omitted if the first part is empty, and
+% \cw{inmenuB} will be omitted if the last part is empty.) To change
+% any of these texts, use \cw{storemesj} or \cw{storexmesj}. For
+% example:
+%
+%^^V\storemesj\menuprefix{********* MENU **********}
+%
+%\begin{usage}
+%\menuprompt
+%\end{usage}
+% Furthermore, the function \cw{menuprompt} is called at the very
+% end of the menu, so that for example a standard prompt such as
+% \verb'Enter a number:' could be applied at the end of all menus,
+% if desired. To change \cw{menuprompt}, use \cw{fmesj} or
+% \cw{fxmesj}.
+%
+%\begin{usage}
+%\menuline, \endmenuline
+%\menutopline, \menubotline
+%\end{usage}
+% Each line in the middle argument of \cw{fmenu} (the list of
+% choices) is embedded in a statement
+% \cw{menuline}\verbdots\cw{endmenuline}. The default definition of
+% \cw{menuline} is to add two spaces at the beginning and a newline
+% at the end. Lines in the top or bottom part of the menu are
+% embedded in \cw{menutopline}\verbdots\cw{endmenuline} or
+% \cw{menubotline}\verbdots\cw{endmenuline} respectively. (Notice
+% that all three share the same ending delimiter; if different
+% actions are wanted at the end of a top or bottom line as opposed
+% to a middle menu line, they must be obtained by defining
+% \cw{menutopline} or \cw{menubotline} to read the entire line as
+% an argument and perform the desired processing.)
+%
+% An enclosing box for a menu can be obtained by
+% defining \cw{menuline} and its relatives appropriately and using
+% \cw{fxmenu} (see below).
+%
+%\begin{usage}
+%\fxmenu\foobar{
+% <preliminary text>
+%}{
+% <menu lines>
+%}{
+% <following text>
+%}
+%\end{usage}
+% Similar to \cw{fmenu} but with full expansion in each part of the
+% text, as with \cw{xmesj}.
+%
+% To get an enclosing box for a menu, write \cs{\.} at the end of
+% each menu line (to protect the preceding spaces from \tex/'s
+% propensity to remove character 32 at the end of a line,
+% regardless of its catcode), and then make sure that \cw{menuline}
+% and \cw{endmenuline} put in the appropriate box-drawing
+% characters on either side. I.e.:
+%
+%^^V \fxmenu\foobar{
+%^^V First line \.
+%^^V Second line \.
+%^^V }{
+%^^V Third line \.
+%^^V ...
+%^^V }{
+%^^V Last line \.
+%^^V }
+%
+% With the \verb'/o' option of em\tex/, you can use the box-drawing
+% characters in the standard PC DOS character set.
+%
+%\begin{usage}
+%\nmenu\Alph\foobar#1{
+% <preliminary text>
+%}{
+% <menu lines>
+%}{
+% <following text>
+%}
+%\end{usage}
+% \cw{nmenu} and \cw{nxmenu} are like \cw{fmenu}, \cw{fxmenu}
+% except that they automatically number each line of the middle
+% part of the menu. (This allows menu choices to be added or deleted
+% without tedious renumbering.) The first argument indicates the
+% type of numbers to be used: \cw{alph}, \cw{Alph}, \cw{arabic},
+% \cw{roman}, \cw{Roman} (following \latex/). {\em These are not yet
+% implemented.}
+%^^A [15-May-1993,mjd]
+%
+% The function \cw{menunumber} (taking one argument) is applied to
+% each automatically generated number. The default value is to add
+% brackets and a space after:
+%
+%^^V \def\menunumber#1{[#1] }
+%
+% but by redefining \cw{menunumber} you can add parentheses or extra
+% spaces or what have you around each number. Internally a line of
+% an autonumbered menu is stored as
+%
+%^^V \menuline\menunumber{5}Text text ...\endmenuline
+%
+%\begin{usage}
+%\optionexec\answer
+%\end{usage}
+% This is a companion function for \cw{readChar} and the menu
+% functions: it checks to see if the answer is equal to any one of
+% the characters \qc{\?} \qc{\Q} \qc{\q} \qc{\X} \qc{\x}, and if so
+% executes \cw{moption?} or \cw{moptionQ} or \cw{moptionX}
+% respectively, otherwise executes
+%
+%^^V \csname moption\curmenu C\endcsname
+%
+% where \qc{\C} means the character that was read and \cw{curmenu} is
+% a string identifying the current location in the menu system.
+% (\cw{optionexec} pushes and pops \cw{curmenu} when going between
+% menus, to keep it up to date.) If this control sequence is
+% undefined, \cw{optionexec} gives a generic ``Sorry, I don't
+% understand'' message and repeats the current menu.
+%
+% Thus the major work involved in making a menu system is to define
+% the menu screens using \cw{fmenu}, \cw{fxmenu}, and then define
+% corresponding functions \cw{moptionXXX} that display one of the
+% menu screens, read a menu choice, and call \cw{optionexec} to
+% branch to the next action.
+%
+%\begin{usage}
+%\specialhelp\answer{Substitute message}
+%\end{usage}
+% As it turns out, it is sometimes desirable to substitute some
+% other message in place of the generic ``Sorry, I don't
+% understand'' message given by \cw{optionexec}. For instance,
+% suppose a given menu choice leads to a secondary prompt where you
+% ask the user to enter a number of columns for printing some data.
+% If the user accidentally mistypes \verb'0', it would be better to
+% respond with something like
+%
+%^^V Number of columns must be greater than 0.
+%
+% than with the generic message. The function \cw{specialhelp}
+% allows you to do this. The first argument is the name of the
+% macro that will be passed to \cw{optionexec}. \cw{specialhelp}
+% modifies that macro to a flag value that will trigger the
+% substitute message. (But does it carefully, so that you can still
+% use the macro naturally in the substitute message text.)
+%
+%\begin{usage}
+%\optionfileexec\answer
+%\end{usage}
+% Like \cw{optionexec}, but gets the next menu from a file instead
+% of from main memory, if applicable. This is not yet
+% implemented.
+%^^A [mjd,24-May-1993]
+% The technical complications involved in managing the menu files
+% are many\Dash for example: How do you prevent the usual file name
+% message of \tex/ from intruding on your carefully designed menu
+% screens, if \cw{input} is used to read the next menu file?
+% Alternatively if you try to use \cw{read} to read the next menu
+% file, how do you deal with catcode changes?
+%
+%\begin{usage}
+%\lettermenu{MN}
+%\end{usage}
+% This is an abbreviation for
+%
+%^^V \menuMN \readChar{Q}\reply \optionexec\reply
+%
+% It calls the menu function associated with the menu name \verb"MN",
+% reads a single uppercase letter into \cw{reply}, and then calls
+% \cw{optionexec} to branch to the case selected by the reply.
+%
+%\begin{usage}
+%\if\xoptiontest\answer ... \else ... \fi
+%\end{usage}
+% The function \cw{xoptiontest} is for use with \cw{readline} or
+% \cw{xreadline}, to trap the special responses \verb'? Q q X x'
+% before executing some conditional code. It returns a `true' value
+% suitable for \cw{if} testing, if and only if the replacement text
+% of \cw{answer} is a single character matching one of those
+% listed. This is used when you are prompting for a response that
+% can be an arbitrary string of characters, but you want to allow
+% the user still to get help or quit with the same one-character
+% responses that are recognized in other situations.
+%
+% \StopEventually{}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \section{Implementation}
+% Standard package identification:
+% \begin{macrocode}
+%<*2e>
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage{menus}[1994/11/08 v0.9x]
+% \end{macrocode}
+% Load the dialog package if necessary.
+% \begin{macrocode}
+\RequirePackage{dialog}
+%</2e>
+% \end{macrocode}
+%
+% This file requires \fn{grabhedr.sty} and \fn{dialog.sty}. If
+% \fn{grabhedr.sty} is not already loaded, load it now and call
+% \cw{fileversiondate}, since it's too late to apply \cw{inputfwh}
+% to {\em this\/} file. See the documentation of \cw{trap.input} in
+% \fn{grabhedr.doc}.
+% \begin{macrocode}
+%<*209>
+\csname trap.input\endcsname
+\input grabhedr.sty \relax
+\fileversiondate{menus.sty}{0.9x}{1994/11/08}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\inputfwh{dialog.sty}
+%</209>
+% \end{macrocode}
+%
+%\section{Definitions}
+%
+% We start by using the \cw{localcatcodes} function from
+% \fn{grabhedr.sty} to save current catcodes and set new catcodes
+% for certain significant characters, as explained at more length
+% in \fn{dialog.doc}.
+%
+% \begin{macrocode}
+\localcatcodes{\@{11}%
+ \~{13}\"{12}\#{6}\^{7}\`{12}\${3}\:{12}}
+% \end{macrocode}
+%
+%\begin{macro}{\menuprefix}
+% \cw{menuprefix} is a string added at the beginning of each menu to
+% pretty it up a little (or uglify it a little, depending on your
+% taste). The length of the default string is 70 characters, not
+% counting the two newline characters. By using \cw{storexmesj} we
+% get embedded newlines corresponding to the ones seen here. [That
+% is, except for the extra line break (where the newline character is
+% commented out), needed to make this fit in the current column
+% width.]
+%
+%\iftrue
+%^^V \storexmesj\menuprefix{
+%^^V ===================================%
+%^^V ===================================
+%^^V }
+%
+%\else
+% \begin{macrocode}
+\storexmesj\menuprefix{
+======================================================================
+}
+% \end{macrocode}
+%\fi
+% \end{macro}
+%
+% \begin{macro}{\menusuffix}
+% The default value for \cw{menusuffix} is the same as for
+% \cw{menuprefix}.
+% \begin{macrocode}
+\let\menusuffix=\menuprefix
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\inmenuA}
+% \begin{macro}{\inmenuB}
+% The default for \cw{inmenuA} and \cw{inmenuB} is a single
+% newline, which will produce a blank line on screen because they
+% will occur after an \cw{endmenuline}, which also
+% contains a newline.
+% \begin{macrocode}
+\storemesj\inmenuA{
+}
+\storemesj\inmenuB{
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+%\begin{macro}{\menuline}
+% The default value for \cw{menuline} is two spaces. This means
+% that each line in the middle section of a menu defined by
+% \cw{fmenu} or \cw{fxmenu} will be indented two spaces.
+% \begin{macrocode}
+\storemesj\menuline{ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\menutopline}
+% \begin{macro}{\menubotline}
+% By default, no spaces are added at the beginning of a line in the
+% top or bottom section of a menu:
+% \begin{macrocode}
+\def\menutopline{}
+\def\menubotline{}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\endmenuline}
+% \cw{endmenuline} is just a newline.
+% \begin{macrocode}
+\storemesj\endmenuline{
+}%
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\menunumber}
+% This definition of \cw{menunumber} adds square brackets and a
+% following space around each item number.
+% \begin{macrocode}
+\def\menunumber#1{[#1] }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\menuprompt}
+% This definition of \cw{menuprompt} is suitable for the purposes
+% of \fn{listout.tex} but will probably need to be no-op'd or
+% changed for other applications.
+% \begin{macrocode}
+\def\menuprompt{\promptmesj{Your choice? }}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\menufirstpart}
+% \begin{macro}{\menuchoices}
+% \begin{macro}{\menulastpart}
+% Each of the three pieces of a menu gets its own token register.
+% \begin{macrocode}
+\newtoks\menufirstpart
+\newtoks\menuchoices
+\newtoks\menulastpart
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\fmenu}
+%
+% The `arguments' of \cw{fmenu} are \arg{1} menu name, \arg{2}
+% optional argument specifiers, \arg{3} preliminary text, \arg{4}
+% list of menu choices, \arg{5} following text. But at first we read
+% only the first two because we want to change some catcodes before
+% reading the others. The auxiliary function \cw{fxmenub} is shared
+% with \cw{fxmenu}.
+%
+% Because of the catcode changes done by \cw{mesjsetup}, newlines,
+% spaces, or percent signs between the three final arguments will
+% not be ignored. To get around this, we use the peculiar
+% \verb'#{' feature of \tex/, in intermediate scratch functions
+% called \cw{@tempa}, to read and discard anything that may occur
+% between one closing brace and the next opening brace. Token
+% register assignments are used to read the arguments proper.
+%
+% \begin{macrocode}
+\def\fmenu#1#2#{\mesjsetup
+ \catcode`\#=6 % for parameters
+ \toks@{\fxmenub{\gdef}{\begingroup}{}#1{#2}}%
+ \def\@tempa##1##{%
+ \def\@tempa####1####{%
+ \def\@tempa{\the\toks@}%
+ \afterassignment\@tempa \menulastpart}%
+ \afterassignment\@tempa \menuchoices}%
+ \afterassignment\@tempa \menufirstpart
+}
+% \end{macrocode}
+% \end{macro}
+%
+% Before proceeding to define \cw{fxmenub}, we must deal with a
+% subproblem. What we will have to work with is three pieces of text
+% in the token registers \cw{menufirstpart}, \cw{menuchoices}, and
+% \cw{menulastpart}, containing active \ctrl{M} characters to mark
+% line breaks, including possibly but not necessarily \ctrl{M} at the
+% beginning and at the end of each piece. What we would like to do,
+% for each piece, is to remove the first \ctrl{M}, if there is one,
+% and the last one, if there is one. The function \cw{stripcontrolMs}
+% does this.
+%
+% If you are one of those rare \tex/ hackers who might actually
+% want to understand the workings of \cw{stripcontrolMs}, the best
+% way is probably to watch it in action with \cw{tracingmacros} =
+% \cw{tracingcommands} = 2, rather than attempt to follow my labored
+% commentary below.
+% \begin{macrocode}
+\begingroup % localize \lccode change
+\lccode`\~=`\^^M
+% \end{macrocode}
+% The functions \cw{stripM}, \cw{stripMa}, \cw{stripMb}, \ldots\ are
+% auxiliary functions for \cw{stripcontrolMs}. They all carry along
+% an extra last argument, the name of the token register originally
+% given to \cw{stripcontrolMs}, so that when we finally reach
+% \cw{stripMd} we can carry out the assignment of the token
+% register.
+%
+% When \cw{stripM} is called, it should be called like this:
+%\begin{verbatim}
+% \expandafter\stripM\expandafter$\the\sometoks
+% $^^M$$\stripM\sometoks
+%\end{verbatim}
+% That is, \qc{\$} should be added at the beginning and \verb'$^^M$$'
+% at the end of the text to be processed. And \cw{expandafter}'s
+% should be added to pre-expand the token register.
+%
+% These examples illustrate the possible contents of (e.g.\@)
+% \cw{menufirstpart}, before processing
+%\begin{enumerate}\renewcommand{\theenumi}{\alph{enumi}}
+%\renewcommand{\labelenumi}{(\theenumi)}
+% \item \label{mmm}
+% \verb'^^Maaa^^Mbbb^^M'
+% \item \verb'aaa^^Mbbb'
+% \item \verb'^^Maaa^^Mbbb'
+% \item \verb'aaa^^Mbbb^^M'
+%\end{enumerate}
+% The processing of example (\ref{mmm}) would proceed as follows.
+% Call \cw{stripM}, adding \qc{\$} at the beginning and \verb'$^^M$$'
+% at the end.
+%\begin{verbatim}
+% \stripM $^^Maaa^^Mbbb^^M$^^M$$\stripM
+%\end{verbatim}
+% This finds a match with the \verb'$^^M' at the beginning. The
+% remaining text is passed on to \cw{stripMb}. We know that there is
+% now an extra \verb'$^^M$$' at the end, but we don't know if the
+% first \qc{\$} is preceded by \ctrl{M}.
+%\begin{verbatim}
+% \stripMb aaa^^Mbbb^^M$^^M$$\stripMb
+%\end{verbatim}
+% If it turns out that \arg{2} = \qc{\$}, then there was {\em not\/}
+% a \ctrl{M} at the end of the original text, and we need to strip
+% off a last remaining \qc{\$} sign. Otherwise we are finished if we
+% just discard \arg{2} and \arg{3} (the remaining \ctrl{M} and
+% \qc{\$} characters of the ones that we added).
+%
+% We use \qc{\$} as a marker since any \qc{\$} characters that
+% happen to occur in the menu text will have category 12 and thus
+% not match the category-3 \qc{\$} used in the definition of
+% \cw{stripMa} etc. A control sequence could also be used as a
+% marker if we took care to give it a bizarre name that would never
+% arise in the menu text (\cw{fxmenub} is used not just by
+% \cw{fmenu} but also by \cw{fxmenu}, which might have arbitrary
+% control sequences in its arguments); but that means using up one
+% more hash table entry and additional string pool.
+%
+% \begin{macro}{\stripM}
+% \begin{macrocode}
+\lowercase{%
+\long\gdef\stripM#1$~#2#3\stripM#4{%
+ \ifx$#2%
+ \stripMa#1\stripMa#4%
+ \else
+ \stripMb#2#3\stripMb#4%
+ \fi
+}
+}% end lowercase
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\stripMa}
+% \begin{macrocode}
+\lowercase{%
+\long\gdef\stripMa $#1\stripMa#2{%
+ \stripMb#1$~$$\stripMb#2}
+}% end lowercase
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\stripMb}
+% \begin{macrocode}
+\lowercase{%
+\long\gdef\stripMb#1~$#2#3\stripMb#4{%
+ \ifx$#2%
+ \stripMc#1\stripMc#4%
+ \else
+ \stripMd#1\stripMd#4%
+ \fi
+}
+}% end lowercase
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\stripMc}
+% \begin{macrocode}
+\long\gdef\stripMc#1$#2\stripMc#3{%
+ \stripMd#1\stripMd#3}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\stripMd}
+% \begin{macrocode}
+\long\gdef\stripMd#1\stripMd#2{#2{#1}}
+\endgroup
+% \end{macrocode}
+% \end{macro}
+%
+% Some tests.
+%\begin{verbatim}
+% %\lowercase{\def\test#1{\stripM $#1$~$$\stripM}
+% %\tracingmacros=2 \tracingcommands=2 \tracingonline=1
+% %\test{~aaa~bbb~}
+% %\test{aaa~bbb}
+% %\test{~aaa~bbb}
+% %\test{aaa~bbb~}
+% %\tracingmacros=0 \tracingcommands=0 \tracingonline=0
+% %}% end lowercase
+%\end{verbatim}
+%
+% \begin{macro}{\stripcontrolMs}
+% The argument of \cw{stripcontrolMs} is a token register. The text
+% of the token register will be stripped of a leading and trailing
+% \ctrl{M} if either or both are present, and the remainder text will
+% be left in the token register.
+%
+% \begin{macrocode}
+\begingroup \lccode`\~=`\^^M
+\lowercase{%
+\gdef\stripcontrolMs#1{\xp@\stripM
+ \xp@$\the#1$~$$\stripM#1}
+}% end lowercase
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\addmenulines}
+% \begin{macrocode}
+\lowercase{%
+\gdef\addmenulines#1#2#3{%
+% \end{macrocode}
+% Add \arg{2} at the beginning and \arg{3} at the end of every line
+% of token register \arg{1}.
+% \begin{macrocode}
+ \def ~##1~##2{%
+ #1\xp@{\the#1#2##1#3}%
+ \ifx\end##2\xp@\@gobbletwo\fi~##2}%
+ \edef\@tempa{\nx@~\the#1\nx@~}#1{}%
+ \@tempa\end}
+}% end lowercase
+\endgroup % restore lccode of ~
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\fxmenub}
+%
+% The function \cw{fxmenub} is the one that does most of the hard
+% work for \cw{fmenu} and \cw{fxmenu}. Argument \arg{4} is the name
+% of the menu, \arg{5} is the argument specifiers (maybe empty).
+% Arguments \arg{1}\arg{2}\arg{3} are assignment type, extra setup,
+% and expansion control; specifically, these arguments are
+% \cw{gdef} \cw{begingroup} \cw{empty} for \cw{fmenu} or \cw{xdef}
+% \cw{xmesjsetup} and an extra \cw{noexpand} for \cw{fxmenu}.
+%
+% That this function actually works should probably be regarded as
+% a miracle rather than a result of my programming efforts.^^A
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \footnote{Let's see, three miracles is a prerequisite for sainthood
+% in the Catholic church\Dash only two more needed for Don
+% Knuth to be a candidate \dots}
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \begin{macrocode}
+\def\fxmenub#1#2#3#4#5{%
+ \stripcontrolMs\menufirstpart
+ \stripcontrolMs\menulastpart
+ \stripcontrolMs\menuchoices
+ \addmenulines\menuchoices\menuline\endmenuline
+ \actively\let\^^M\relax % needed for \xdef
+% \end{macrocode}
+% Define \arg{4}. Expansion control is rather tricky because of the
+% possibility of parameter markers inside \cw{menufirstpart},
+% \cw{menuchoices} or \cw{menulastpart}.
+% \begin{macrocode}
+ \toks@{\long#1#4#5}% e.g. \xdef\foo##1##2
+% \end{macrocode}
+% If \cw{menufirstpart} is empty, we don't add the separator
+% material \cw{inmenuA}.
+% \begin{macrocode}
+ \edef\@tempa{\the\menufirstpart}%
+ \ifx\@tempa\@empty
+ \let\nxa@\@gobble
+ \else
+ \addmenulines\menufirstpart
+ \menutopline\endmenuline
+ \let\nxa@\nx@
+ \fi
+% \end{macrocode}
+% If \cw{menulastpart} is empty, we don't add the separator
+% material \cw{inmenuB}.
+% \begin{macrocode}
+ \edef\@tempa{\the\menulastpart}%
+ \ifx\@tempa\@empty
+ \let\nxb@\@gobble
+ \else
+ \addmenulines\menulastpart
+ \menubotline\endmenuline
+ \let\nxb@\nx@
+ \fi
+% \end{macrocode}
+% Set up the definition statement that will create the new menu.
+% \arg{2} = \cw{begingroup} or \cw{xmesjsetup}.
+% \begin{macrocode}
+\edef\@tempa{{#3\nx@#3#2%
+ \def#3\nx@#3\mesjtext{%
+ #3\nx@#3\menuprefix
+ \the\menufirstpart #3\nxa@#3\inmenuA
+ \the\menuchoices #3\nxb@#3\inmenuB
+ \the\menulastpart #3\nx@#3\menusuffix}%
+ #3\nx@#3\sendmesj
+ #3\nx@#3\menuprompt}}%
+ \toks2 \xp@{\@tempa}%
+ \edef\@tempa{\the\toks@\the\toks2 }%
+% \end{macrocode}
+% Temporarily \cw{relax}ify \cw{menuline} etc. in order to prevent
+% their premature expansion if \cw{xdef} is applied.
+% \begin{macrocode}
+ \let\menutopline\relax \let\menuline\relax
+ \let\menubotline\relax \let\endmenuline\relax
+ \let\menunumber\relax
+ \@tempa % finally, execute the \gdef or \xdef
+ \endgroup % matches \mesjsetup done by \fxmenu
+}% end \fxmenub
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\fxmenu}
+%
+% Expanding analog of \cw{fmenu}.
+% \begin{macrocode}
+\def\fxmenu#1#2#{\xmesjsetup
+ \toks@{\fxmenub{\xdef}{\xmesjsetup}\nx@#1{#2}}%
+ \def\@tempa##1##{%
+ \def\@tempa####1####{%
+ \def\@tempa{\the\toks@}%
+ \afterassignment\@tempa \menulastpart}%
+ \afterassignment\@tempa \menuchoices}%
+ \afterassignment\@tempa \menufirstpart
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\notyet}
+%
+% \begin{macrocode}
+\def\notyet#1{%
+ \errmessage{Not yet implemented: \string#1}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\nmenu}
+% \begin{macro}{\nxmenu}
+% These two functions aren't implemented yet.
+%^^A [mjd,24-May-1993]
+% \begin{macrocode}
+\long\def\nmenu#1#2#3#4#5{\notyet\nmenu}
+\long\def\nxmenu#1#2#3#4#5{\notyet\nxmenu}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \section{Menu traversal functions}
+%
+% For reliable travel up and down the menu tree, we need to push
+% and pop the value of \cw{curmenu} as we go along. Among other
+% things, \cw{curmenu} is used to repeat the current menu after a
+% help message.
+%
+% \begin{macro}{\optionstack}
+% \begin{macrocode}
+\newtoks\optionstack
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\curmenu}
+% \begin{macrocode}
+\let\curmenu\@empty
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\estart}
+% Start of a stack element.
+% \begin{macrocode}
+\let\estart\relax
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\eend}
+% End of a stack element.
+% \begin{macrocode}
+\let\eend\relax
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\pushoptions}
+% \begin{macrocode}
+\def\pushoptions#1{%
+ \edef\pushtemp{\estart
+ \def\nx@\curmenu{\curmenu}%
+ \eend
+ \the\optionstack}%
+ \global\optionstack\xp@{\pushtemp}%
+ \edef\curmenu{\curmenu#1}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\popoptions}
+% \begin{macrocode}
+\def\popoptions{%
+ \edef\@tempa{\the\optionstack}%
+ \ifx\@empty\@tempa
+ \errmessage{Can't pop empty stack
+ (\string\optionstack)}%
+ \else
+ \def\estart##1\eend##2\@nil{%
+ \global\optionstack{##2}%
+ \let\estart\relax##1}%
+ \the\optionstack\@nil
+ \fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\moptionX}
+%
+% The \qc{\X} option is a total exit from the menu maze, as
+% compared to \cw{moptionQ}, which returns you to the previous menu
+% level.
+%
+% \begin{macrocode}
+\fmesj\moptionX{Exiting . . .}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\repeatoption}
+% \begin{macrocode}
+\def\repeatoption{%
+ \csname moption\curmenu\endcsname}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\moptionQ}
+% \begin{macrocode}
+\def\moptionQ{\popoptions \repeatoption}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\badoptionmesj}
+% The sole reason for using \cw{fxmesj} rather than \cw{fmesj} here
+% is to use \qc{\%} to comment out the initial newline, as the line
+% break was needed only for convenient printing of this
+% documentation within a narrow column width.
+% \begin{macrocode}
+\fxmesj\badoptionmesj#1{%
+?---I don't understand "#1".}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\optionexec}
+%
+% The function \cw{optionexec} takes one argument, which it uses
+% together with \cw{curmenu} to determine the next action. The
+% argument is expected to be a macro containing a single letter,
+% the most recent menu choice received from the user.
+%
+% Common options such as \qc{\?}, \qc{\Q}, or \qc{\X} that may
+% occur at any level of the menu system are handled specially, to
+% cut down on the number of control sequence names needed for a
+% csname implementation of the menus.
+% \begin{macrocode}
+\def\optionexec#1{%
+ \if ?#1\relax \let\@tempa\moptionhelp
+ \else \if Q#1\relax
+ \ifx\curmenu\@empty \let\@tempa\moptionX
+ \else \let\@tempa\moptionQ \fi
+ \else \if X#1\relax \let\@tempa\moptionX
+ \else
+% \end{macrocode}
+% Because special characters, including backslash, are deactivated
+% by \cw{readChar}, we can apply \cw{csname} without fearing problems
+% from responses such as \cw{relax}.
+% \begin{macrocode}
+ \xp@\let\xp@\@tempa
+ \csname moption\curmenu#1\endcsname
+ \ifx\@tempa\relax
+ \badoptionmesj{#1}\let\@tempa\repeatoption
+ \else
+ \pushoptions{#1}%
+ \fi
+ \fi\fi\fi
+% \end{macrocode}
+% We save up the next action in \cw{@tempa} and execute it last, to
+% get tail recursion.
+% \begin{macrocode}
+ \@tempa
+}
+% \end{macrocode}
+% \end{macro}
+%
+% Really big menu systems could get around \tex/ memory limits by
+% storing individual menus or groups of menus in separate files and
+% using \cw{optionfileexec} in place of \cw{optionexec} to
+% retrieve the menu text from disk storage instead of from main
+% memory. However there are a number of technical complications and
+% I probably won't get around to working on them in the near future.
+%^^A [mjd,24-May-1993]
+%
+% \begin{macro}{\optionfileexec}
+% \begin{macrocode}
+\def\optionfileexec#1{\notyet\optionfileexec}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\xoptiontest}
+% The function \cw{xoptiontest} must return true if and only if the
+% macro \arg{1} consists entirely of one of the one-letter
+% responses \verb"? Q q X x" that correspond to special menu
+% actions. The rather cautious implementation with \cw{aftergroup}
+% avoids rescanning the contents of \verb"#1", just in case it
+% contains anything that's \cw{outer}.
+% \begin{macrocode}
+\def\xoptiontest#1{TT\fi
+ \begingroup \def\0{?}\def\1{Q}%
+ \def\2{q}\def\3{x}\def\4{X}%
+ \aftergroup\if\aftergroup T%
+ \ifx\0#1\aftergroup T%
+ \else\ifx\1#1\aftergroup T%
+ \else\ifx\2#1\aftergroup T%
+ \else\ifx\3#1\aftergroup T%
+ \else\ifx\4#1\aftergroup T%
+ \else \aftergroup F%
+ \fi\fi\fi\fi\fi
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\menuhelpmesj}
+%
+% Default help message, can be redefined if necessary. The extra
+% newlines commented out with \qc{\%} are here only for convenient
+% printing within a narrow column width.
+%
+% \begin{macrocode}
+\fxmesj\menuhelpmesj{&\menuprefix%
+A response of Q will usually send you back to %
+the previous menu.
+A response of X will get you entirely out of %
+the menu system.
+&\menusuffix%
+Press the <Return> key ( Enter ) to continue:
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\moptionhelp}
+% \begin{macrocode}
+\def\moptionhelp{%
+ \menuhelpmesj \readline{}\reply \repeatoption}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\moptionhelp}
+% \cw{moptionhelp} is the branch that will be taken if the user
+% enters a question mark in response to a menu.
+% \begin{macrocode}
+\def\moptionhelp{%
+ \menuhelpmesj \readline{}\reply \repeatoption}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\moption?}
+% \begin{macrocode}
+\xp@\def\csname moption?\endcsname{%
+ \moptionhelp}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\specialhelp}
+% The function \cw{specialhelp} can be used to provide a one-time
+% alternate help message tailored to a specifc response given by
+% the user. It defines the first argument (the macro containing the
+% response) to contain \qc{\?}, then redefines \cw{menuhelpmesj} to
+% use the message text given in arg \arg{2}.
+% \begin{macrocode}
+\def\specialhelp#1#2{%
+ \let\specialhelpreply=#1\def#1{?}\begingroup
+ \def\menuhelpmesj{\let#1\specialhelpreply
+ \promptxmesj{#2\
+Press <return> to continue:}\endgroup}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\specialhelpreply}
+% Init.
+% \begin{macrocode}
+\def\specialhelpreply{}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lettermenu}
+% This is a convenient abbreviation for an often-used combination.
+% \begin{macrocode}
+\def\lettermenu#1{%
+ \csname menu#1\endcsname
+ \readChar{Q}\reply \optionexec\reply
+}
+% \end{macrocode}
+% \end{macro}
+%
+% Restore any catcodes changed locally, and depart.
+% \begin{macrocode}
+\restorecatcodes
+\endinput
+% \end{macrocode}
+%
+% \CheckSum{513}
+% \Finale