summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/dialogl/menus.dtx
blob: b0f03f5f1ec283b2752c3f0ac7bca7d73d0a613e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
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