1MH-FORMAT(5)                       [nmh-1.3]                      MH-FORMAT(5)
2
3
4

NAME

6       mh-format - format file for nmh message system
7

DESCRIPTION

9       Several  nmh  commands  utilize either a format string or a format file
10       during their execution.  For example, scan uses a format  string  which
11       directs it how to generate the scan listing for each message; repl uses
12       a format file which directs it how to generate the reply to a  message,
13       and so on.
14
15       There   are   a   few  alternate  scan  listing  formats  available  in
16       nmh/etc/scan.time, nmh/etc/scan.size, and nmh/etc/scan.timely.  Look in
17       nmh/etc  for other scan and repl format files which may have been writ‐
18       ten at your site.
19
20       It suffices to have your local nmh expert  actually  write  new  format
21       commands  or modify existing ones.  This manual section explains how to
22       do that.  Note: familiarity with the C printf routine is assumed.
23
24       A format string consists of ordinary text, and special  multi-character
25       escape  sequences  which  begin  with  `%'.   When  specifying a format
26       string, the usual C backslash characters are honored: `\b', `\f', `\n',
27       `\r',  and  `\t'.  Continuation lines in format files end with `\' fol‐
28       lowed by the newline character.
29
30
31   SYNTAX
32       Format strings are built around  escape  sequences.   There  are  three
33       types  of  escape sequences: header components, built-in functions, and
34       flow control.  Comments may be inserted in most places where a function
35       argument  is  not expected.  A comment begins with `%;' and ends with a
36       (non-escaped) newline.
37
38       A component escape is specified as `%{component}', and exists for  each
39       header  found  in  the  message being processed.  For example `%{date}'
40       refers to the “Date:” field of the appropriate message.  All  component
41       escapes have a string value.  Normally, component values are compressed
42       by converting any control characters (tab and newline included) to spa‐
43       ces,  then  eliding  any leading or multiple spaces.  However, commands
44       may give different interpretations to some component escapes;  be  sure
45       to refer to each command's manual entry for complete details.
46
47       A  function  escape  is  specified as `%(function)'.  All functions are
48       built-in, and most have a string or numeric value.  A  function  escape
49       may  have an argument.  The argument follows the function escape: sepa‐
50       rating whitespace is discarded: `%(function argument)'.
51
52       In addition to literal numbers or strings, the argument to  a  function
53       escape can be another function, a component, or a control escape.  When
54       the argument is a function or a component, they are  listed  without  a
55       leading `%'.  When control escapes are used as function arguments, they
56       written as normally, with a leading `%';
57
58
59   Control escapes
60       A control escape is one of: `%<', `%?', `%|', or `%>'.  These are  com‐
61       bined into the conditional execution construct:
62
63            %< condition format-text
64            %? condition format-text
65                ...
66            %| format-text
67            %>
68
69       Extra white space is shown here only for clarity.  These constructs may
70       be nested without ambiguity.  They form a general  if-elseif-else-endif
71       block  where  only  one  of  the format-texts is interpreted.  In other
72       words, `%<' is like the "if", `%?' is like the "elseif", `%|'  is  like
73       "else", and `%>' is like "endif".
74
75       A  `%<'  or  `%?'  control escape causes its condition to be evaluated.
76       This condition is a component or function.  For  integer  valued  func‐
77       tions  or  components,  the condition is true if the function return or
78       component value is non-zero, and false  if  zero.   For  string  valued
79       functions  or  components, the condition is true if the function return
80       or component value is a  non-empty  string,  and  false  for  an  empty
81       string.
82
83
84       The `%?' control escape is optional, and may there may be more than one
85       `%?' control escape in a conditional block.  The `%|' control escape is
86       also optional, but may be included at most once.
87
88
89   Function escapes
90       Functions expecting an argument generally require an argument of a par‐
91       ticular type.  In addition  to  the  number  and  string  types,  these
92       include:
93
94            Argument Description            Example Syntax
95            literal  A literal number       %(func 1234)
96                     or string              %(func text string)
97            comp     Any component          %(func{in-reply-to})
98            date     A date component       %(func{date})
99            addr     An address component   %(func{from})
100            expr     Nothing                %(func)
101                     or a subexpression     %(func(func2))
102                     or control escape      %(func %<{reply-to}%|%{from}%>)
103
104       The  types date and addr have the same syntax as comp, but require that
105       the header component be a date string, or address string, respectively.
106
107       Most arguments not of type expr are required.  When escapes are  nested
108       (via expr arguments), evaluation is done from inner-most to outer-most.
109       As noted above, for the expr argument type,  functions  and  components
110       are written without a leading `%'.  Control escape arguments must use a
111       leading `%', preceded by a space.
112
113       For example,
114
115            %<(mymbox{from}) To: %{to}%>
116
117       writes  the  value of the header component “From:” to the internal reg‐
118       ister  named  str; then (mymbox) reads str and writes its result to the
119       internal register named num; then the control escape evaluates num.  If
120       num  is non-zero, the string “To:” is printed  followed  by  the  value
121       of  the header component “To:”.
122
123   Evaluation
124       The evaluation of format  strings  is  performed  by  a  small  virtual
125       machine.   The  machine  is capable of evaluating nested expressions as
126       described above, and in addition has an integer  register  num,  and  a
127       text  string  register  str.   When  a  function escape that accepts an
128       optional argument is processed, and the argument is  not  present,  the
129       current  value of either num or str is used as the argument: which reg‐
130       ister is used depends on the function, as listed below.
131
132       Component escapes write the value  of  their  message  header  in  str.
133       Function  escapes write their return value in num for functions return‐
134       ing integer or boolean values,  and  in  str  for  functions  returning
135       string  values.   (The  boolean type is a subset of integers with usual
136       values 0=false and 1=true.)  Control escapes return  a  boolean  value,
137       setting  num to 1 if the last explicit condition evaluated by a `%<' or
138       `%?' control succeeded, and 0 otherwise.
139
140       All component escapes, and those function escapes which return an inte‐
141       ger  or string value, evaluate to their value as well as setting str or
142       num.  Outermost escape expressions in  these  forms  will  print  their
143       value, but outermost escapes which return a boolean value do not result
144       in printed output.
145
146   Functions
147       The function escapes may be roughly grouped into a few categories.
148
149            Function    Argument Result   Description
150            msg                  integer  message number
151            cur                  integer  message is current (0 or 1)
152            unseen               integer  message is unseen (0 or 1)
153            size                 integer  size of message
154            strlen               integer  length of str
155            width                integer  output buffer size in bytes
156            charleft             integer  bytes left in output buffer
157            timenow              integer  seconds since the UNIX epoch
158            me                   string   the user's mailbox
159            eq          literal  boolean  num == arg
160            ne          literal  boolean  num != arg
161            gt          literal  boolean  num > arg
162            match       literal  boolean  str contains arg
163            amatch      literal  boolean  str starts with arg
164            plus        literal  integer  arg plus num
165            minus       literal  integer  arg minus num
166            divide      literal  integer  num divided by arg
167            modulo      literal  integer  num modulo arg
168            num         literal  integer  Set num to arg.
169            num                  integer  Set num to zero.
170            lit         literal  string   Set str to arg.
171            lit                  string   Clear str.
172            getenv      literal  string   Set str to environment value of arg
173            profile     literal  string   Set str to profile component arg
174                                          value
175            nonzero     expr     boolean  num is non-zero
176            zero        expr     boolean  num is zero
177            null        expr     boolean  str is empty
178            nonnull     expr     boolean  str is non-empty
179            void        expr              Set str or num
180            comp        comp     string   Set str to component text
181            compval     comp     integer  Set num to “atoi(comp)”
182            decode      expr     string   decode str as RFC-2047 (MIME-encoded)
183                                          component
184            unquote     expr     string   remove RFC-2822 quotes from str
185            trim        expr              trim trailing white-space from str
186            putstr      expr              print str
187            putstrf     expr              print str in a fixed width
188            putnum      expr              print num
189            putnumf     expr              print num in a fixed width
190            nodate      string   integer  Argument not a date string (0 or 1)
191            formataddr  expr              append arg to str as a
192                                          (comma separated) address list
193            putaddr     literal           print str address list with
194                                          arg as optional label;
195                                          get line width from num
196
197       The following functions require a date component as an argument:
198
199            Function    Argument Return   Description
200            sec         date     integer  seconds of the minute
201            min         date     integer  minutes of the hour
202            hour        date     integer  hours of the day (0-23)
203            wday        date     integer  day of the week (Sun=0)
204            day         date     string   day of the week (abbrev.)
205            weekday     date     string   day of the week
206            sday        date     integer  day of the week known?
207                                          (1=explicit,0=implicit,-1=unknown)
208            mday        date     integer  day of the month
209            yday        date     integer  day of the year
210            mon         date     integer  month of the year
211            month       date     string   month of the year (abbrev.)
212            lmonth      date     string   month of the year
213            year        date     integer  year (may be > 100)
214            zone        date     integer  timezone in hours
215            tzone       date     string   timezone string
216            szone       date     integer  timezone explicit?
217                                          (1=explicit,0=implicit,-1=unknown)
218            date2local  date              coerce date to local timezone
219            date2gmt    date              coerce date to GMT
220            dst         date     integer  daylight savings in effect? (0 or 1)
221            clock       date     integer  seconds since the UNIX epoch
222            rclock      date     integer  seconds prior to current time
223            tws         date     string   official 822 rendering
224            pretty      date     string   user-friendly rendering
225
226       These functions require an  address  component  as  an  argument.   The
227       return  value  of  functions  noted with `*' is computed from the first
228       address present in the header component.
229
230            Function    Argument Return   Description
231            proper      addr     string   official 822 rendering
232            friendly    addr     string   user-friendly rendering
233            addr        addr     string   mbox@host or host!mbox rendering*
234            pers        addr     string   the personal name*
235            note        addr     string   commentary text*
236            mbox        addr     string   the local mailbox*
237            mymbox      addr     integer  List has the user's address? (0 or 1)
238            host        addr     string   the host domain*
239            nohost      addr     integer  no host was present (0 or 1)*
240            type        addr     integer  host type* (0=local,1=network,
241                                          -1=uucp,2=unknown)
242            path        addr     string   any leading host route*
243            ingrp       addr     integer  address was inside a group (0 or 1)*
244            gname       addr     string   name of group*
245
246       (A clarification on (mymbox{comp}) is in order.  This  function  checks
247       each of the addresses in the header component “comp” against the user's
248       mailbox name and any “Alternate-Mailboxes”.  It  returns  true  if  any
249       address  matches, however, it also returns true if the “comp” header is
250       not present in the message.  If needed, the (null) function can be used
251       to explicitly test for this case.)
252
253   Formatting
254       When  a function or component escape is interpreted and the result will
255       be immediately printed, an optional field width  can  be  specified  to
256       print  the field in exactly a given number of characters.  For example,
257       a numeric escape like %4(size) will print at most 4 digits of the  mes‐
258       sage  size;  overflow  will be indicated by a `?' in the first position
259       (like `?234').  A string escape like %4(me)  will  print  the  first  4
260       characters  and  truncate  at  the end.  Short fields are padded at the
261       right with the fill character (normally, a blank).  If the field  width
262       argument  begins with a leading zero, then the fill character is set to
263       a zero.
264
265       The functions (putnumf) and (putstrf) print their result in exactly the
266       number  of  characters specified by their leading field width argument.
267       For example, %06(putnumf(size)) will print the message size in a  field
268       six  characters wide filled with leading zeros; %14(putstrf{from}) will
269       print the “From:” header component in fourteen characters with trailing
270       spaces  added  as  needed.  For putstrf, using a negative value for the
271       field width causes right-justification of the string within the  field,
272       with padding on the left up to the field width.  The functions (putnum)
273       and (putstr) are somewhat special: they print their result in the mini‐
274       mum  number  of characters required, and ignore any leading field width
275       argument.
276
277       The available output width is kept in an internal register; any  output
278       past this width will be truncated.
279
280   Examples
281       With all this in mind, here's the default format string for scan.  It's
282       been divided into several pieces for readability.  The first part is:
283
284              %4(msg)%<(cur)+%| %>%<{replied}-%?{encrypted}E%| %>
285
286       which says that the message number should be printed  in  four  digits.
287       If the message is the current message then a `+' else a space should be
288       printed; if a “Replied:” field  is  present  then  a  `-'  else  if  an
289       “Encrypted:”  field  is present then an `E' otherwise a space should be
290       printed.  Next:
291
292              %02(mon{date})/%02(mday{date})
293
294       the month and date are printed in two digits (zero filled) separated by
295       a slash. Next,
296
297            %<{date} %|*%>
298
299       If  a  “Date:”  field was present, then a space is printed, otherwise a
300       `*'.  Next,
301
302            %<(mymbox{from})%<{to}To:%14(decode(friendly{to}))%>%>
303
304       if the message is from me, and there is a  “To:”  header,  print  “To:”
305       followed  by  a  “user-friendly”  rendering of the first address in the
306       “To:” field; any MIME-encoded characters are decoded  into  the  actual
307       characters.  Continuing,
308
309            %<(zero)%17(decode(friendly{from}))%>
310
311       if  either  of  the above two tests failed, then the “From:” address is
312       printed in a mime-decoded, “user-friendly” format.  And finally,
313
314            %(decode{subject})%<{body}<<%{body}>>%>
315
316       the mime-decoded subject and initial body (if any) are printed.
317
318       For a more complicated example, next consider a possible replcomps for‐
319       mat file.
320
321            %(lit)%(formataddr %<{reply-to}
322
323       This  clears str and formats the “Reply-To:” header if present.  If not
324       present, the else-if clause is executed.
325
326            %?{from}%?{sender}%?{return-path}%>)\
327
328       This formats the “From:”, “Sender:” and “Return-Path:”  headers,  stop‐
329       ping as soon as one of them is present.  Next:
330
331            %<(nonnull)%(void(width))%(putaddr To: )\n%>\
332
333       If the formataddr result is non-null, it is printed as an address (with
334       line folding if needed) in a field width wide with a leading  label  of
335       “To:”.
336
337            %(lit)%(formataddr{to})%(formataddr{cc})%(formataddr(me))\
338
339       str  is cleared, and the “To:” and “Cc:” headers, along with the user's
340       address (depending on what was specified with the “-cc” switch to repl)
341       are formatted.
342
343            %<(nonnull)%(void(width))%(putaddr cc: )\n%>\
344
345       If  the result is non-null, it is printed as above with a leading label
346       of “cc:”.
347
348            %<{fcc}Fcc: %{fcc}\n%>\
349
350       If a -fcc folder switch was given to repl (see repl(1) for more details
351       about %{fcc}), an “Fcc:” header is output.
352
353            %<{subject}Subject: Re: %{subject}\n%>\
354
355       If a subject component was present, a suitable reply subject is output.
356
357            %<{message-id}In-Reply-To: %{message-id}\n%>\
358            %<{message-id}References: %<{references} %{references}%>\
359            %{message-id}\n%>
360            --------
361
362       If a message-id component was present, an “In-Reply-To:” header is out‐
363       put including the message-id, followed by a “References:”  header  with
364       references,  if  present,  and the message-id.  As with all plain-text,
365       the row of dashes are output as-is.
366
367       This last part is a good example for a little more elaboration.  Here's
368       that part again in pseudo-code:
369
370            if (comp_exists(message-id))  then
371                 print (“In-reply-to: ”)
372                 print (message-id.value)
373                 print (“\n”)
374            endif
375            if (comp_exists(message-id)) then
376                 print (“References: ”)
377                 if (comp_exists(references)) then
378                       print(references.value);
379                 endif
380                 print (message-id.value)
381                 print (“\n”)
382            endif
383
384       One  more  example: Currently, nmh supports very large message numbers,
385       and it is not uncommon for a folder to have far more  than  10000  mes‐
386       sages.  Nontheless (as noted above) the various scan format strings are
387       inherited from older MH versions, and are  generally  hard-coded  to  4
388       digits  of  message  number  before formatting problems start to occur.
389       The nmh format strings can be modified to  behave  more  sensibly  with
390       larger message numbers:
391
392              %(void(msg))%<(gt 9999)%(msg)%|%4(msg)%>
393
394       The  current  message  number is placed in num.  (Note that (msg) is an
395       int function, not a component.)  The (gt) conditional is used  to  test
396       whether  the message number has 5 or more digits.  If so, it is printed
397       at full width: otherwise at 4 digits.
398

SEE ALSO

400       scan(1), repl(1), ap(8), dp(8)
401
402

CONTEXT

404       None
405
406
407
408MH.6.8                            1 June 2008                     MH-FORMAT(5)
Impressum