MH-FORMAT(5)	      [mh.6] (MH.6.8)		  MH-FORMAT(5)

     NAME
	  mh-format - format file for MH message system

     SYNOPSIS
	  some MH commands

     DESCRIPTION
	  Several MH 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 MH
	  which	means they are not necessarily simple to write and
	  understand.  This means that novice, casual, or even
	  advanced users of MH should not have to deal with them.
	  Some canned scan listing formats are in
	  /usr/local/lib/mh/scan.time, /usr/local/lib/mh/scan.size,
	  and /usr/local/lib/mh/scan.timely.  Look in
	  /usr/local/lib/mh for	other scan and repl format files which
	  may have been	written	at your	site.

	  It suffices to have your local MH 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 components, built-in functions, and flow
	  control.

	  A component escape is	specified as `%{component}', and
	  exists for each header found in the message being processed.
	  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 interpretations 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.

     Page 1					     (printed 9/30/94)

     MH-FORMAT(5)	      [mh.6] (MH.6.8)		  MH-FORMAT(5)

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

	       %<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 component
	  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; normal
	  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
	  interpreted.	If the control escape encountered was `%?',
	  then the condition associated	with that control escape is
	  evaluated, 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.

     Page 2					     (printed 9/30/94)

     MH-FORMAT(5)	      [mh.6] (MH.6.8)		  MH-FORMAT(5)

	  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.

	Function escapes
	  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 arguments.

	  The evaluation of format strings is based on a simple
	  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 present, it
	  reads	the current value of either num	or str as appropriate.

	Return values
	  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

     Page 3					     (printed 9/30/94)

     MH-FORMAT(5)	      [mh.6] (MH.6.8)		  MH-FORMAT(5)

	  msg		      integer  message number
	  cur		      integer  message is current
	  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
	  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  num set to atoi(comp)
	  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

     Page 4					     (printed 9/30/94)

     MH-FORMAT(5)	      [mh.6] (MH.6.8)		  MH-FORMAT(5)

	  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 argument.
	  The return value of functions	noted with `*' pertain only to
	  the first address present in the header component.

	  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

     Page 5					     (printed 9/30/94)

     MH-FORMAT(5)	      [mh.6] (MH.6.8)		  MH-FORMAT(5)

	  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 character (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 register;
	  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
	  readability.	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)

     Page 6					     (printed 9/30/94)

     MH-FORMAT(5)	      [mh.6] (MH.6.8)		  MH-FORMAT(5)

	  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 present.
	  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})%(formataddr(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: .

     Page 7					     (printed 9/30/94)

     MH-FORMAT(5)	      [mh.6] (MH.6.8)		  MH-FORMAT(5)

	       %<{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	output.

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

	  If a subject component was present, a	suitable reply subject
	  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 format, 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
	  elaboration.	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.

     FILES
	  None

     PROFILE COMPONENTS
	  None

     SEE ALSO
	  scan(1), repl(1), ap(8), dp(8)

     Page 8					     (printed 9/30/94)

     MH-FORMAT(5)	      [mh.6] (MH.6.8)		  MH-FORMAT(5)

     DEFAULTS
	  None

     CONTEXT
	  None

     HISTORY
	  This software	was contributed	for MH 6.3.  Prior to this,
	  output format	specifications were much easier	to write, but
	  considerably less flexible.

     BUGS
	  On hosts where MH was	configured with	the BERK option,
	  address parsing is not enabled.

     Page 9					     (printed 9/30/94)