Reworked the man page system and some man page contents (mmh-intro).
[mmh] / man / mh-format.man5
diff --git a/man/mh-format.man5 b/man/mh-format.man5
new file mode 100644 (file)
index 0000000..80021df
--- /dev/null
@@ -0,0 +1,624 @@
+.\"
+.\" THIS FILE HAS BEEN AUTOMATICALLY GENERATED.  DO NOT EDIT.
+.\"
+.TH MH-FORMAT %manext5% "%nmhdate%" MH.6.8 [%nmhversion%]
+.SH NAME
+mh-format \- format file for nmh message system
+.SH DESCRIPTION
+Several
+.B nmh
+commands utilize either a
+.I format
+string or a
+.I format
+file during their execution.  For example,
+.B scan
+uses a format string which directs it how to generate the scan listing
+for each message;
+.B repl
+uses a format file which directs it
+how to generate the reply to a message, and so on.
+.PP
+There are a few alternate scan listing formats available
+in
+.IR nmh/etc/scan.time ,
+.IR nmh/etc/scan.size ,
+and
+.IR nmh/etc/scan.timely .
+Look in
+.I nmh/etc
+for other
+.B scan
+and
+.B repl
+format files which may have been written at your site.
+.PP
+It suffices to have your local
+.B nmh
+expert actually write new format
+commands or modify existing ones.  This manual section explains how to
+do that.  Note: familiarity with the C
+.B printf
+routine is assumed.
+.PP
+A format string consists of ordinary text, and special multi-character
+escape sequences which begin with `%'.  When specifying a format
+string, the usual C backslash characters are honored: `\\b', `\\f',
+`\\n', `\\r', and `\\t'.  Continuation lines in format files end with
+`\\' followed by the newline character.
+
+.\" TALK ABOUT SYNTAX FIRST, THEN SEMANTICS
+.SS SYNTAX
+Format strings are built around
+.IR "escape sequences" .
+There are three types of escape sequences: header
+.IR components ,
+built-in
+.IR functions ,
+and flow
+.IR control .
+Comments may be inserted in most places where a function argument is
+not expected.  A comment begins with `%;' and ends with a (non-escaped)
+newline.
+.PP
+A
+.I component
+escape is specified as
+.RI `%{ component }',
+and
+exists for each header found in the message being processed.  For example
+.RI `%{ date }'
+refers to the \*(lqDate:\*(rq field of the appropriate message.
+All component escapes have a string value.  Normally, component values are
+compressed by converting any control characters (tab and newline included)
+to spaces, then eliding any leading or multiple spaces.  However, commands
+may give different interpretations to some component escapes; be sure
+to refer to each command's manual entry for complete details.
+.PP
+A
+.I function
+escape is specified as
+.RI `%( function )'.
+All functions are built-in, and most have a string or numeric value.
+A function escape may have an
+.IR argument .
+The argument follows the function escape: separating
+whitespace is discarded:
+.RI `%( function " " argument )'.
+.PP
+In addition to literal numbers or strings,
+the argument to a function escape can be another function, a component,
+or a control escape.  When the argument is a function or a
+component, they are listed without a leading `%'.  When control escapes
+are used as function arguments, they written as normally, with
+a leading `%';
+
+.SS "Control escapes"
+.PP
+A
+.I control
+escape is one of: `%<', `%?', `%|', or `%>'.
+These are combined into the conditional execution construct:
+.PP
+.RS 5
+.nf
+.RI "%< " condition " " "format-text"
+.RI "%? " condition " " "format-text"
+    \&...
+.RI "%| " "format-text"
+%>
+.fi
+.RE
+.PP
+Extra white space is shown here only for clarity.  These
+constructs may be nested without ambiguity.  They form a general
+.B if\-elseif\-else\-endif
+block where only one of the
+format-texts
+is interpreted.  In other
+words, `%<' is like the "if", `%?' is like the "elseif", `%|' is like
+"else", and `%>' is like "endif".
+.PP
+A `%<' or `%?' control escape causes its condition to be evaluated.
+This condition is a
+.I component
+or
+.IR function .
+For integer valued functions or components, the condition is true
+if the function return or component value is non-zero, and false if zero.
+For string valued functions or components, the condition is true
+if the function return or component value is
+a non-empty string, and false for an empty string.
+
+.PP
+The `%?' control escape is optional, and may there may be more
+than one `%?' control escape in a conditional block.
+The `%|' control escape
+is also optional, but may be included at most once.
+
+.SS "Function escapes"
+Functions expecting an argument generally
+require an argument of a particular type.
+In addition to the number and string types,
+these include:
+.PP
+.RS 5
+.nf
+.ta +\w'Argument 'u +\w'An optional component, 'u
+.I Argument    Description     Example Syntax
+literal        A literal number        %(\fIfunc\fR 1234)
+       or string               %(\fIfunc\fR text string)
+comp   Any component           %(\fIfunc\fR\^{\fIin-reply-to\fR\^})
+date   A date component        %(\fIfunc\fR\^{\fIdate\fR\^})
+addr   An address component    %(\fIfunc\fR\^{\fIfrom\fR\^})
+expr   Nothing %(\fIfunc\fR)
+       or a subexpression      %(\fIfunc\fR\^(\fIfunc2\fR\^))
+       or control escape       %(\fIfunc\fR %<{\fIreply-to\fR\^}%|%{\fIfrom\fR\^}%>)
+.fi
+.RE
+.PP
+The types
+.I date
+and
+.I addr
+have the same syntax as
+.IR comp ,
+but require that the header component be a date string, or address
+string, respectively.
+.PP
+Most arguments not of type
+.IR expr
+are required.
+When escapes are nested (via expr arguments), evaluation is done from inner-most to outer-most.
+As noted above, for the
+expr
+argument type,
+functions and components are written without a
+leading `%'.
+Control escape arguments must use a leading `%', preceded by a space.
+.PP
+For example,
+.PP
+.RS 5
+.nf
+%<(mymbox{from}) To: %{to}%>
+.fi
+.RE
+.PP
+writes  the  value of the header component \*(lqFrom:\*(rq to the
+internal register named str; then (\fImymbox\fR\^) reads str and
+writes its result to the internal register named
+.IR num ;
+then the control escape evaluates
+.IR num .
+If
+.IR num
+is non-zero, the
+string \*(lqTo:\*(rq is printed  followed  by  the  value  of  the
+header component \*(lqTo:\*(rq.
+.SS Evaluation
+The evaluation of format strings is performed
+by a small virtual machine.
+The machine is capable of evaluating nested expressions
+as described above, and in addition
+has an integer register
+.IR num ,
+and a text string register
+.IR str .
+When a function escape that
+accepts an optional argument is processed,
+and the argument is not present, the current value of either
+.I num
+or
+.I str
+is used as the argument: which register is
+used depends on the function, as listed below.
+.PP
+Component escapes write the value of their message header in
+.IR str .
+Function escapes write their return value in
+.I num
+for functions returning integer or boolean values, and in
+.I str
+for functions returning string values.  (The boolean type is a subset
+of integers with usual values 0=false and 1=true.)  Control escapes
+return a boolean value, setting
+.I num
+to 1 if the last explicit condition
+evaluated by a `%<' or `%?' control
+succeeded, and 0 otherwise.
+.PP
+All component escapes, and those function escapes which return an
+integer or string value, evaluate to their value as well as setting
+.I str
+or
+.IR num .
+Outermost escape expressions in
+these forms will print
+their value, but outermost escapes which return a boolean value
+do not result in printed output.
+.SS Functions
+The function escapes may be roughly grouped into a few categories.
+.PP
+.RS 5
+.nf
+.ta \w'Fformataddr 'u +\w'Aboolean 'u +\w'Rboolean 'u
+.I Function    Argument   Result       Description
+msg            integer message number
+cur            integer message is current (0 or 1)
+unseen         integer message is unseen (0 or 1)
+size           integer size of message
+strlen         integer length of \fIstr\fR
+width          integer output buffer size in bytes
+charleft               integer bytes left in output buffer
+timenow                integer seconds since the UNIX epoch
+me             string  the user's mailbox
+eq     literal boolean \fInum\fR == \fIarg\fR
+ne     literal boolean \fInum\fR != \fIarg\fR
+gt     literal boolean \fInum\fR > \fIarg\fR
+match  literal boolean \fIstr\fR contains \fIarg\fR
+amatch literal boolean \fIstr\fR starts with \fIarg\fR
+plus   literal integer \fIarg\fR plus \fInum\fR
+minus  literal integer \fIarg\fR minus \fInum\fR
+divide literal integer \fInum\fR divided by \fIarg\fR
+modulo literal integer \fInum\fR modulo \fIarg\fR
+num    literal integer Set \fInum\fR to \fIarg\fR.
+num            integer Set \fInum\fR to zero.
+lit    literal string  Set \fIstr\fR to \fIarg\fR.
+lit            string  Clear \fIstr\fR.
+getenv         literal string  Set \fIstr\fR to environment value of \fIarg\fR
+profile        literal string  Set \fIstr\fR to profile component \fIarg\fR
+                       value
+.\" dat        literal int     return value of dat[arg]
+nonzero        expr    boolean \fInum\fR is non-zero
+zero   expr    boolean \fInum\fR is zero
+null   expr    boolean \fIstr\fR is empty
+nonnull        expr    boolean \fIstr\fR is non-empty
+void   expr            Set \fIstr\fR or \fInum\fR
+comp   comp    string  Set \fIstr\fR to component text
+compval        comp    integer Set \fInum\fR to \*(lq\fBatoi\fR(\fIcomp\fR\^)\*(rq
+.\" compflag   comp    integer Set \fInum\fR to component flags bits (internal)
+.\" decodecomp comp    string  Set \fIstr\fR to RFC-2047 decoded component text
+decode expr    string  decode \fIstr\fR as RFC-2047 (MIME-encoded)
+                       component
+unquote        expr    string  remove RFC-2822 quotes from \fIstr\fR
+trim   expr            trim trailing white-space from \fIstr\fR
+putstr expr            print \fIstr\fR
+putstrf        expr            print \fIstr\fR in a fixed width
+putnum expr            print \fInum\fR
+putnumf        expr            print \fInum\fR in a fixed width
+.\" addtoseq literal    add msg to sequence (LBL option)
+nodate string  integer Argument not a date string (0 or 1)
+formataddr     expr            append \fIarg\fR to \fIstr\fR as a
+                       (comma separated) address list
+putaddr        literal         print \fIstr\fR address list with
+                       \fIarg\fR as optional label;
+                       get line width from \fInum\fR
+.fi
+.RE
+.PP
+The following functions require a date component as an argument:
+.PP
+.RS 5
+.nf
+.ta \w'Fformataddr 'u +\w'Aboolean 'u +\w'Rboolean 'u
+.I Function    Argument        Return  Description
+sec    date    integer seconds of the minute
+min    date    integer minutes of the hour
+hour   date    integer hours of the day (0-23)
+wday   date    integer day of the week (Sun=0)
+day    date    string  day of the week (abbrev.)
+weekday        date    string  day of the week
+sday   date    integer day of the week known?
+                       (1=explicit,0=implicit,\-1=unknown)
+mday   date    integer day of the month
+yday   date    integer day of the year
+mon    date    integer month of the year
+month  date    string  month of the year (abbrev.)
+lmonth date    string  month of the year
+year   date    integer year (may be > 100)
+zone   date    integer timezone in hours
+tzone  date    string  timezone string
+szone  date    integer timezone explicit?
+                       (1=explicit,0=implicit,\-1=unknown)
+date2local     date            coerce date to local timezone
+date2gmt       date            coerce date to GMT
+dst    date    integer daylight savings in effect? (0 or 1)
+clock  date    integer seconds since the UNIX epoch
+rclock date    integer seconds prior to current time
+tws    date    string  official 822 rendering
+pretty date    string  user-friendly rendering
+.fi
+.RE
+.PP
+These functions require an address component as an argument.
+The return value of functions noted with `*' is computed from
+the first address present in the header component.
+.PP
+.RS 5
+.nf
+.ta \w'Fformataddr 'u +\w'Aboolean 'u +\w'Rboolean 'u
+.I Function    Argument        Return  Description
+proper addr    string  official 822 rendering
+friendly       addr    string  user-friendly rendering
+addr   addr    string  mbox@host or host!mbox rendering*
+pers   addr    string  the personal name*
+note   addr    string  commentary text*
+mbox   addr    string  the local mailbox*
+mymbox addr    integer List has the user's address? (0 or 1)
+host   addr    string  the host domain*
+nohost addr    integer no host was present (0 or 1)*
+type   addr    integer host type* (0=local,1=network,
+                       \-1=uucp,2=unknown)
+path   addr    string  any leading host route*
+ingrp  addr    integer address was inside a group (0 or 1)*
+gname  addr    string  name of group*
+.fi
+.RE
+.PP
+(A clarification on (\fImymbox\fR\^{\fIcomp\fR\^}) is in order.
+This function checks each of the addresses in the header component
+\*(lq\fIcomp\fR\*(rq against the user's mailbox name and any
+.RI \*(lq Alternate-Mailboxes \*(rq.
+It returns true if any address matches,
+however, it also returns true if the \*(lq\fIcomp\fR\*(rq header is not
+present in the message.  If needed, the (\fInull\fR\^) function can be
+used to explicitly test for this case.)
+.SS Formatting
+When a function or component escape is interpreted and the result will
+be immediately printed, an optional field width can be specified to
+print the field in exactly a given number of characters.  For example, a
+numeric escape like %4(\fIsize\fR\^) will print at most 4 digits of the
+message size; overflow will be indicated by a `?' in the first position
+(like `?234').  A string escape like %4(\fIme\fR\^) will print the first 4
+characters and truncate at the end.  Short fields are padded at the right
+with the fill character (normally, a blank).  If the field width argument
+begins with a leading zero, then the fill character is set to a zero.
+.PP
+The functions (\fIputnumf\fR\^) and (\fIputstrf\fR\^)
+print their result in exactly the number of characters
+specified by their leading field width argument.  For example,
+%06(\fIputnumf\fR\^(\fIsize\fR\^)) will print the message
+size in a field six characters wide filled with leading zeros;
+%14(\fIputstrf\^\fR{\fIfrom\^\fR}) will print the \*(lqFrom:\*(rq header
+component in fourteen characters with trailing spaces added as needed.
+For \fIputstrf\fR, using a negative value for the field width causes
+right-justification of the string within the field, with padding on
+the left up to the field width.
+The functions (\fIputnum\fR\^) and
+(\fIputstr\fR\^) are somewhat special: they print their result in the minimum number of characters
+required, and ignore any leading field width argument.
+.PP
+The available output width is kept in an internal register; any output
+past this width will be truncated.
+.SS Examples
+With all this in mind,
+here's the default format string for
+.BR scan .
+It's been divided into several pieces for readability.
+The first part is:
+.PP
+.RS
+.nf
+%4(msg)%<(cur)+%| %>%<{replied}\-%?{encrypted}E%| %>
+.fi
+.RE
+.PP
+which says that the message number should be printed in four digits.
+If the message is the current message then a `+' else a space should
+be printed; if a \*(lqReplied:\*(rq field is present then a `\-'
+else if an \*(lqEncrypted:\*(rq field is present then an `E' otherwise
+a space should be printed.  Next:
+.PP
+.RS
+.nf
+%02(mon{date})/%02(mday{date})
+.fi
+.RE
+.PP
+the month and date are printed in two digits (zero filled) separated by
+a slash. Next,
+.PP
+.RS 5
+.nf
+%<{date} %|*%>
+.fi
+.RE
+.PP
+If a \*(lqDate:\*(rq field was present,
+then a space is printed, otherwise a `*'.
+Next,
+.PP
+.RS 5
+.nf
+%<(mymbox{from})%<{to}To:%14(decode(friendly{to}))%>%>
+.fi
+.RE
+.PP
+if the message is from me, and there is a \*(lqTo:\*(rq header,
+print \*(lqTo:\*(rq followed by a \*(lquser-friendly\*(rq rendering of the
+first address in the \*(lqTo:\*(rq field; any MIME-encoded
+characters are decoded into the actual characters.
+Continuing,
+.PP
+.RS 5
+.nf
+%<(zero)%17(decode(friendly{from}))%>
+.fi
+.RE
+.PP
+if either of the above two tests failed,
+then the \*(lqFrom:\*(rq address is printed
+in a mime-decoded, \*(lquser-friendly\*(rq format.
+And finally,
+.PP
+.RS 5
+.nf
+%(decode{subject})%<{body}<<%{body}>>%>
+.fi
+.RE
+.PP
+the mime-decoded subject and initial body (if any) are printed.
+.PP
+For a more complicated example, next consider
+a possible
+.I replcomps
+format file.
+.PP
+.RS 5
+.nf
+%(lit)%(formataddr %<{reply-to}
+.fi
+.RE
+.PP
+This clears
+.I str
+and formats the \*(lqReply-To:\*(rq header
+if present.  If not present, the else-if clause is executed.
+.PP
+.RS 5
+.nf
+%?{from}%?{sender}%?{return-path}%>)\\
+.fi
+.RE
+.PP
+This formats the
+\*(lqFrom:\*(rq, \*(lqSender:\*(rq and \*(lqReturn-Path:\*(rq
+headers, stopping as soon as one of them is present.  Next:
+.PP
+.RS 5
+.nf
+%<(nonnull)%(void(width))%(putaddr To: )\\n%>\\
+.fi
+.RE
+.PP
+If the \fIformataddr\fR result is non-null, it is printed as
+an address (with line folding if needed) in a field \fIwidth\fR
+wide with a leading label of \*(lqTo:\*(rq.
+.PP
+.RS 5
+.nf
+%(lit)%(formataddr{to})%(formataddr{cc})%(formataddr(me))\\
+.fi
+.RE
+.PP
+.I str
+is cleared, and the \*(lqTo:\*(rq and \*(lqCc:\*(rq headers, along with the user's
+address (depending on what was specified with
+the \*(lq\-cc\*(rq switch to \fIrepl\fR\^) are formatted.
+.PP
+.RS 5
+.nf
+%<(nonnull)%(void(width))%(putaddr cc: )\\n%>\\
+.fi
+.RE
+.PP
+If the result is non-null, it is printed as above with a
+leading label of \*(lqcc:\*(rq.
+.PP
+.RS 5
+.nf
+%<{fcc}Fcc: %{fcc}\\n%>\\
+.fi
+.RE
+.PP
+If a
+.B \-fcc
+.I folder
+switch was given to
+.B repl
+(see
+.BR repl (1)
+for more details about %{\fIfcc\fR\^}),
+an \*(lqFcc:\*(rq header is output.
+.PP
+.RS 5
+.nf
+%<{subject}Subject: Re: %{subject}\\n%>\\
+.fi
+.RE
+.PP
+If a subject component was present,
+a suitable reply subject is output.
+.PP
+.RS 5
+.nf
+%<{message-id}In-Reply-To: %{message-id}\\n%>\\
+%<{message-id}References: %<{references} %{references}%>\\
+%{message-id}\\n%>
+\-\-\-\-\-\-\-\-
+.fi
+.RE
+.PP
+If a message-id component was present, an \*(lqIn-Reply-To:\*(rq header is
+output including the message-id, followed by a \*(lqReferences:\*(rq
+header with references, if present, and the message-id.
+As with all
+plain-text, the row of dashes are output as-is.
+.PP
+This last part is a good example for a little more elaboration.
+Here's that part again in pseudo-code:
+.PP
+.RS 5
+.nf
+.ta .5i 1i 1.5i 2i
+if (comp_exists(message-id))  then
+       print (\*(lqIn-reply-to: \*(rq)
+       print (message-id.value)
+       print (\*(lq\\n\*(rq)
+endif
+if (comp_exists(message-id)) then
+       print (\*(lqReferences: \*(rq)
+       if (comp_exists(references)) then
+             print(references.value);
+       endif
+       print (message-id.value)
+       print (\*(lq\\n\*(rq)
+endif
+.fi
+.RE
+.PP
+.\" (Note that this pseudocode begs the question ``why not just
+.\" support this syntax?''  MH has been hacked on for a long time...)
+.\".PP
+One more example: Currently,
+.B nmh
+supports very
+large message numbers, and it is not uncommon for a folder
+to have far more than 10000 messages.
+.\" (Indeed, the original MH
+.\" tutorial document by Rose and Romine is entitled "How to
+.\" process 200 messages a day and still get some real work
+.\" done."  The authors apparently only planned to get
+.\" real work done for about 50 days per folder.)
+Nontheless (as noted above)
+the various scan format strings are inherited
+from older MH versions, and are generally hard-coded to 4
+digits of message number before formatting problems
+start to occur.
+The nmh format strings can be modified to behave more sensibly with larger
+message numbers:
+.PP
+.RS
+.nf
+%(void(msg))%<(gt 9999)%(msg)%|%4(msg)%>
+.fi
+.RE
+.PP
+The current message number is placed in \fInum\fP.
+(Note that
+.RI ( msg )
+is an int function, not a component.)
+The
+.RI ( gt )
+conditional
+is used to test whether the message number
+has 5
+or more digits.
+If so, it is printed at full width: otherwise
+at 4 digits.
+.SH "SEE ALSO"
+scan(1), repl(1), ap(8), dp(8)
+
+.SH CONTEXT
+None