.aH "USER-DEFINED LIST STRUCTURES \*(BU" .VL 4\"WARNING .LI "\ \(rh" .I This appendix is intended only for users accustomed to writing formatter macros. .R .LE .P If a large document requires complex list structures, it is useful to be able to define the appearance for each list level only once, instead of having to define it at the beginning of each list. This permits consistency of style in a large document. For example, a generalized list-initialization macro might be defined in such a way that what it does depends on the list-nesting level in effect at the time the macro is called. Suppose that levels 1 through 5 of lists are to have the following appearance: .tr ~ .DS 1 1 .ML A. .LI \&~\& .ML [1] .LI \&~\& .ML \*(BU .LI \&~\& .ML a) .LI \&~\& .ML + .LI \&~\& .LC 0 .DE .tr ~~ .P The following code defines a macro (\f3.\fPaL) that always begins a new list and determines the type of list according to the current list level. To understand it, you should know that the number register .I :g is used by the \*(PM list macros to determine the current list level; it is 0 if there is no currently active list. Each call to a list-initialization macro increments .I :g, and each \&\f3.\fPLE call decrements it. .br .tr `` .Es 1 \&\f3.\fPde aL \&\'\^`" register g is used as a local temporary to save \f3:\fPg before it is changed below \&\f3.\fPnr g ``n(\f3:\fPg \&\f3.\fPif ``ng=0 \f3.\fPAL A `" give me an A. \&\f3.\fPif ``ng=1 \f3.\fPLB ``n(Li 0 1 4 `" give me a [1] \&\f3.\fPif ``ng=2 \f3.\fPBL `" give me a bullet \&\f3.\fPif ``ng=3 \f3.\fPLB ``n(Li 0 2 2 a `" give me an a) \&\f3.\fPif ``ng=4 \f3.\fPML + `" give me a + \&\f3.\|.\fP .tr `\\ .Ee .tr `` .P This macro can be used (in conjunction with \f3.\fPLI and \f3.\fPLE) instead of \&\f3.\fPAL, \f3.\fPRL, \f3.\fPBL, \f3.\fPLB, and \f3.\fPML. For example, the following input: .de aL .nr g \\n(:g .if !\\ng .AL A \" A. .if \\ng .if !\\ng-1 .LB \\n(Li 0 1 4 \" [1] .if \\ng-1 .if !\\ng-2 .BL \" bullet .if \\ng-2 if !\\ng-3 .LB \\n(Li 0 2 2 a \" a) .if \\ng-3 .ML + 3 \" + .. .Es 1 \&\f3.\fPaL \&\f3.\fPLI first line. \&\f3.\fPaL \&\f3.\fPLI second line. \&\f3.\fPLE \&\f3.\fPLI third line. \&\f3.\fPLE .Ee 1 will yield: .in +5n .aL .LI first line. .aL .LI second line. .LE .LI third line. .LE .in -5n .P There is another approach to lists that is similar to the \f3.\fPH mechanism. The list-initialization, as well as the \f3.\fPLI and the \f3.\fPLE macros are all included in a single macro. That macro (called \f3.\fPbL below) requires\p .if t .bp an argument to tell it what level of item is required; it adjusts the list level by either beginning a new list or setting the list level back to a previous value, and then issues a \f3.\fPLI macro call to produce the item: .br .Es 1 \&\f3.\fPde bL \&\f3.\fPie \e\en(\f3.\fP$ \f3.\fPnr g \e\e$1 \e" if there is an argument, that is the level \&\f3.\fPel \f3.\fPnr g \e\en(\f3:\fPg \e" if no argument, use current level \&\f3.\fPif \e\eng-\e\en(\f3:\fPg>1 \f3.\fP)D "\^\(**\(**ILLEGAL SKIPPING OF LEVEL\^" \e" increasing level by more than 1 \&\f3.\fPif \e\eng>\e\en(\f3:\fPg \e{\f3.\fPaL \e\eng-1 \e" if g > \f3:\fPg, begin new list \&\f3.\fP nr g \e\en(\f3:\fPg\e} \e" and reset g to current level (\f3.\fPaL changes g) \&\f3.\fPif \e\en(\f3:\fPg>\e\eng \f3.\fPLC \e\eng \e" if \f3:\fPg > g, prune back to correct level \&\'\^`" if \f3:\fPg = g, stay within current list \&\f3.\fPLI \e" in all cases, get out an item \&\f3.\fP\|\f3.\fP .tr `\\ .Ee .tr `` .P For \f3.\fPbL to work, the previous definition of the \f3.\fPaL macro must be changed to obtain the value of .I g from its argument, rather than from .I :g . Invoking \f3.\fPbL without arguments causes it to stay at the current list level. The \*(PM \f3.\fPLC macro (List Clear) removes list descriptions until the level is less than or equal to that of its argument. For example, the \f3.\fPH macro includes the call ``\f3.\fPLC\ \|0''. If text is to be resumed at the end of a list, insert the call ``\f3.\fPLC\ \|0'' to clear out the lists completely. The example below illustrates the relatively small amount of input needed by this approach. The input text: .Es 1 \&The quick brown fox jumped over the lazy dog's back. \&\f3.\fPbL 1 first line. \&\f3.\fPbL 2 second line. \&\f3.\fPbL 1 third line. \&\f3.\fPbL fourth line. \&\f3.\fPLC 0 fifth line. .Ee 1 yields: .de aL .nr g \\$1 '''.tm \\ng \\n(:g .if \\ng=0 .AL A \" give me an A. .if \\ng=1 .LB \\n(Li 0 1 4 \" give me a [1] .if \\ng=2 .BL \" give me a bullet .if \\ng=3 .LB \\n(Li 0 2 2 a \" give me an a) .if \\ng=4 .ML + 3 \" give me a + '''.tm \\ng \\n(:g .. .de bL .ie \\n(.$ .nr g \\$1 \"if there is an argument, that is the level .el .nr g \\n(:g \"if no argument, use current level .if \\ng-\\n(:g>1 .tm ILLEGAL SKIPPING OF LEVEL \"increasing level by more than 1 .if \\ng>\\n(:g \{.aL \\ng-1 \" begin new list . nr g \\n(:g\} .if \\n(:g>\\ng .LC \\ng \" prune back to correct level .LI \"in all cases, get out an item .. .sp .5v The quick brown fox jumped over the lazy dog's back. .bL 1 first line. .bL 2 second line. .bL 1 third line. .bL fourth line. .LC 0 fifth line. .rm aL .rm bL