{
    "content": [
        {
            "type": "text",
            "text": "# mh-format (man)\n\n## NAME\n\nmh-format - formatting language for nmh message system\n\n## DESCRIPTION\n\nSeveral  nmh commands utilize either a format string or a format file during their execution.\nFor example, scan uses a format string to generate its listing of messages; repl uses a  for‐\nmat file to generate message replies, and so on.\n\n## Sections\n\n- **NAME**\n- **DESCRIPTION** (10 subsections)\n- **SEE ALSO**\n- **CONTEXT**\n\nUse structuredContent.sections for detailed options, examples, and full documentation.\n"
        }
    ],
    "structuredContent": {
        "command": "mh-format",
        "section": "",
        "mode": "man",
        "summary": "mh-format - formatting language for nmh message system",
        "synopsis": null,
        "tldr_summary": null,
        "tldr_examples": [],
        "tldr_source": null,
        "flags": [],
        "examples": [],
        "see_also": [
            {
                "name": "scan",
                "section": "1",
                "url": "https://www.chedong.com/phpMan.php/man/scan/1/json"
            },
            {
                "name": "repl",
                "section": "1",
                "url": "https://www.chedong.com/phpMan.php/man/repl/1/json"
            },
            {
                "name": "fmttest",
                "section": "1",
                "url": "https://www.chedong.com/phpMan.php/man/fmttest/1/json"
            }
        ],
        "section_outline": [
            {
                "name": "NAME",
                "lines": 2,
                "subsections": []
            },
            {
                "name": "DESCRIPTION",
                "lines": 24,
                "subsections": [
                    {
                        "name": "Component escapes",
                        "lines": 9
                    },
                    {
                        "name": "Function escapes",
                        "lines": 11
                    },
                    {
                        "name": "Control escapes",
                        "lines": 22
                    },
                    {
                        "name": "Function escapes",
                        "lines": 30
                    },
                    {
                        "name": "Evaluation",
                        "lines": 19
                    },
                    {
                        "name": "Functions",
                        "lines": 140
                    },
                    {
                        "name": "Formatting",
                        "lines": 37
                    },
                    {
                        "name": "Special Handling",
                        "lines": 8
                    },
                    {
                        "name": "Other Hints and Tips",
                        "lines": 39
                    },
                    {
                        "name": "Examples",
                        "lines": 108
                    }
                ]
            },
            {
                "name": "SEE ALSO",
                "lines": 2,
                "subsections": []
            },
            {
                "name": "CONTEXT",
                "lines": 5,
                "subsections": []
            }
        ],
        "sections": {
            "NAME": {
                "content": "mh-format - formatting language for nmh message system\n",
                "subsections": []
            },
            "DESCRIPTION": {
                "content": "Several  nmh commands utilize either a format string or a format file during their execution.\nFor example, scan uses a format string to generate its listing of messages; repl uses a  for‐\nmat file to generate message replies, and so on.\n\nThere   are  a  number  of  scan  listing  formats  available,  including  nmh/etc/scan.time,\nnmh/etc/scan.size, and nmh/etc/scan.timely.  Look in /etc/nmh for other scan and repl  format\nfiles which may have been written at your site.\n\nYou  can have your local nmh expert write new format commands or modify existing ones, or you\ncan try your hand at it yourself.  This manual section explains how to do that.   Note:  some\nfamiliarity with the C printf routine is assumed.\n\nA  format string consists of ordinary text combined with special, multi-character, escape se‐\nquences which begin with `%'.  When specifying a format string, the usual C backslash charac‐\nters  are  honored: `\\b', `\\f', `\\n', `\\r', and `\\t'.  Continuation lines in format files end\nwith `\\' followed by the newline character.  A literal `%' can be inserted into a format file\nby using the sequence `%%'.\n\nSYNTAX\nFormat  strings are built around escape sequences.  There are three types of escape sequence:\nheader components, built-in functions, and flow control.  Comments may be  inserted  in  most\nplaces where a function argument is not expected.  A comment begins with `%;' and ends with a\n(non-escaped) newline.\n",
                "subsections": [
                    {
                        "name": "Component escapes",
                        "content": "A component escape is specified as `%{component}', and exists for each header in the  message\nbeing  processed.   For  example,  `%{date}' refers to the “Date:” field of the message.  All\ncomponent escapes have a string value.  Such values are usually compressed by converting  any\ncontrol characters (tab and newline included) to spaces, then eliding any leading or multiple\nspaces.  Some commands, however, may interpret some component escapes differently; be sure to\nrefer  to  each command's manual entry for details.  Some commands (such as ap(8) and mhl(1))\nuse a special component `%{text}' to refer to the text being processed; see their  respective\nman pages for details and examples.\n"
                    },
                    {
                        "name": "Function escapes",
                        "content": "A function escape is specified as `%(function)'.  All functions are built-in, and most have a\nstring or integer value.  A function escape may take an argument.  The argument  follows  the\nfunction escape (and any separating whitespace is discarded) as in the following example:\n\n%(function argument)\n\nIn  addition  to literal numbers or strings, the argument to a function escape can be another\nfunction, or a component, or a control escape.  When the argument is a function or  a  compo‐\nnent,  the  argument  is specified without a leading `%'.  When the argument is a control es‐\ncape, it is specified with a leading `%'.\n"
                    },
                    {
                        "name": "Control escapes",
                        "content": "A control escape is one of: `%<', `%?', `%|', or `%>'.  These are combined  into  the  condi‐\ntional execution construct:\n\n%< condition format-text\n%? condition format-text\n...\n%| format-text\n%>\n\n(Extra  white  space  is shown here only for clarity.)  These constructs, which may be nested\nwithout ambiguity, form a general if-elseif-else-endif block where only one  of  the  format-\ntexts is interpreted.  In other words, `%<' is like the \"if\", `%?' is like the \"elseif\", `%|'\nis like \"else\", and `%>' is like \"endif\".\n\nA `%<' or `%?' control escape causes its condition to be evaluated.  This condition is a com‐\nponent or function.  For components and functions whose value is an integer, the condition is\ntrue if it is non-zero, and false if zero.  For components and functions  whose  value  is  a\nstring, the condition is true it is a non-empty string, and false if an empty string.\n\nThe  `%?'  control escape is optional, and can be used multiple times in a conditional block.\nThe `%|' control escape is also optional, but may only be used once.\n"
                    },
                    {
                        "name": "Function escapes",
                        "content": "Functions expecting an argument generally require an argument of a particular type.  In addi‐\ntion to the integer and string types, these include:\n\nArgument Description            Example Syntax\nliteral  A literal number       %(func 1234)\nor string              %(func text string)\ncomp     Any component          %(func{in-reply-to})\ndate     A date component       %(func{date})\naddr     An address component   %(func{from})\nexpr     Nothing                %(func)\nor a subexpression     %(func(func2))\nor control escape      %(func %<{reply-to}%|%{from}%>)\n\nThe  date  and  addr  types  have  the same syntax as the component type, comp, but require a\nheader component which is a date, or address, string, respectively.\n\nMost arguments not of type expr are required.  When escapes are nested (via expr  arguments),\nevaluation  is done from innermost to outermost.  As noted above, for the expr argument type,\nfunctions and components are written without a leading `%'.  Control  escape  arguments  must\nuse a leading `%', preceded by a space.\n\nFor example,\n\n%<(mymbox{from}) To: %{to}%>\n\nwrites   the   value of the header component “From:” to the internal register named str; then\n(mymbox) reads str and writes its result to the internal register named num; then the control\nescape, `%<', evaluates num.  If num is non-zero, the string “To:” is printed followed by the\nvalue of the header component “To:”.\n"
                    },
                    {
                        "name": "Evaluation",
                        "content": "The evaluation of format strings is performed by a small virtual machine.  The machine is ca‐\npable  of evaluating nested expressions (as described above) and, in addition, has an integer\nregister num, and a text string register str.  When a function escape  that  accepts  an  op‐\ntional  argument  is  processed, and the argument is not present, the current value of either\nnum or str is substituted as the argument: the register used  depends  on  the  function,  as\nlisted below.\n\nComponent  escapes  write  the  value of their message header in str.  Function escapes write\ntheir return value in num for functions returning integer or boolean values, and in  str  for\nfunctions  returning  string  values.   (The boolean type is a subset of integers, with usual\nvalues 0=false and 1=true.)  Control escapes return a boolean value, setting num to 1 if  the\nlast  explicit  condition  evaluated by a `%<' or `%?' control escape succeeded, and 0 other‐\nwise.\n\nAll component escapes, and those function escapes which return an integer  or  string  value,\nevaluate to their value as well as setting str or num.  Outermost escape expressions in these\nforms will print their value, but outermost escapes which return a boolean value do  not  re‐\nsult in printed output.\n"
                    },
                    {
                        "name": "Functions",
                        "content": "The function escapes may be roughly grouped into a few categories.\n\nFunction    Argument Return   Description\nmsg                  integer  message number\ncur                  integer  message is current (0 or 1)\nunseen               integer  message is unseen (0 or 1)\nsize                 integer  size of message\nstrlen               integer  length of str\nwidth                integer  column width of terminal\ncharleft             integer  bytes left in output buffer\ntimenow              integer  seconds since the Unix epoch\nme                   string   the user's mailbox (username)\nmyhost               string   the user's local hostname\nmyname               string   the user's name\nlocalmbox            string   the complete local mailbox\neq          literal  boolean  num == arg\nne          literal  boolean  num != arg\ngt          literal  boolean  num > arg\nmatch       literal  boolean  str contains arg\namatch      literal  boolean  str starts with arg\nplus        literal  integer  arg plus num\nminus       literal  integer  arg minus num\nmultiply    literal  integer  num multiplied by arg\ndivide      literal  integer  num divided by arg\nmodulo      literal  integer  num modulo arg\nnum         literal  integer  Set num to arg.\nnum                  integer  Set num to zero.\nlit         literal  string   Set str to arg.\nlit                  string   Clear str.\ngetenv      literal  string   Set str to environment value of arg\nprofile     literal  string   Set str to profile component arg\nvalue\nnonzero     expr     boolean  num is non-zero\nzero        expr     boolean  num is zero\nnull        expr     boolean  str is empty\nnonnull     expr     boolean  str is non-empty\nvoid        expr              Set str or num\ncomp        comp     string   Set str to component text\ncompval     comp     integer  Set num to “atoi(comp)”\ndecode      expr     string   decode str as RFC 2047 (MIME-encoded)\ncomponent\nunquote     expr     string   remove RFC 2822 quotes from str\ntrim        expr              trim trailing whitespace from str\nkilo        expr     string   express in SI units: 15.9K, 2.3M, etc.\n%(kilo) scales by factors of 1000,\nkibi        expr     string   express in IEC units: 15.5Ki, 2.2Mi.\n%(kibi) scales by factors of 1024.\nputstr      expr              print str\nputstrf     expr              print str in a fixed width\nputnum      expr              print num\nputnumf     expr              print num in a fixed width\nputlit      expr              print str without space compression\nzputlit     expr              print str without space compression;\nstr must occupy no width on display\nbold                 string   set terminal bold mode\nunderline            string   set terminal underlined mode\nstandout             string   set terminal standout mode\nresetterm            string   reset all terminal attributes\nhascolor             boolean  terminal supports color\nfgcolor     literal  string   set terminal foreground color\nbgcolor     literal  string   set terminal background color\nformataddr  expr              append arg to str as a\n(comma separated) address list\nconcataddr  expr              append arg to str as a\n(comma separated) address list,\nincluding duplicates,\nsee Special Handling\nputaddr     literal           print str address list with\narg as optional label;\nget line width from num\n\nThe  (me)  function  returns the username of the current user.  The (myhost) function returns\nthe localname entry in mts.conf, or the local hostname if localname is not  configured.   The\n(myname)  function will return the value of the SIGNATURE environment variable if set, other‐\nwise it will return the passwd GECOS field (truncated at the first comma if it contains  one)\nfor  the  current  user.  The (localmbox) function will return the complete form of the local\nmailbox, suitable for use in a “From” header.  It will return the “Local-Mailbox” profile en‐\ntry if there is one; if not, it will be equivalent to:\n\n%(myname) <%(me)@%(myhost)>\n\nThe following functions require a date component as an argument:\n\nFunction    Argument Return   Description\nsec         date     integer  seconds of the minute\nmin         date     integer  minutes of the hour\nhour        date     integer  hours of the day (0-23)\nwday        date     integer  day of the week (Sun=0)\nday         date     string   day of the week (abbrev.)\nweekday     date     string   day of the week\nsday        date     integer  day of the week known?\n(1=explicit,0=implicit,-1=unknown)\nmday        date     integer  day of the month\nyday        date     integer  day of the year\nmon         date     integer  month of the year\nmonth       date     string   month of the year (abbrev.)\nlmonth      date     string   month of the year\nyear        date     integer  year (may be > 100)\nzone        date     integer  timezone in minutes\ntzone       date     string   timezone string\nszone       date     integer  timezone explicit?\n(1=explicit,0=implicit,-1=unknown)\ndate2local  date              coerce date to local timezone\ndate2gmt    date              coerce date to GMT\ndst         date     integer  daylight savings in effect? (0 or 1)\nclock       date     integer  seconds since the Unix epoch\nrclock      date     integer  seconds prior to current time\ntws         date     string   official RFC 822 rendering\npretty      date     string   user-friendly rendering\nnodate      date     integer  returns 1 if date is invalid\n\nThe  following  functions  require  an address component as an argument.  The return value of\nfunctions noted with `*' is computed from the first address present in the header component.\n\nFunction    Argument Return   Description\nproper      addr     string   official RFC 822 rendering\nfriendly    addr     string   user-friendly rendering\naddr        addr     string   mbox@host or host!mbox rendering*\npers        addr     string   the personal name*\nnote        addr     string   commentary text*\nmbox        addr     string   the local mailbox*\nmymbox      addr     integer  list has the user's address? (0 or 1)\ngetmymbox   addr     string   the user's (first) address,\nwith personal name\ngetmyaddr   addr     string   the user's (first) address,\nwithout personal name\nhost        addr     string   the host domain*\nnohost      addr     integer  no host was present (0 or 1)*\ntype        addr     integer  host type* (0=local,1=network,\n-1=uucp,2=unknown)\npath        addr     string   any leading host route*\ningrp       addr     integer  address was inside a group (0 or 1)*\ngname       addr     string   name of group*\n\n(A clarification on (mymbox{comp}) is in order.  This function checks each of  the  addresses\nin the header component “comp” against the user's mailbox name and any “Alternate-Mailboxes”.\nIt returns true if any address matches. However, it also returns true if the “comp” header is\nnot  present  in  the message.  If needed, the (null) function can be used to explicitly test\nfor this case.)\n"
                    },
                    {
                        "name": "Formatting",
                        "content": "When a function or component escape is interpreted and the result  will  be  printed  immedi‐\nately,  an optional field width can be specified to print the field in exactly a given number\nof characters.  For example, a numeric escape like %4(size) will print at most  4  digits  of\nthe message size; overflow will be indicated by a `?' in the first position (like `?234').  A\nstring escape like %4(me) will print the first 4 characters and truncate at the  end.   Short\nfields  are  padded  at  the right with the fill character (normally, a blank).  If the field\nwidth argument begins with a leading zero, then the fill character is set to a zero.\n\nThe functions (putnumf) and (putstrf) print their result in exactly the number of  characters\nspecified  by their leading field width argument.  For example, %06(putnumf(size)) will print\nthe message size in a field six characters wide filled with leading zeros; %14(putstrf{from})\nwill  print the “From:” header component in fourteen characters with trailing spaces added as\nneeded.  Using a negative value for the field width  causes  right-justification  within  the\nfield,  with  padding on the left up to the field width.  Padding is with spaces except for a\nleft-padded putnumf when the width starts with zero.  The functions (putnum) and (putstr) are\nsomewhat  special:  they print their result in the minimum number of characters required, and\nignore any leading field width argument.  The (putlit) function outputs the exact contents of\nthe  str  register  without  any changes such as duplicate space removal or control character\nconversion.  Similarly, the (zputlit) function outputs the exact contents of the  str  regis‐\nter,  but requires that those contents not occupy any output width.  It can therefore be used\nfor outputting terminal escape sequences.\n\nThere are a limited number of function escapes to output terminal  escape  sequences.   These\nsequences  are retrieved from the terminfo(5) database according to the current terminal set‐\nting.  The (bold), (underline), and (standout) escapes set bold  mode,  underline  mode,  and\nstandout mode respectively.  (hascolor) can be used to determine if the current terminal sup‐\nports color.  (fgcolor) and (bgcolor) set the foreground and background colors  respectively.\nBoth  of these escapes take one literal argument, the color name, which can be one of: black,\nred, green, yellow, blue, magenta, cyan, white.  (resetterm) resets all  terminal  attributes\nto  their  default setting.  These terminal escapes should be used in conjunction with (zput‐\nlit) (preferred) or (putlit), as the normal (putstr) function will strip out control  charac‐\nters.\n\nThe  available  output width is kept in an internal register; any output exceeding this width\nwill be truncated.  The one exception to this is that (zputlit) functions will still be  exe‐\ncuted if a terminal reset code is being placed at the end of a line.\n"
                    },
                    {
                        "name": "Special Handling",
                        "content": "Some functions have different behavior depending on the command they are invoked from.\n\nIn  repl  the  (formataddr)  function stores all email addresses encountered into an internal\ncache and will use this cache to suppress duplicate addresses.  If you need to create an  ad‐\ndress  list  that  includes  previously-seen addresses you may use the (concataddr) function,\nwhich is identical to (formataddr) in all other respects.  Note that  (concataddr)  does  not\nadd addresses to the duplicate-suppression cache.\n"
                    },
                    {
                        "name": "Other Hints and Tips",
                        "content": "Sometimes,  the  writer  of  a format function is confused because output is duplicated.  The\ngeneral rule to remember is simple: If a function or component escape begins with a  `%',  it\nwill generate text in the output file.  Otherwise, it will not.\n\nA  good example is a simple attempt to generate a To: header based on the From: and Reply-To:\nheaders:\n\n%(formataddr %<{reply-to}%|%{from})%(putaddr To: )\n\nUnfortunately, if the Reply-to: header is not present, the  output  line  will  be  something\nlike:\n\nMy From User <from@example.com>To: My From User <from@example.com>\n\nWhat  went wrong?  When performing the test for the if clause (%<), the component is not out‐\nput because it is considered an argument to the if statement (so the rule about not  starting\nwith  % applies).  But the component escape in our else statement (everything after the `%|')\nis not an argument to anything; it begins with a %, and thus the value of that  component  is\noutput.   This also has the side effect of setting the str register, which is later picked up\nby the (formataddr) function and then output by (putaddr).  The example format  string  above\nhas  another  bug:  there  should  always  be  a  valid  width value in the num register when\n(putaddr) is called, otherwise bad formatting can take place.\n\nThe solution is to use the (void) function; this will prevent the function or component  from\noutputting  any  text.  With this in place (and using (width) to set the num register for the\nwidth) a better implementation would look like:\n\n%(formataddr %<{reply-to}%|%(void{from})%(void(width))%(putaddr To: )\n\nIt should be noted here that the side effects of function and component escapes are still  in\nforce  and,  as a result, each component test in the if-elseif-else-endif clause sets the str\nregister.\n\nAs an additional note, the (formataddr) and (concataddr) functions have special behavior when\nit  comes  to  the  str register.  The starting point of the register is saved and is used to\nbuild up entries in the address list.\n\nYou will find the fmttest(1) utility invaluable when debugging problems with format strings.\n"
                    },
                    {
                        "name": "Examples",
                        "content": "With all the above in mind, here is a breakdown of the default format string for  scan.   The\nfirst part is:\n\n%4(msg)%<(cur)+%| %>%<{replied}-%?{encrypted}E%| %>\n\nwhich  says  that the message number should be printed in four digits.  If the message is the\ncurrent message then a `+', else a space, should be printed; if a “Replied:” field is present\nthen  a  `-', else if an “Encrypted:” field is present then an `E', otherwise a space, should\nbe printed.  Next:\n\n%02(mon{date})/%02(mday{date})\n\nthe month and date are printed in two digits (zero filled) separated by a slash.  Next,\n\n%<{date} %|*%>\n\nIf a “Date:” field is present it is printed, followed by a space; otherwise a `*' is printed.\nNext,\n\n%<(mymbox{from})%<{to}To:%14(decode(friendly{to}))%>%>\n\nif  the  message  is  from  me, and there is a “To:” header, print “To:” followed by a “user-\nfriendly” rendering of the first address in the “To:” field; any MIME-encoded characters  are\ndecoded into the actual characters.  Continuing,\n\n%<(zero)%17(decode(friendly{from}))%>\n\nif  either  of  the above two tests failed, then the “From:” address is printed in a mime-de‐\ncoded, “user-friendly” format.  And finally,\n\n%(decode{subject})%<{body}<<%{body}>>%>\n\nthe mime-decoded subject and initial body (if any) are printed.\n\nFor a more complicated example, consider a possible replcomps format file.\n\n%(lit)%(formataddr %<{reply-to}\n\nThis clears str and formats the “Reply-To:” header if present.  If not present,  the  else-if\nclause is executed.\n\n%?{from}%?{sender}%?{return-path}%>)\\\n\nThis  formats  the  “From:”, “Sender:” and “Return-Path:” headers, stopping as soon as one of\nthem is present.  Next:\n\n%<(nonnull)%(void(width))%(putaddr To: )\\n%>\\\n\nIf the formataddr result is non-null, it is printed as  an  address  (with  line  folding  if\nneeded) in a field width wide, with a leading label of “To:”.\n\n%(lit)%(formataddr{to})%(formataddr{cc})%(formataddr(me))\\\n\nstr  is cleared, and the “To:” and “Cc:” headers, along with the user's address (depending on\nwhat was specified with the “-cc” switch to repl) are formatted.\n\n%<(nonnull)%(void(width))%(putaddr cc: )\\n%>\\\n\nIf the result is non-null, it is printed as above with a leading label of “cc:”.\n\n%<{fcc}Fcc: %{fcc}\\n%>\\\n\nIf a -fcc folder switch was given to repl (see repl(1) for more  details  about  %{fcc}),  an\n“Fcc:” header is output.\n\n%<{subject}Subject: Re: %{subject}\\n%>\\\n\nIf a subject component was present, a suitable reply subject is output.\n\n%<{message-id}In-Reply-To: %{message-id}\\n%>\\\n%<{message-id}References: %<{references} %{references}%>\\\n%{message-id}\\n%>\n--------\n\nIf  a message-id component was present, an “In-Reply-To:” header is output including the mes‐\nsage-id, followed by a “References:” header with references, if present, and the  message-id.\nAs with all plain-text, the row of dashes are output as-is.\n\nThis  last  part  is a good example for a little more elaboration.  Here's that part again in\npseudo-code:\n\nif (compexists(message-id))  then\nprint (“In-reply-to: ”)\nprint (message-id.value)\nprint (“\\n”)\nendif\nif (compexists(message-id)) then\nprint (“References: ”)\nif (compexists(references)) then\nprint(references.value);\nendif\nprint (message-id.value)\nprint (“\\n”)\nendif\n\nOne more example: Currently, nmh supports very large message numbers, and it is not  uncommon\nfor  a folder to have far more than 10000 messages.  Nonetheless (as noted above) the various\nscan format strings, inherited from older MH versions, are generally hard-coded to  4  digits\nfor the message number. Thereafter, formatting problems occur.  The nmh format strings can be\nmodified to behave more sensibly with larger message numbers:\n\n%(void(msg))%<(gt 9999)%(msg)%|%4(msg)%>\n\nThe current message number is placed in num.  (Note that (msg) is a function escape which re‐\nturns  an  integer, it is not a component.)  The (gt) conditional is used to test whether the\nmessage number has 5 or more digits.  If so, it is printed at full width, otherwise at 4 dig‐\nits.\n"
                    }
                ]
            },
            "SEE ALSO": {
                "content": "scan(1), repl(1), fmttest(1),\n",
                "subsections": []
            },
            "CONTEXT": {
                "content": "None\n\n\n\nnmh-1.7.1                                    2015-01-10                               MH-FORMAT(5mh)",
                "subsections": []
            }
        }
    }
}