1MH-FORMAT(5) [nmh-1.3] MH-FORMAT(5)
2
3
4
6 mh-format - format file for nmh message system
7
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
400 scan(1), repl(1), ap(8), dp(8)
401
402
404 None
405
406
407
408MH.6.8 1 June 2008 MH-FORMAT(5)