SysIII/usr/src/man/docs/mm_man/s21appa

.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