source: trunk/third/nmh/man/mh-format.man @ 12455

Revision 12455, 17.4 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12454, which included commits to RCS files with non-trunk default branches.
Line 
1.\"
2.\" %nmhwarning%
3.\" $Id: mh-format.man,v 1.1.1.1 1999-02-07 18:14:20 danw Exp $
4.\"
5.\" include the -mh macro file
6.so %etcdir%/tmac.h
7.\"
8.TH MH-FORMAT %manext5% MH.6.8 [%nmhversion%]
9.SH NAME
10mh-format \- format file for nmh message system
11.SH SYNOPSIS
12.in +.5i
13.ti -.5i
14some \fInmh\fR commands
15.in -.5i
16.SH DESCRIPTION
17Several \fInmh\fR commands utilize either a \fIformat\fR string or a
18\fIformat\fR file during their execution.  For example, \fIscan\fR\0(1)
19uses a format string which directs it how to generate the scan listing
20for each message; \fIrepl\fR\0(1) uses a format file which directs it
21how to generate the reply to a message, and so on.
22
23Format strings are designed to be efficiently parsed by \fInmh\fR
24which means they are not necessarily simple to write and understand.
25This means that novice, casual, or even advanced users of \fInmh\fR
26should not have to deal with them.
27
28There are a few alternate scan listing formats available
29in %etcdir%/scan.time, %etcdir%/scan.size, and %etcdir%/scan.timely.
30Look in %etcdir% for other \fIscan\fR and \fIrepl\fR format files which
31may have been written at your site.
32
33It suffices to have your local \fInmh\fR expert actually write new format
34commands or modify existing ones.  This manual section explains how to
35do that.  Note: familiarity with the C \fIprintf\fR routine is assumed.
36
37A format string consists of ordinary text, and special multi-character
38\fIescape\fR sequences which begin with `%'.  When specifying a format
39string, the usual C backslash characters are honored: `\\b', `\\f',
40`\\n', `\\r', and `\\t'.  Continuation lines in format files end with
41`\\' followed by the newline character.
42
43.\" TALK ABOUT SYNTAX FIRST, THEN SEMANTICS
44There are three types of \fIescape\fR sequences: header
45\fIcomponents\fR, built-in \fIfunctions\fR, and flow \fIcontrol\fR.
46
47A \fIcomponent\fR escape is specified as `%{\fIcomponent\fR\^}', and
48exists for each header found in the message being processed.  For example
49`%{date}' refers to the \*(lqDate:\*(rq field of the appropriate message.
50All component escapes have a string value.  Normally, component values are
51compressed by converting any control characters (tab and newline included)
52to spaces, then eliding any leading or multiple spaces.  However, commands
53may give different interpretations to some component escapes; be sure
54to refer to each command's manual entry for complete details.
55
56A \fIfunction\fR escape is specified as `%(\fIfunction\fR\^)'.
57All functions are built-in, and most have a string or numeric value.
58
59.ne 12
60.Uh "Control-flow escapes"
61A \fIcontrol\fR escape is one of: `%<', `%?', `%|', or `%>'.
62These are combined into the conditional execution construct:
63.sp
64.nf
65        %<condition
66                \fIformat text 1\fP
67        %?condition2
68                \fIformat text 2\fP
69        %?condition3
70                \fIformat text 3\fP
71        \.\.\.
72        %|
73                \fIformat text N\fP
74        %>
75.fi
76.sp
77Extra white space is shown here only for clarity.  These
78constructs may be nested without ambiguity.  They form a general
79\fBif\-elseif\-else\-endif\fP block where only one of the \fIformat
80text\fP segments is interpreted.
81
82The `%<' and `%?' control escapes causes a condition to be evaluated. 
83This condition
84may be either a \fIcomponent\fP or a \fIfunction\fP.
85The four constructs have the following syntax:
86.sp 1
87.nf
88        %<{component}
89        %<(function)
90        %?{component}
91        %?(function)
92.fi
93.sp
94These control escapes test whether the function or component value is
95non-zero (for integer-valued escapes), or non-empty (for string-valued
96escapes).
97
98If this test evaulates true, then the format text up to the next
99corresponding control escape (one of `%|', `%?', or `%>') is interpreted
100normally.  Next, all format text (if any) up to the corresponding `%>'
101control escape is skipped.  The `%>' control escape is not interpreted;
102normal interpretation resumes after the `%>' escape.
103
104If the test evaluates false, however, then the format text up to
105the next corresponding control escape (again, one of `%|', `%?', or
106`%>') is skipped, instead of being interpreted.  If the control escape
107encountered was `%?', then the condition associated with that control
108escape is evaluated, and interpretation proceeds after that test as
109described in the previous paragraph.  If the control escape encountered
110was `%|', then the format text up to the corresponding `%>' escape is
111interpreted normally.  As above, the `%>' escape is not interpreted and
112normal interpretation resumes after the `%>' escape.
113
114The `%?' control escape and its following format text is optional, and may
115be included zero or more times.  The `%|' control escape and its following
116format text is also optional, and may be included zero or one times.
117
118.Uh "Function escapes"
119.ne 10
120Most functions expect an argument of a particular type:
121.sp 1
122.nf
123.ta +\w'Argument 'u +\w'An optional component, 'u
124\fIArgument\fR  \fIDescription\fR       \fIExample Syntax\fR
125literal A literal number,       %(\fIfunc\fR 1234)
126        or string       %(\fIfunc\fR text string)
127comp    Any header component    %(\fIfunc\fR\^{\fIin-reply-to\fR\^})
128date    A date component        %(\fIfunc\fR\^{\fIdate\fR\^})
129addr    An address component    %(\fIfunc\fR\^{\fIfrom\fR\^})
130expr    An optional component,  %(\fIfunc\fR\^(\fIfunc2\fR\^))
131        function or control,    %(\fIfunc\fR %<{\fIreply-to\fR\^}%|%{\fIfrom\fR\^}%>)
132        perhaps nested  %(\fIfunc\fR\^(\fIfunc2\fR\^{\fIcomp\fR\^}))
133.re
134.fi
135
136The types \fIdate\fR and \fIaddr\fR have the same syntax as \fIcomp\fR,
137but require that the header component be a date string, or address
138string, respectively.
139
140All arguments except those of type \fIexpr\fR are required.  For the
141\fIexpr\fR argument type, the leading `%' must be omitted for component
142and function escape arguments, and must be present (with a leading space)
143for control escape arguments.
144
145The evaluation of format strings is based on a simple virtual machine
146with an integer register \fInum\fR, and a text string register \fIstr\fR.
147When a function escape is processed, if it accepts an optional \fIexpr\fR
148argument which is not present, it reads the current value of either
149\fInum\fR or \fIstr\fR as appropriate.
150
151.Uh "Return values"
152Component escapes write the value of their message header in \fIstr\fR.
153Function escapes write their return value in \fInum\fR for functions
154returning \fIinteger\fR or \fIboolean\fR values, and in \fIstr\fR for
155functions returning string values.  (The \fIboolean\fR type is a subset
156of integers with usual values 0=false and 1=true.)  Control escapes
157return a \fIboolean\fP value, and set \fInum\fP.
158
159All component escapes, and those function escapes which return an
160\fIinteger\fR or \fIstring\fR value, pass this value back to their caller
161in addition to setting \fIstr\fR or \fInum\fR.  These escapes will print
162out this value unless called as part of an argument to another escape
163sequence.  Escapes which return a \fIboolean\fR value do pass this value
164back to their caller in \fInum\fP, but will never print out the value.
165
166.nf
167.ta \w'Formataddr 'u +\w'Argument 'u +\w'Rboolean 'u
168\fIFunction\fR  \fIArgument\fR  \fIReturn\fR    \fIDescription\fR
169msg             integer message number
170cur             integer message is current
171unseen          integer message is unseen
172size            integer size of message
173strlen          integer length of \fIstr\fR
174width           integer output buffer size in bytes
175charleft                integer bytes left in output buffer
176timenow         integer seconds since the UNIX epoch
177me              string  the user's mailbox
178eq      literal boolean \fInum\fR == \fIarg\fR
179ne      literal boolean \fInum\fR != \fIarg\fR
180gt      literal boolean \fInum\fR > \fIarg\fR
181match   literal boolean \fIstr\fR contains \fIarg\fR
182amatch  literal boolean \fIstr\fR starts with \fIarg\fR
183plus    literal integer \fIarg\fR plus \fInum\fR
184minus   literal integer \fIarg\fR minus \fInum\fR
185divide  literal integer \fInum\fR divided by \fIarg\fR
186modulo  literal integer \fInum\fR modulo \fIarg\fR
187num     literal integer Set \fInum\fR to \fIarg\fR
188lit     literal string  Set \fIstr\fR to \fIarg\fR
189getenv  literal string  Set \fIstr\fR to environment value of \fIarg\fR
190profile literal string  Set \fIstr\fR to profile component \fIarg\fR value
191.\" dat literal int     return value of dat[arg]
192nonzero expr    boolean \fInum\fR is non-zero
193zero    expr    boolean \fInum\fR is zero
194null    expr    boolean \fIstr\fR is empty
195nonnull expr    boolean \fIstr\fR is non-empty
196void    expr            Set \fIstr\fR or \fInum\fR
197comp    comp    string  Set \fIstr\fR to component text
198compval comp    integer Set \fInum\fR to \*(lq\fBatoi\fR(\fIcomp\fR\^)\*(rq
199.\" compflag    comp    integer Set \fInum\fR to component flags bits (internal)
200.\" decodecomp  comp    string  Set \fIstr\fR to RFC-2047 decoded component text
201decode  expr    string  decode \fIstr\fR as RFC-2047 component
202trim    expr            trim trailing white-space from \fIstr\fR
203putstr  expr            print \fIstr\fR
204putstrf expr            print \fIstr\fR in a fixed width
205putnum  expr            print \fInum\fR
206putnumf expr            print \fInum\fR in a fixed width
207.\" addtoseq literal    add msg to sequence (LBL option)
208.re     
209.fi
210
211These functions require a date component as an argument:
212.sp 1
213.nf
214.ta \w'Formataddr 'u +\w'Argument 'u +\w'Rboolean 'u
215\fIFunction\fR  \fIArgument\fR  \fIReturn\fR    \fIDescription\fR
216sec     date    integer seconds of the minute
217min     date    integer minutes of the hour
218hour    date    integer hours of the day (0-23)
219wday    date    integer day of the week (Sun=0)
220day     date    string  day of the week (abbrev.)
221weekday date    string  day of the week
222sday    date    integer day of the week known?
223                        (0=implicit,\-1=unknown)
224mday    date    integer day of the month
225yday    date    integer day of the year
226mon     date    integer month of the year
227month   date    string  month of the year (abbrev.)
228lmonth  date    string  month of the year
229year    date    integer year (may be > 100)
230zone    date    integer timezone in hours
231tzone   date    string  timezone string
232szone   date    integer timezone explicit?
233                        (0=implicit,\-1=unknown)
234date2local      date            coerce date to local timezone
235date2gmt        date            coerce date to GMT
236dst     date    integer daylight savings in effect?
237clock   date    integer seconds since the UNIX epoch
238rclock  date    integer seconds prior to current time
239tws     date    string  official 822 rendering
240pretty  date    string  user-friendly rendering
241nodate  date    integer \fIstr\fR not a date string
242.re     
243.fi
244
245.ne 12
246These functions require an address component as an argument. 
247The return value of functions noted with `*' pertain only to
248the first address present in the header component.
249.sp 1
250.nf
251.ta \w'Formataddr 'u +\w'Argument 'u +\w'Rboolean 'u
252\fIFunction\fR  \fIArgument\fR  \fIReturn\fR    \fIDescription\fR
253proper  addr    string  official 822 rendering
254friendly        addr    string  user-friendly rendering
255addr    addr    string  mbox@host or host!mbox rendering*
256pers    addr    string  the personal name*
257note    addr    string  commentary text*
258mbox    addr    string  the local mailbox*
259mymbox  addr    integer the user's addresses? (0=no,1=yes)
260host    addr    string  the host domain*
261nohost  addr    integer no host was present*
262type    addr    integer host type* (0=local,1=network,
263                        \-1=uucp,2=unknown)
264path    addr    string  any leading host route*
265ingrp   addr    integer address was inside a group*
266gname   addr    string  name of group*
267formataddr      expr            append \fIarg\fR to \fIstr\fR as a
268                        (comma separated) address list
269putaddr literal         print \fIstr\fR address list with
270                        \fIarg\fR as optional label;
271                        get line width from \fInum\fR
272.re     
273.fi
274
275When escapes are nested, evaluation is done from inner-most to outer-most.
276The outer-most escape must begin with `%'; the inner escapes must not.
277For example,
278
279.ti +.5i
280%<(mymbox{from}) To: %{to}%>
281
282writes the value of the header component \*(lqFrom:\*(rq to \fIstr\fR\^;
283then (\fImymbox\fR\^) reads \fIstr\fR and writes its result to \fInum\fR;
284then the control escape evaluates \fInum\fR.  If \fInum\fR is non-zero,
285the string \*(lqTo: \*(rq is printed followed by the value of the header
286component \*(lqTo:\*(rq.
287
288A minor explanation of (\fImymbox\fR\^{\fIcomp\fR\^}) is in order.
289In general, it checks each of the addresses in the header component
290\*(lq\fIcomp\fR\*(rq against the user's mailbox name and any
291\fIAlternate-Mailboxes\fR.  It returns true if any address matches,
292however, it also returns true if the \*(lq\fIcomp\fR\*(rq header is not
293present in the message.  If needed, the (\fInull\fR\^) function can be
294used to explicitly test for this condition.
295
296When a function or component escape is interpreted and the result will
297be immediately printed, an optional field width can be specified to
298print the field in exactly a given number of characters.  For example, a
299numeric escape like %4(\fIsize\fR\^) will print at most 4 digits of the
300message size; overflow will be indicated by a `?' in the first position
301(like `?234').  A string escape like %4(\fIme\fR\^) will print the first 4
302characters and truncate at the end.  Short fields are padded at the right
303with the fill character (normally, a blank).  If the field width argument
304begins with a leading zero, then the fill character is set to a zero.
305
306As above, the functions (\fIputnumf\fR\^) and (\fIputstrf\fR\^)
307print their result in exactly the number of characters
308specified by their leading field width argument.  For example,
309%06(\fIputnumf\fR\^(\fIsize\fR\^)) will print the message
310size in a field six characters wide filled with leading zeros;
311%14(\fIputstrf\^\fR{\fIfrom\^\fR}) will print the \*(lqFrom:\*(rq header
312component in fourteen characters with trailing spaces added as needed.
313For \fIputstrf\fR, using a negative value for the field width causes
314right-justification of the string within the field, with padding on
315the left up to the field width.  The functions (\fIputnum\fR\^) and
316(\fIputstr\fR\^) print their result in the minimum number of characters
317required, and ignore any leading field width argument.
318
319The available output width is kept in an internal register; any output
320past this width will be truncated.
321
322Comments may be inserted in most places where a function argument is
323not expected.  A comment begins with `%;' and ends with a (non-escaped)
324newline.
325
326With all this in mind,
327here's the default format string for \fIscan\fR.
328It's been divided into several pieces for readability.
329The first part is:
330
331.ti +.5i
332%4(msg)%<(cur)+%| %>%<{replied}\-%?{encrypted}E%| %>
333
334which says that the message number should be printed in four digits,
335if the message is the current message then a `+' else a space should
336be printed, and if a \*(lqReplied:\*(rq field is present then a `\-'
337else if an \*(lqEncrypted:\*(rq field is present then an `E' otherwise
338a space should be printed.  Next:
339
340.ti +.5i
341%02(mon{date})/%02(mday{date})
342
343the month and date are printed in two digits (zero filled) separated by
344a slash.
345Next,
346
347.ti +.5i
348%<{date} %|*>
349
350If a \*(lqDate:\*(rq field was present,
351then a space is printed, otherwise a `*'.
352Next,
353
354.ti +.5i
355%<(mymbox{from})%<{to}To:%14(friendly{to})%>%>
356
357if the message is from me,
358and there is a \*(lqTo:\*(rq header,
359print `To:' followed by a \*(lquser-friendly\*(rq rendering of the
360first address in the \*(lqTo:\*(rq field.
361Continuing,
362
363.ti +.5i
364%<(zero)%17(friendly{from})%>
365
366if either of the above two tests failed,
367then the \*(lqFrom:\*(rq address is printed
368in a \*(lquser-friendly\*(rq format.
369And finally,
370
371.ti +.5i
372%{subject}%<{body}<<%{body}%>
373
374the subject and initial body (if any) are printed.
375
376For a more complicated example, next consider
377the default \fIreplcomps\fR format file.
378
379.ti +.5i
380%(lit)%(formataddr %<{reply-to}
381
382This clears \fIstr\fR and formats the \*(lqReply-To:\*(rq header
383if present.  If not present, the else-if clause is executed.
384
385.ti +.5i
386%?{from}%?{sender}%?{return-path}%>)\\
387
388This formats the
389\*(lqFrom:\*(rq, \*(lqSender:\*(rq and \*(lqReturn-Path:\*(rq
390headers, stopping as soon as one of them is present.  Next:
391
392.ti +.5i
393%<(nonnull)%(void(width))%(putaddr To: )\\n%>\\
394
395If the \fIformataddr\fR result is non-null, it is printed as
396an address (with line folding if needed) in a field \fIwidth\fR
397wide with a leading label of \*(lqTo: \*(rq.
398
399.ti +.5i
400%(lit)%(formataddr{to})%(formataddr{cc})%(formataddr(me))\\
401
402\fIstr\fR is cleared, and the
403\*(lqTo:\*(rq and \*(lqCc:\*(rq headers, along with the user's
404address
405(depending on what was specified with
406the \*(lq\-cc\*(rq switch to \fIrepl\fR\^) are formatted.
407
408.ti +.5i
409%<(nonnull)%(void(width))%(putaddr cc: )\\n%>\\
410
411If the result is non-null, it is printed as above with a
412leading label of \*(lqcc: \*(rq.
413
414.ti +.5i
415%<{fcc}Fcc: %{fcc}\\n%>\\
416
417If a \*(lq\-fcc\ folder\*(rq switch was given to \fIrepl\fR
418(see \fIrepl\fR\0(1) for more details about %{\fIfcc\fR\^}),
419an \*(lqFcc:\*(rq header is output.
420
421.ti +.5i
422%<{subject}Subject: Re: %{subject}\\n%>\\
423
424If a subject component was present,
425a suitable reply subject is output.
426
427.nf
428.ti +.5i
429%<{date}In-reply-to: Your message of "\\
430.ti +.5i
431%<(nodate{date})%{date}%|%(pretty{date})%>."%<{message-id}
432.ti +.5i
433             %{message-id}%>\\n%>\\
434.ti +.5i
435\-\-\-\-\-\-\-\-
436.fi
437
438If a date component was present, an \*(lqIn-Reply-To:\*(rq header is
439output with the preface \*(lqYour message of \*(rq.  If the date was
440parseable, it is output in a user-friendly format, otherwise it is
441output as-is.  The message-id is included if present.  As with all
442plain-text, the row of dashes are output as-is.
443
444This last part is a good example for a little more elaboration.
445Here's that part again in pseudo-code:
446.sp 1
447.nf
448.in +.5i
449.ta .5i 1i 1.5i 2i
450if (comp_exists(date))  then
451        print (\*(lqIn-reply-to: Your message of \\\*(lq\*(rq)
452        if (not_date_string(date.value) then
453                print (date.value)
454        else
455                print (pretty(date.value))
456        endif
457        print (\*(lq\\\*(rq\*(rq)
458        if (comp_exists(message-id)) then
459                print (\*(lq\\n\\t\*(rq)
460                print (message-id.value)
461        endif
462        print (\*(lq\\n\*(rq)
463endif
464.re
465.in -.5i
466.fi
467.sp 1
468Although this seems complicated,
469in point of fact,
470this method is flexible enough to extract individual fields and print them in
471any format the user desires.
472.Fi
473None
474.Pr
475None
476.Sa
477scan(1), repl(1), ap(8), dp(8)
478.De
479None
480.Co
481None
482.En
Note: See TracBrowser for help on using the repository browser.