MH-FORMAT(5)                                         MH-FORMAT(5)

NAME
       mh-format - format file for nmh message system

SYNOPSIS
       some nmh commands

DESCRIPTION
       Several  nmh  commands utilize either a format string or a
       format file during their execution.  For example, scan (1)
       uses  a format string which directs it how to generate the
       scan listing for each message; repl (1) uses a format file
       which  directs  it how to generate the reply to a message,
       and so on.

       Format strings are designed to be  efficiently  parsed  by
       nmh  which  means they are not necessarily simple to write
       and understand.  This means that novice, casual,  or  even
       advanced users of nmh should not have to deal with them.

       There  are  a few alternate scan listing formats available
       in     /etc/nmh/scan.time,     /etc/nmh/scan.size,     and
       /etc/nmh/scan.timely.  Look in /etc/nmh for other scan and
       repl format files which may  have  been  written  at  your
       site.

       It  suffices  to have your local nmh expert actually write
       new format commands or modify existing ones.  This  manual
       section  explains  how to do that.  Note: familiarity with
       the C printf routine is assumed.

       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.

       There  are  three types of escape sequences: header compo-
       nents, built-in functions, and flow control.

       A component escape is  specified  as  `%{component}',  and
       exists  for  each  header  found in the message being pro-
       cessed.  For example `%{date}' refers to the "Date:" 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 interpreta-
       tions to some component escapes; be sure to refer to  each
       command's manual entry for complete details.

       A  function  escape  is  specified  as `%(function)'.  All
       functions are built-in, and most have a string or  numeric
       value.

       A  control  escape  is  one of: `%<', `%?', `%|', or `%>'.
       These are combined into  the  conditional  execution  con-
       struct:

            %<condition
                 format text 1
            %?condition2
                 format text 2
            %?condition3
                 format text 3
            ...
            %|
                 format text N
            %>

       Extra  white  space is shown here only for clarity.  These
       constructs may be nested without ambiguity.  They  form  a
       general  if-elseif-else-endif  block where only one of the
       format text segments is interpreted.

       The `%<' and `%?' control escapes causes a condition to be
       evaluated.   This condition may be either a component or a
       function.  The four constructs have the following syntax:

            %<{component}
            %<(function)
            %?{component}
            %?(function)

       These control escapes test whether the function or  compo-
       nent  value  is  non-zero (for integer-valued escapes), or
       non-empty (for string-valued escapes).

       If this test evaulates true, then the format  text  up  to
       the  next corresponding control escape (one of `%|', `%?',
       or `%>') is interpreted normally.  Next, all  format  text
       (if  any)  up  to the corresponding `%>' control escape is
       skipped.  The `%>' control escape is not interpreted; nor-
       mal interpretation resumes after the `%>' escape.

       If the test evaluates false, however, then the format text
       up to the next corresponding control escape (again, one of
       `%|',  `%?',  or `%>') is skipped, instead of being inter-
       preted.  If the control escape encountered was `%?',  then
       the condition associated with that control escape is eval-
       uated, and interpretation  proceeds  after  that  test  as
       described  in  the  previous  paragraph.   If  the control
       escape encountered was `%|', then the format  text  up  to
       the corresponding `%>' escape is interpreted normally.  As
       above, the `%>'  escape  is  not  interpreted  and  normal
       interpretation resumes after the `%>' escape.

       The  `%?'  control escape and its following format text is
       optional, and may be included zero  or  more  times.   The
       `%|'  control escape and its following format text is also
       optional, and may be included zero or one times.

       Most functions expect an argument of a particular type:

       Argument Description            Example Syntax
       literal  A literal number,      %(func 1234)
                or string              %(func text string)
       comp     Any header component   %(func{in-reply-to})
       date     A date component       %(func{date})
       addr     An address component   %(func{from})
       expr     An optional component, %(func(func2))
                function or control,   %(func %<{reply-to}%|%{from}%>)
                perhaps nested         %(func(func2{comp}))

       The types date and addr have the same syntax as comp,  but
       require  that  the  header  component be a date string, or
       address string, respectively.

       All arguments except those of type expr are required.  For
       the  expr  argument  type, the leading `%' must be omitted
       for component and function escape arguments, and  must  be
       present  (with  a  leading space) for control escape argu-
       ments.

       The evaluation of format strings is based on a simple vir-
       tual  machine  with  an  integer  register num, and a text
       string register str.  When a function escape is processed,
       if  it accepts an optional expr argument which is not pre-
       sent, it reads the current value of either num or  str  as
       appropriate.

       Component  escapes write the value of their message header
       in str.  Function escapes write their return value in  num
       for  functions returning integer or boolean values, and in
       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, and  set
       num.

       All  component  escapes,  and those function escapes which
       return an integer or string value, pass this value back to
       their  caller  in  addition  to setting str or num.  These
       escapes will print out this value unless called as part of
       an  argument  to  another  escape sequence.  Escapes which
       return a boolean value do pass this value  back  to  their
       caller in num, but will never print out the value.

       Function   Argument Return   Description
       msg                 integer  message number
       cur                 integer  message is current
       unseen              integer  message is unseen
       size                integer  size of message
       strlen              integer  length of str
       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  num == arg
       ne         literal  boolean  num != arg
       gt         literal  boolean  num > arg
       match      literal  boolean  str contains arg
       amatch     literal  boolean  str starts with arg
       plus       literal  integer  arg plus num
       minus      literal  integer  arg minus num
       divide     literal  integer  num divided by arg
       modulo     literal  integer  num modulo arg
       num        literal  integer  Set num to arg
       lit        literal  string   Set str to arg
       getenv     literal  string   Set str to environment value of arg
       profile    literal  string   Set str to profile component arg value
       nonzero    expr     boolean  num is non-zero
       zero       expr     boolean  num is zero
       null       expr     boolean  str is empty
       nonnull    expr     boolean  str is non-empty
       void       expr              Set str or num
       comp       comp     string   Set str to component text
       compval    comp     integer  Set num to "atoi(comp)"
       decode     expr     string   decode str as RFC-2047 component
       trim       expr              trim trailing white-space from str
       putstr     expr              print str
       putstrf    expr              print str in a fixed width
       putnum     expr              print num
       putnumf    expr              print num in a fixed width

       These functions require a date component as an argument:

       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?
                                    (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?
                                    (0=implicit,-1=unknown)
       date2local date              coerce date to local timezone
       date2gmt   date              coerce date to GMT
       dst        date     integer  daylight savings in effect?
       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
       nodate     date     integer  str not a date string

       These  functions  require an address component as an argu-
       ment.  The return value of functions noted with  `*'  per-
       tain  only to the first address present in the header com-
       ponent.

       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  the user's addresses? (0=no,1=yes)
       host       addr     string   the host domain*
       nohost     addr     integer  no host was present*
       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*
       gname      addr     string   name of group*
       formataddr expr              append arg to str as a
                                    (comma separated) address list
       putaddr    literal           print str address list with
                                    arg as optional label;
                                    get line width from num

       When escapes are nested, evaluation is  done  from  inner-
       most to outer-most.  The outer-most escape must begin with
       `%'; the inner escapes must not.  For example,

            %<(mymbox{from}) To: %{to}%>

       writes the value of the header component "From:"  to  str;
       then (mymbox) reads str and writes its result to num; then
       the control escape evaluates num.  If num is non-zero, the
       string  "To:  "  is  printed  followed by the value of the
       header component "To:".

       A minor explanation of (mymbox{comp})  is  in  order.   In
       general,  it  checks  each  of the addresses in the header
       component "comp" against the user's mailbox name  and  any
       Alternate-Mailboxes.   It  returns  true  if  any  address
       matches, however, it  also  returns  true  if  the  "comp"
       header  is  not  present  in  the message.  If needed, the
       (null) function can be used to explicitly  test  for  this
       condition.

       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(size)  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(me) will
       print the first 4 characters  and  truncate  at  the  end.
       Short fields are padded at the right with the fill charac-
       ter (normally, a blank).   If  the  field  width  argument
       begins with a leading zero, then the fill character is set
       to a zero.

       As above, the  functions  (putnumf)  and  (putstrf)  print
       their result in exactly the number of characters specified
       by their  leading  field  width  argument.   For  example,
       %06(putnumf(size))  will print the message size in a field
       six   characters   wide   filled   with   leading   zeros;
       %14(putstrf{from}) will print the "From:" header component
       in fourteen  characters  with  trailing  spaces  added  as
       needed.  For putstrf, 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 (putnum) and (putstr) print their result  in
       the  minimum number of characters required, and ignore any
       leading field width argument.

       The available output width is kept in an  internal  regis-
       ter; any output past this width will be truncated.

       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.

       With  all  this  in mind, here's the default format string
       for scan.  It's been divided into several pieces for read-
       ability.  The first part is:

            %4(msg)%<(cur)+%| %>%<{replied}-%?{encrypted}E%| %>

       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, and if a "Replied:"
       field is present then a `-' else if an "Encrypted:"  field
       is  present  then  an  `E'  otherwise  a  space  should be
       printed.  Next:

            %02(mon{date})/%02(mday{date})

       the month and date are printed in two digits (zero filled)
       separated by a slash.  Next,

            %<{date} %|*>

       If  a  "Date:" field was present, then a space is printed,
       otherwise a `*'.  Next,

            %<(mymbox{from})%<{to}To:%14(friendly{to})%>%>

       if the message is from me, and there is  a  "To:"  header,
       print `To:' followed by a "user-friendly" rendering of the
       first address in the "To:" field.  Continuing,

            %<(zero)%17(friendly{from})%>

       if either of the above two tests failed, then the  "From:"
       address  is  printed  in  a  "user-friendly"  format.  And
       finally,

            %{subject}%<{body}<<%{body}%>

       the subject and initial body (if any) are printed.

       For a more complicated example, next consider the  default
       replcomps format file.

            %(lit)%(formataddr %<{reply-to}

       This clears str and formats the "Reply-To:" header if pre-
       sent.  If not present, the else-if clause is executed.

            %?{from}%?{sender}%?{return-path}%>)\

       This formats the  "From:",  "Sender:"  and  "Return-Path:"
       headers,  stopping  as  soon  as  one  of them is present.
       Next:

            %<(nonnull)%(void(width))%(putaddr To: )\n%>\

       If the formataddr result is non-null, it is printed as  an
       address  (with  line  folding  if needed) in a field width
       wide with a leading label of "To: ".

            %(lit)%(formataddr{to})%(formataddr{cc})%(for-
       mataddr(me))\

       str  is  cleared,  and  the "To:" and "Cc:" headers, along
       with the user's address (depending on what  was  specified
       with the "-cc" switch to repl) are formatted.

            %<(nonnull)%(void(width))%(putaddr cc: )\n%>\

       If  the  result is non-null, it is printed as above with a
       leading label of "cc: ".

            %<{fcc}Fcc: %{fcc}\n%>\

       If a "-fcc folder" switch was given to repl (see  repl (1)
       for  more  details about %{fcc}), an "Fcc:" header is out-
       put.

            %<{subject}Subject: Re: %{subject}\n%>\

       If a subject component was present, a suitable reply  sub-
       ject is output.

            %<{date}In-reply-to: Your message of "\
            %<(nodate{date})%{date}%|%(pretty{date})%>."%<{message-id}
                         %{message-id}%>\n%>\
            --------

       If  a date component was present, an "In-Reply-To:" header
       is output with the preface "Your message  of  ".   If  the
       date  was  parseable, it is output in a user-friendly for-
       mat, otherwise it is  output  as-is.   The  message-id  is
       included  if  present.  As with all plain-text, the row of
       dashes are output as-is.

       This last part is a good example for a little more  elabo-
       ration.  Here's that part again in pseudo-code:

            if (comp_exists(date))  then
                 print ("In-reply-to: Your message of \"")
                 if (not_date_string(date.value) then
                      print (date.value)
                 else
                      print (pretty(date.value))
                 endif
                 print ("\"")
                 if (comp_exists(message-id)) then
                      print ("\n\t")
                      print (message-id.value)
                 endif
                 print ("\n")
            endif

       Although  this  seems  complicated, in point of fact, this
       method is flexible enough to extract individual fields and
       print  them  in  any  format  the user desires.  None None
       scan(1), repl(1), ap(8), dp(8) None None

[nmh-0.27]                    MH.6.8                            1