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