]> diplodocus.org Git - nmh/commitdiff
Merge branch 'format-test'
authorKen Hornstein <kenh@pobox.com>
Fri, 22 Feb 2013 03:40:48 +0000 (22:40 -0500)
committerKen Hornstein <kenh@pobox.com>
Fri, 22 Feb 2013 03:40:48 +0000 (22:40 -0500)
1  2 
.gitignore
Makefile.am
docs/README.manpages
sbr/fmt_compile.c
sbr/fmt_scan.c
uip/forwsbr.c
uip/mhlsbr.c
uip/rcvdist.c
uip/replsbr.c
uip/scansbr.c

diff --combined .gitignore
index bc20fbc489c18649cec3b02b6c5f15448d7f12f1,ebf140c2f116e2f73d53ad7d45549ab0c22067f1..8d7e69d79e4856722d0c0ce2a70da10c75d14f5d
@@@ -41,7 -41,6 +41,7 @@@
  /RPM/
  a.out.dSYM/
  /config/version.c
 +/etc/gen-ctype-checked
  /etc/mhn.defaults
  /etc/mts.conf
  /man/*.[1578]
@@@ -49,7 -48,6 +49,7 @@@
  /man/mh-chart.man
  /mts/libmts.a
  /sbr/*.a
 +/sbr/ctype-checked.*
  /sbr/sigmsg.h
  /test/testdir/
  /uip/ali
@@@ -62,6 -60,7 +62,7 @@@
  /uip/dp
  /uip/flist
  /uip/fmtdump
+ /uip/fmttest
  /uip/folder
  /uip/forw
  /uip/inc
  /test/fakepop
  /test/getfullname
  /test/getfqdn
 +/test/getcwidth
  
  # Removed by mostlyclean:
  *.o
diff --combined Makefile.am
index 48b2ba8053186b579341e8650379c22f359c0d0c,7e93a12a2c1825416ca023f0fa9a150bcd31c7d3..3654eab7404b9b5e850957822ac2a820f571bbb3
@@@ -14,7 -14,7 +14,7 @@@ ACLOCAL_AMFLAGS = -I m
  ## LDADD is included in the program-specific LDADD since we want to add
  ## to this list of libraries, not replace it.
  ##
 -LDADD = sbr/libmh.a sbr/libdtimep.a
 +LDADD = sbr/libmh.a
  
  ##
  ## These are used to create the default mhn.defaults config file
@@@ -38,14 -38,13 +38,14 @@@ TESTS_ENVIRONMENT = MH_OBJ_DIR="@abs_bu
                    auxexecdir="$(auxexecdir)" bindir="$(bindir)" \
                    mandir="$(mandir)" sysconfdir="$(sysconfdir)" \
                    MULTIBYTE_ENABLED=$(MULTIBYTE_ENABLED) \
 +                  ICONV_ENABLED=$(ICONV_ENABLED) \
                    $(TESTS_SHELL) ## Keep at end of TESTS_ENVIRONMENT.
  ##
  ## Important note: the "cleanup" test should always be last
  ##
  TESTS = test/ali/test-ali test/anno/test-anno \
        test/bad-input/test-header \
 -      test/burst/test-burst \
 +      test/burst/test-burst test/burst/test-burst-mime \
        test/comp/test-comp-format test/dist/test-dist \
        test/folder/test-create test/folder/test-packf \
        test/folder/test-recurse test/folder/test-sortm \
@@@ -53,7 -52,6 +53,7 @@@
        test/format/test-dp test/format/test-fmtdump \
        test/format/test-localmbox test/format/test-myname \
        test/format/test-myhost test/format/test-mymbox \
 +      test/format/test-rightjustify \
        test/forw/test-forw-digest test/forw/test-forw-format \
        test/inc/test-deb359167 test/inc/test-eom-align \
        test/inc/test-inc-scanout test/inc/test-msgchk \
@@@ -63,8 -61,8 +63,8 @@@
        test/mhlist/test-mhlist test/mhmail/test-mhmail \
        test/mhparam/test-mhparam test/mhpath/test-mhpath \
        test/mhshow/test-cte-binary test/mhshow/test-qp \
 -      test/mhshow/test-subpart test/mhstore/test-mhstore \
 -      test/new/test-basic \
 +      test/mhshow/test-subpart test/mhshow/test-msg-buffer-boundaries \
 +      test/mhstore/test-mhstore test/new/test-basic \
        test/pick/test-pick test/pick/test-stderr \
        test/post/test-post-aliases test/post/test-post-basic \
        test/post/test-post-multiple test/post/test-post-bcc \
        test/cleanup ## The "cleanup" test should always be last.
  
  check_SCRIPTS = test/common.sh
 -check_PROGRAMS = test/getfullname test/getfqdn test/fakepop test/fakesmtp
 +check_PROGRAMS = test/getfullname test/getfqdn test/fakepop test/fakesmtp \
 +               test/getcwidth
  DISTCHECK_CONFIGURE_FLAGS = DISABLE_SETGID_MAIL=1
  
  ##
  ## Stuff that should be cleaned via "make clean"
  ##
  CLEANFILES = config/version.c sbr/sigmsg.h etc/mts.conf \
 +           etc/gen-ctype-checked sbr/ctype-checked.h sbr/ctype-checked.c \
             etc/mhn.defaults man/man.sed man/mh-chart.man $(man_MANS)
  clean-local:
        @rm -rf RPM a.out.dSYM uip/a.out.dSYM
@@@ -117,7 -113,7 +117,7 @@@ superclean: maintainer-clea
  ##
  ## Files that need to be built before everything else
  ##
 -BUILT_SOURCES = sbr/sigmsg.h
 +BUILT_SOURCES = sbr/sigmsg.h sbr/ctype-checked.c
  
  ##
  ## This is a list of all programs that get installed in the "bin" directory
  ## the latter do not have $(EXEEXT) added on the end.
  ##
  bin_PROGRAMS = uip/ali uip/anno uip/burst uip/comp uip/dist uip/flist \
-              uip/folder uip/forw uip/inc uip/install-mh uip/mark \
-              uip/mhbuild uip/mhlist uip/mhn uip/mhparam \
+              uip/fmttest uip/folder uip/forw uip/inc uip/install-mh \
+              uip/mark uip/mhbuild uip/mhlist uip/mhn uip/mhparam \
               uip/mhpath uip/mhshow uip/mhstore uip/msgchk uip/msh uip/new \
               uip/packf uip/pick uip/prompter uip/refile uip/repl uip/rmf \
               uip/rmm uip/scan uip/send uip/show uip/sortm uip/whatnow \
@@@ -143,18 -139,11 +143,18 @@@ auxexec_PROGRAMS = uip/ap uip/conflict 
  
  auxexec_SCRIPTS = uip/spost
  
 +##
 +## Programs that MAY need to get built at some point; we need to list them
 +## here if they don't appear in any other primary so Automake knows about
 +## them and can properly record dependency information.
 +##
 +EXTRA_PROGRAMS = etc/gen-ctype-checked
 +
  ##
  ## Internal libraries that we create as part of the build process
  ## but do not install
  ##
 -noinst_LIBRARIES = sbr/libmh.a sbr/libdtimep.a mts/libmts.a
 +noinst_LIBRARIES = sbr/libmh.a mts/libmts.a
  
  ##
  ## These are all of our header files.  Right now we don't install any of
@@@ -165,7 -154,7 +165,7 @@@ noinst_HEADERS = h/addrsbr.h h/aliasbr.
                 h/mh.h h/mhcachesbr.h h/mhparse.h h/mime.h h/msh.h \
                 h/mts.h h/nmh.h h/picksbr.h h/popsbr.h h/prototypes.h \
                 h/rcvmail.h h/scansbr.h h/signals.h h/tws.h h/utils.h \
 -               h/vmhsbr.h mts/smtp/smtp.h
 +               h/vmhsbr.h mts/smtp/smtp.h sbr/ctype-checked.h
  
  ##
  ## Extra files we need to install in various places
@@@ -208,7 -197,7 +208,7 @@@ dist_contrib_DATA = docs/contrib/replyf
  ##
  man_MANS = man/ali.1 man/anno.1 man/ap.8 man/burst.1 man/comp.1 \
           man/conflict.8 man/dist.1 man/dp.8 man/flist.1 man/flists.1 \
-          man/fmtdump.8 man/fnext.1 man/folder.1 man/folders.1 \
+          man/fmtdump.8 man/fmttest.1 man/fnext.1 man/folder.1 man/folders.1 \
           man/forw.1 man/fprev.1 man/inc.1 man/install-mh.1 man/mark.1 \
           man/mh-alias.5 man/mh-chart.7 man/mh-draft.5 man/mh-format.5 \
           man/mh-mail.5 man/mh-profile.5 man/mh_profile.5 man/mh-sequence.5 \
  ##
  man_SRCS = man/ali.man man/anno.man man/ap.man man/burst.man man/comp.man \
           man/conflict.man man/dist.man man/dp.man man/flist.man \
-          man/flists.man man/fmtdump.man man/fnext.man man/folder.man \
-          man/folders.man man/forw.man man/fprev.man man/inc.man \
-          man/install-mh.man man/mark.man man/mh-alias.man \
+          man/flists.man man/fmtdump.man man/fmttest.man man/fnext.man \
+          man/folder.man man/folders.man man/forw.man man/fprev.man
+          man/inc.man man/install-mh.man man/mark.man man/mh-alias.man \
           man/mh-chart-gen.sh man/mh-draft.man man/mh-format.man \
           man/mh-mail.man man/mh-profile.man man/mh_profile.man \
           man/mh-sequence.man man/mh-tailor.man man/mhbuild.man man/mhl.man \
@@@ -267,8 -256,7 +267,8 @@@ uip_ali_SOURCES = uip/ali.c uip/aliasbr
  
  uip_anno_SOURCES = uip/anno.c uip/annosbr.c
  
 -uip_burst_SOURCES = uip/burst.c
 +uip_burst_SOURCES = uip/burst.c uip/mhparse.c uip/mhmisc.c uip/mhfree.c \
 +                  uip/mhcachesbr.c uip/md5.c
  
  uip_comp_SOURCES = uip/comp.c uip/whatnowproc.c uip/whatnowsbr.c uip/sendsbr.c \
                   uip/annosbr.c uip/distsbr.c
@@@ -380,6 -368,9 +380,9 @@@ uip_dp_LDADD = $(LDADD) $(TERMLIB) $(IC
  uip_fmtdump_SOURCES = uip/fmtdump.c
  uip_fmtdump_LDADD = $(LDADD) $(ICONVLIB)
  
+ uip_fmttest_SOURCES = uip/fmttest.c uip/termsbr.c
+ uip_fmttest_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB)
  uip_mhl_SOURCES = uip/mhl.c uip/mhlsbr.c uip/termsbr.c
  uip_mhl_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB)
  
@@@ -419,12 -410,6 +422,12 @@@ test_fakepop_LDADD 
  test_fakesmtp_SOURCES = test/fakesmtp.c
  test_fakesmtp_LDADD =
  
 +test_getcwidth_SOURCES = test/getcwidth.c
 +test_getcwidth_LDADD =
 +
 +etc_gen_ctype_checked_SOURCES = etc/gen-ctype-checked.c
 +etc_gen_ctype_checked_LDADD =
 +
  ##
  ## Our rebuild rules for files that aren't built via the normal mechanisms
  ##
@@@ -434,11 -419,6 +437,11 @@@ config/version.c: Makefil
  sbr/sigmsg.h: $(srcdir)/sbr/sigmsg.awk $(SIGNAL_H)
        $(AWK) -f $(srcdir)/sbr/sigmsg.awk $(SIGNAL_H) > $@
  
 +sbr/ctype-checked.h: etc/gen-ctype-checked
 +      etc/gen-ctype-checked
 +
 +sbr/ctype-checked.c: etc/gen-ctype-checked sbr/ctype-checked.h
 +
  etc/mts.conf: $(srcdir)/etc/mts.conf.in Makefile
        @rm -f $@
        $(SED) -e 's,%mts%,$(MTS),' \
@@@ -503,8 -483,7 +506,8 @@@ sbr_libmh_a_SOURCES = sbr/addrsbr.c sbr
                      sbr/context_replace.c sbr/context_save.c \
                      sbr/copy.c sbr/copyip.c sbr/cpydata.c \
                      sbr/cpydgst.c sbr/crawl_folders.c sbr/discard.c \
 -                    sbr/done.c sbr/dtime.c sbr/escape_addresses.c \
 +                    sbr/done.c sbr/dtimep.l sbr/dtime.c \
 +                    sbr/escape_addresses.c \
                      sbr/error.c sbr/ext_hook.c sbr/fdcompare.c \
                      sbr/folder_addmsg.c sbr/folder_delmsgs.c \
                      sbr/folder_free.c sbr/folder_pack.c \
                      sbr/showfile.c sbr/signals.c sbr/smatch.c \
                      sbr/snprintb.c sbr/ssequal.c sbr/strcasecmp.c \
                      sbr/strindex.c sbr/trimcpy.c sbr/uprf.c sbr/vfgets.c \
 -                    sbr/fmt_def.c sbr/m_msgdef.c sbr/mf.c sbr/utils.c \
 +                    sbr/fmt_def.c sbr/mf.c sbr/utils.c sbr/ctype-checked.c \
                      sbr/m_mktemp.c sbr/getansreadline.c config/config.c \
                      config/version.c
  
@@@ -539,6 -518,11 +542,6 @@@ sbr_libmh_a_CPPFLAGS = -I./sbr -DNMHETC
                -DSENDMAILPATH='"$(sendmailpath)"' -DNMHBINDIR='"$(bindir)"' \
                -DNMHLIBDIR='"$(libdir)"'
  
 -sbr_libdtimep_a_SOURCES = sbr/dtimep.l
 -sbr_libdtimep_a_CFLAGS = $(sbr_libmh_a_CPPFLAGS) \
 -                       $(DISABLE_UNUSED_MACROS_WARNING) \
 -                       $(DISABLE_SIGN_COMPARE_WARNING)
 -
  mts_libmts_a_SOURCES = mts/smtp/smtp.c
  
  ##
@@@ -596,8 -580,8 +599,8 @@@ cleanman
  
  ## Don't include commit hashes in ChangeLog.
  ChangeLog:
 -      @[ -d .git ]  &&  git --no-pager log --abbrev-commit | \
 -           egrep -v '^commit [0-9a-f]+$$' > $@  ||  true
 +      @[ -d $(srcdir)/.git ]  &&  (cd $(srcdir); git --no-pager log --abbrev-commit | \
 +           egrep -v '^commit [0-9a-f]+$$' > $@)  ||  true
  ## Make ChangeLog phony so it will always get regenerated.  But don't
  ## fail if we don't have a git repository in order to allow
  ## regeneration of distribution archive or RPM.
diff --combined docs/README.manpages
index 6d6111df8eb7616b768bf9a02866613154b6938f,33693df31a7a173447d0043b1d89fafefff3dc21..6bb6636bc088c1c4e6d8e673574de13731078203
@@@ -1,6 -1,6 +1,6 @@@
  NMH MANPAGE STYLE GUIDE
  
 -nmh manpages should be in this general form:
 +nmh manpages should be in this general form and section order:
  
  .TH COMP %manext1% "DATE" "%nmhversion%"
  .\"
@@@ -8,8 -8,9 +8,10 @@@
  .\"
  .SH NAME
  comp \- compose a message
 +.\"
  .SH SYNOPSIS
+ .HP 5
+ .na
  .B comp 
  .RI [ +folder ]
  .RI [ msgs ]
  .RB [ \-use " | " \-nouse ]
  .RB [ \-version ]
  .RB [ \-help ]
+ .ad
  .SH DESCRIPTION
  .B Comp
  is used to create a new message to be mailed.  It copies something.
 -.SH FILES
 -.TP
 -filename1
 -description of filename1
 -.TP
 -filename2
 -description of filename2
 +.\"
  .SH "PROFILE COMPONENTS"
  .TP
  Path
@@@ -29,7 -37,13 +32,7 @@@ Location of the user's MH folder direct
  .TP
  moreproc
  The pager command name
 -.SH "SEE ALSO"
 -.IR dist (1),
 -.IR forw (1),
 -.IR repl (1),
 -.IR send (1),
 -.IR whatnow (1),
 -.IR mh-profile (5)
 +.\"
  .SH DEFAULTS
  .TP
  .RI + folder
@@@ -37,22 -51,6 +40,22 @@@ defaults to the current folde
  .\"
  .SH CONTEXT
  None
 +.\"
 +.SH FILES
 +.TP
 +filename1
 +description of filename1
 +.TP
 +filename2
 +description of filename2
 +.\"
 +.SH "SEE ALSO"
 +.IR dist (1),
 +.IR forw (1),
 +.IR repl (1),
 +.IR send (1),
 +.IR whatnow (1),
 +.IR mh-profile (5)
  .\" Leave out the BUGS section if there are none worth describing.
  .SH BUGS
  None
@@@ -73,7 -71,7 +76,7 @@@ Don't abbreviate the month
  
  In the FILES section, prefer the default .TP indent. The pathnames are
  variable and long, so any indentation value that works for you won't
 -work for someone else.
 +work for someone using a different directory layout.
  
  
  Source files
@@@ -204,8 -202,7 +207,8 @@@ Pointer manpage
        
  
  CONTEXT
 -    Don't include a CONTEXT section when contexts are out of context.
 +    Don't include a CONTEXT section when contexts are not
 +    applicable.
  
  
  AUTHOR and HISTORY sections
  
  BUGS
  
 -    The BUGS section goes last.
 +    The BUGS section goes last. 
diff --combined sbr/fmt_compile.c
index 4409e628323bfab20b8536e61fdc97ee6ee1b407,9ef3946748cf932b977fdfff2b734deda81f67c3..0fd83d1e47af8333e305bb6ee037416418e3f9c3
@@@ -270,7 -270,7 +270,7 @@@ static struct ftable functable[] = 
  #define PUTC(c)                       do { NEW(FT_CHAR,0,0); fp->f_char = (c); } while (0)
  
  static char *format_string;
 -static unsigned char *usr_fstring;    /* for CERROR */
 +static char *usr_fstring;     /* for CERROR */
  
  #define CERROR(str) compile_error (str, cp)
  
@@@ -321,7 -321,7 +321,7 @@@ compile_error(char *str, char *cp
  
      for (i = errpos-errctx; i < errpos; i++) {
  #ifdef LOCALE
 -      if (iscntrl(usr_fstring[i]))
 +      if (iscntrl((unsigned char) usr_fstring[i]))
  #else
        if (usr_fstring[i] < 32)
  #endif
@@@ -856,6 -856,24 +856,24 @@@ fmt_free(struct format *fmt, int reset_
        free_comptable();
  }
  
+ /*
+  * Free just the text strings from all of the component hash table entries
+  */
+ void
+ fmt_freecomptext(void)
+ {
+     unsigned int i;
+     struct comp *cm;
+     for (i = 0; i < sizeof(wantcomp)/sizeof(wantcomp[0]); i++)
+       for (cm = wantcomp[i]; cm; cm = cm->c_next)
+           if (cm->c_text) {
+               free(cm->c_text);
+               cm->c_text = NULL;
+           }
+ }
+       
  /*
   * Find a component in our hash table.  This is just a public interface to
   * the FINDCOMP macro, so we don't have to expose our hash table.
diff --combined sbr/fmt_scan.c
index 6cceff3266588ab15cc7b454cca6d34c4c040a29,e654b15e91a95fb9c5bdabae934e552a6f4ccc46..dad7a3c6a08c56700b2392a0af291bb548ceb928
@@@ -50,24 -50,13 +50,24 @@@ match (char *str, char *sub
  
  #ifdef LOCALE
      while ((c1 = *sub)) {
 -      c1 = (isalpha(c1) && isupper(c1)) ? tolower(c1) : c1;
 -      while ((c2 = *str++) && c1 != ((isalpha(c2) && isupper(c2)) ? tolower(c2) : c2))
 +      c1 = (isascii((unsigned char) c1) && isalpha((unsigned char) c1) &&
 +            isupper((unsigned char) c1)) ? tolower((unsigned char) c1) : c1;
 +      while ((c2 = *str++) && c1 != ((isascii((unsigned char) c2) &&
 +                                      isalpha((unsigned char) c2) &&
 +                                      isupper((unsigned char) c2)) ?
 +                                          tolower((unsigned char) c2) : c2))
            ;
        if (! c2)
            return 0;
        s1 = sub + 1; s2 = str;
 -      while ((c1 = *s1++) && ((isalpha(c1) && isupper(c1)) ? tolower(c1) : c1) == ((isalpha(c2 =*s2++) && isupper(c2)) ? tolower(c2) : c2))
 +      while ((c1 = *s1++) && ((isascii((unsigned char) c1) &&
 +                               isalpha((unsigned char) c1) &&
 +                               isupper((unsigned char) c1)) ?
 +                                      tolower(c1) : c1) ==
 +                      ((isascii((unsigned char) (c2 =*s2++)) &&
 +                        isalpha((unsigned char) c2) &&
 +                        isupper((unsigned char) c2)) ?
 +                              tolower((unsigned char) c2) : c2))
            ;
        if (! c1)
            return 1;
@@@ -125,8 -114,8 +125,8 @@@ cpnumber(char **dest, int num, unsigne
   * no more than n bytes are copied
   */
  static void
 -cptrimmed(char **dest, char *str, unsigned int wid, char fill, size_t n,
 -        size_t max) {
 +cptrimmed(char **dest, char **ep, char *str, unsigned int wid, char fill,
 +        char *epmax) {
      int remaining;     /* remaining output width available */
      int c, ljust;
      int end;           /* number of input bytes remaining in str */
  #endif
      char *sp;          /* current position in source string */
      char *cp = *dest;  /* current position in destination string */
 -    char *ep = cp + n; /* end of destination buffer based on desired width */
 -    char *epmax = cp + max; /* true end of destination buffer */
      int prevCtrl = 1;
  
      /* get alignment */
        ljust++;
      }
      if ((sp = (str))) {
 +#ifdef MULTIBYTE_SUPPORT
        mbtowc(NULL, NULL, 0); /* reset shift state */
 +#endif
        end = strlen(str);
        while (*sp && remaining > 0 && end > 0) {
  #ifdef MULTIBYTE_SUPPORT
            char_len = mbtowc(&wide_char, sp, end);
  
 -          /* Account for multibyte characters taking only one character's
 -             width of output. */
 -          if (char_len > 1  &&  epmax - ep >= char_len - 1) {
 -              ep += char_len - 1;
 +          if (char_len <= 0)
 +              break;
 +
 +          w = wcwidth(wide_char);
 +
 +          /*
 +           * Multibyte characters can have a variable number of column
 +           * widths, so use the column width to bump the end pointer when
 +           * appropriate.
 +           */
 +          if (char_len > 1 && epmax - *ep >= char_len - w) {
 +              *ep += char_len - w;
            }
  
 -          if (char_len <= 0 || (cp + char_len > ep))
 +          if (cp + w > *ep)
                break;
  
            end -= char_len;
            end--;
              /* isnctrl(), etc., take an int argument.  Cygwin's ctype.h
                 intentionally warns if they are passed a char. */
 -            c = *sp;
 +            c = (unsigned char) *sp;
            if (iscntrl(c) || isspace(c)) {
                sp++;
  #endif
            prevCtrl = 0;
  
  #ifdef MULTIBYTE_SUPPORT
 -          w = wcwidth(wide_char);
            if (w >= 0 && remaining >= w) {
                strncpy(cp, sp, char_len);
                cp += char_len;
      }
  
      if (ljust) {
 -      if (cp + remaining > ep)
 -          remaining = ep - cp;
 -      ep = cp + remaining;
 +        char *endfield;
 +      if (cp + remaining > *ep)
 +          remaining = *ep - cp;
 +      endfield = cp + remaining;
        if (remaining > 0) {
            /* copy string to the right */
            while (--cp >= *dest)
            for (c=remaining; c>0; c--)
                *cp-- = fill;
        }
 -      *dest = ep;
 +      *dest = endfield;
      } else {
        /* pad remaining space */
 -      while (remaining-- > 0 && cp < ep)
 +      while (remaining-- > 0 && cp < *ep)
                *cp++ = fill;
        *dest = cp;
      }
  }
  
  static void
 -cpstripped (char **dest, char *end, char *max, char *str)
 +cpstripped (char **dest, char **end, char *max, char *str)
  {
      int prevCtrl = 1; /* This is 1 so we strip out leading spaces */
      int len;
  #ifdef MULTIBYTE_SUPPORT
 -    int char_len;
 +    int char_len, w;
      wchar_t wide_char;
  #endif /* MULTIBYTE_SUPPORT */
  
       * then deal with that here.
       */
  
 -    while (*str != '\0' && len > 0 && *dest < end) {
 +    while (*str != '\0' && len > 0 && *dest < *end) {
  #ifdef MULTIBYTE_SUPPORT
        char_len = mbtowc(&wide_char, str, len);
 -
 -      /* Account for multibyte characters taking only one character's
 -         width of output. */
 -      if (char_len > 1  &&  max - end >= char_len - 1) {
 -          end += char_len - 1;
 +      w = wcwidth(wide_char);
 +
 +      /*
 +       * Account for multibyte characters, and increment the end pointer
 +       * by the number of "extra" bytes in this character.  That's the
 +       * character length (char_len) minus the column width (w).
 +       */
 +      if (char_len > 1  &&  max - *end >= char_len - w) {
 +          *end += char_len - w;
        }
  
 -      if (char_len <= 0 || *dest + char_len > end)
 +      if (char_len <= 0 || *dest + char_len > *end)
            break;
  
        len -= char_len;
        if (iswcntrl(wide_char) || iswspace(wide_char)) {
            str += char_len;
  #else /* MULTIBYTE_SUPPORT */
 -      int c = *str;
 +      int c = (unsigned char) *str;
        len--;
        if (iscntrl(c) || isspace(c)) {
            str++;
@@@ -351,10 -328,13 +351,11 @@@ get_x400_comp (char *mbox, char *key, c
  }
  
  struct format *
- fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat)
+ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat,
+         struct fmt_callbacks *callbacks)
  {
 -    char *cp, *ep;
 -    unsigned char *sp;
 -    char *savestr = NULL;
 -    unsigned char *str = NULL;
 +    char *cp, *ep, *sp;
 +    char *savestr = NULL, *str = NULL;
      char buffer[BUFSIZ], buffer2[BUFSIZ];
      int i, c, ljust, n;
      int value = 0;
        switch (fmt->f_type) {
  
        case FT_COMP:
 -          cpstripped (&cp, ep, scanl + max - 1, fmt->f_comp->c_text);
 +          cpstripped (&cp, &ep, scanl + max - 1, fmt->f_comp->c_text);
            break;
        case FT_COMPF:
 -          cptrimmed (&cp, fmt->f_comp->c_text, fmt->f_width, fmt->f_fill,
 -                     ep - cp, scanl - cp + max - 1);
 +          cptrimmed (&cp, &ep, fmt->f_comp->c_text, fmt->f_width, fmt->f_fill,
 +                     scanl + max - 1);
            break;
  
        case FT_LIT:
            break;
  
        case FT_STR:
 -          cpstripped (&cp, ep, scanl + max - 1, str);
 +          cpstripped (&cp, &ep, scanl + max - 1, str);
            break;
        case FT_STRF:
 -          cptrimmed (&cp, str, fmt->f_width, fmt->f_fill, ep - cp,
 -                     scanl - cp + max - 1);
 +          cptrimmed (&cp, &ep, str, fmt->f_width, fmt->f_fill, 
 +                     scanl + max - 1);
            break;
        case FT_STRLIT:
            sp = str;
            break;
  
        case FT_DONE:
+           if (callbacks && callbacks->trace_func)
+               callbacks->trace_func(callbacks->trace_context, fmt, value,
+                                     str, scanl);
            goto finished;
  
        case FT_IF_S:
  
        case FT_LS_TRIM:
            if (str) {
 -                  unsigned char *xp;
 +                  char *xp;
  
                    strncpy(buffer, str, sizeof(buffer));
                    buffer[sizeof(buffer)-1] = '\0';
                    str = buffer;
 -                  while (isspace(*str))
 +                  while (isspace((unsigned char) *str))
                            str++;
                    ljust = 0;
                    if ((i = fmt->f_width) < 0) {
                            str[i] = '\0';
                    xp = str;
                    xp += strlen(str) - 1;
 -                  while (xp > str && isspace(*xp))
 +                  while (xp > str && isspace((unsigned char) *xp))
                            *xp-- = '\0';
                    if (ljust && i > 0 && (int) strlen(str) > i)
                        str += strlen(str) - i;
  
        case FT_FORMATADDR:
            /* hook for custom address list formatting (see replsbr.c) */
-           str = formataddr (savestr, str);
+           if (callbacks && callbacks->formataddr)
+               str = callbacks->formataddr (savestr, str);
+           else
+               str = formataddr (savestr, str);
            break;
  
        case FT_CONCATADDR:
            /* The same as formataddr, but doesn't do duplicate suppression */
-           str = concataddr (savestr, str);
+           if (callbacks && callbacks->concataddr)
+               str = callbacks->concataddr (savestr, str);
+           else
+               str = concataddr (savestr, str);
            break;
  
        case FT_PUTADDR:
             * (e.g., "To: ")
             */
            {
 -          unsigned char *lp;
 -          char *lastb;
 +          char *lp, *lastb;
            int indent, wid, len;
  
            lp = str;
                adios(NULL, "putaddr -- num register (%d) must be greater "
                            "than label width (%d)", value, indent);
            }
 -          while( (c = *sp++) && cp < ep)
 -              *cp++ = c;
 +          while( (c = (unsigned char) *sp++) && cp < ep)
 +              *cp++ = (char) c;
            while (len > wid) {
                /* try to break at a comma; failing that, break at a
                 * space.
                 */
                lastb = 0; sp = lp + wid;
 -              while (sp > lp && (c = *--sp) != ',') {
 +              while (sp > lp && (c = (unsigned char) *--sp) != ',') {
                    if (! lastb && isspace(c))
                        lastb = sp - 1;
                }
                if (sp == lp) {
                    if (! (sp = lastb)) {
                        sp = lp + wid - 1;
 -                      while (*sp && *sp != ',' && !isspace(*sp))
 +                      while (*sp && *sp != ',' &&
 +                                              !isspace((unsigned char) *sp))
                            sp++;
                        if (*sp != ',')
                            sp--;
                len -= sp - lp + 1;
                while (cp < ep && lp <= sp)
                    *cp++ = *lp++;
 -              while (isspace(*lp))
 +              while (isspace((unsigned char) *lp))
                    lp++, len--;
                if (*lp) {
                    if (cp < ep)
                        *cp++ = ' ';
                }
            }
 -          cpstripped (&cp, ep, scanl + max - 1, lp);
 +          cpstripped (&cp, &ep, scanl + max - 1, lp);
            }
            break;
  
            }
            break;
        }
+       /*
+        * Call our tracing callback function, if one was supplied
+        */
+       if (callbacks && callbacks->trace_func)
+           callbacks->trace_func(callbacks->trace_context, fmt, value,
+                                 str, scanl);
        fmt++;
      }
  
      while (fmt->f_type != FT_DONE) {
        if (fmt->f_type == FT_LS_LIT) {
            str = fmt->f_text;
+           if (callbacks && callbacks->trace_func)
+               callbacks->trace_func(callbacks->trace_context, fmt, value,
+                                     str, scanl);
        } else if (fmt->f_type == FT_STRLITZ) {
            /* Don't want to emit part of an escape sequence.  So if
               there isn't enough room in the buffer for the entire
            if (cp - scanl + strlen (str) + 1 < max) {
                for (sp = str; *sp; *cp++ = *sp++) continue;
            }
+           if (callbacks && callbacks->trace_func)
+               callbacks->trace_func(callbacks->trace_context, fmt, value,
+                                     str, scanl);
        }
        fmt++;
      }
diff --combined uip/forwsbr.c
index 7c480e25000cb9ecf953bda228c605446aca5262,1f181fdd5866a18ee3f07100c9673c47da492e5c..48fecb179a6b05f50463e004bf499c2988ff435c
@@@ -46,7 -46,7 +46,7 @@@ build_form (char *form, char *digest, i
            char *cc, char *fcc, char *subject, char *inputfile)
  {
      int       in;
 -    int fmtsize, state, char_read = 0;
 +    int fmtsize, state;
      int i;
      register char *nfs;
      char *line, tmpfil[BUFSIZ], name[NAMESZ], **ap;
@@@ -54,7 -54,6 +54,7 @@@
      register struct comp *cptr;
      struct format *fmt;
      char *cp = NULL;
 +    m_getfld_state_t gstate = 0;
  
      /*
       * Open the message we'll be scanning for components
@@@ -87,9 -86,8 +87,9 @@@
       * these routines?
       */
  
 -    for (state = FLD;;) {
 -      state = m_getfld(state, name, msgbuf, sizeof(msgbuf), tmp);
 +    for (;;) {
 +      int msg_count = sizeof msgbuf;
 +      state = m_getfld (&gstate, name, msgbuf, &msg_count, tmp);
        switch (state) {
            case FLD:
            case FLDPLUS:
  
                i = fmt_addcomptext(name, msgbuf);
                if (i != -1) {
 -                  char_read += msg_count;
                    while (state == FLDPLUS) {
 -                      state = m_getfld(state, name, msgbuf,
 -                                       sizeof(msgbuf), tmp);
 +                      msg_count = sizeof msgbuf;
 +                      state = m_getfld (&gstate, name, msgbuf, &msg_count, tmp);
                        fmt_appendcomp(i, name, msgbuf);
 -                      char_read += msg_count;
                    }
                }
 -              while (state == FLDPLUS)
 -                  state = m_getfld(state, name, msgbuf, sizeof(msgbuf), tmp);
 +              while (state == FLDPLUS) {
 +                  msg_count = sizeof msgbuf;
 +                  state = m_getfld (&gstate, name, msgbuf, &msg_count, tmp);
 +              }
                break;
  
            case LENERR:
       */
  
  finished:
 +    m_getfld_state_destroy (&gstate);
  
      cptr = fmt_findcomp ("digest");
      if (cptr) {
        adios ("dup", "unable to");
  
      line = mh_xmalloc ((unsigned) fmtsize);
-     fmt_scan (fmt, line, fmtsize - 1, fmtsize, dat);
+     fmt_scan (fmt, line, fmtsize - 1, fmtsize, dat, NULL);
      fputs (line, tmp);
      free (line);
      if (fclose (tmp))
diff --combined uip/mhlsbr.c
index 6babf5105e01118adf2505c0159aa3d93b79af4e,fc0a1a109a6d75cbb81a032958148ad603cf63cb..5dbf341cc09c99ccf366db7cbd2eef4e723d2ca4
@@@ -288,7 -288,7 +288,7 @@@ static unsigned int wid
  
  static char *ovtxt;
  
 -static unsigned char *onelp;
 +static char *onelp;
  
  static char *parptr;
  
@@@ -336,8 -336,7 +336,8 @@@ static void quitser (int)
  static void mhladios (char *, char *, ...);
  static void mhldone (int);
  static void m_popen (char *);
 -static void filterbody (struct mcomp *, char *, int, int, FILE *);
 +static void filterbody (struct mcomp *, char *, int, int, FILE *,
 +                        m_getfld_state_t);
  static void compile_formatfield(struct mcomp *);
  static void compile_filterargs (void);
  
@@@ -937,7 -936,6 +937,7 @@@ mhlfile (FILE *fp, char *mname, int ofi
      int state, bucket;
      struct mcomp *c1, *c2, *c3;
      char **ip, name[NAMESZ], buf[BUFSIZ];
 +    m_getfld_state_t gstate = 0;
  
      compile_filterargs();
  
        }
      }
  
 -    for (state = FLD;;) {
 -      switch (state = m_getfld (state, name, buf, sizeof(buf), fp)) {
 +    for (;;) {
 +      int bufsz = sizeof buf;
 +      switch (state = m_getfld (&gstate, name, buf, &bufsz, fp)) {
            case FLD: 
            case FLDPLUS: 
                bucket = fmt_addcomptext(name, buf);
                for (ip = ignores; *ip; ip++)
                    if (!mh_strcasecmp (name, *ip)) {
                        while (state == FLDPLUS) {
 -                          state = m_getfld (state, name, buf, sizeof(buf), fp);
 +                          bufsz = sizeof buf;
 +                          state = m_getfld (&gstate, name, buf, &bufsz, fp);
                            fmt_appendcomp(bucket, name, buf);
                        }
                        break;
                if (c1 == NULL)
                    c1 = add_queue (&msghd, &msgtl, name, buf, 0);
                while (state == FLDPLUS) {
 -                  state = m_getfld (state, name, buf, sizeof(buf), fp);
 +                  bufsz = sizeof buf;
 +                  state = m_getfld (&gstate, name, buf, &bufsz, fp);
                    c1->c_text = add (buf, c1->c_text);
                    fmt_appendcomp(bucket, name, buf);
                }
                    if (dobody && !mh_strcasecmp (c1->c_name, "body")) {
                        if (c1->c_flags & FMTFILTER && state == BODY &&
                                                        formatproc != NULL) {
 -                          filterbody(c1, buf, sizeof(buf), state, fp);
 +                          filterbody(c1, buf, sizeof(buf), state, fp, gstate);
                        } else {
                            holder.c_text = mh_xmalloc (sizeof(buf));
                            strncpy (holder.c_text, buf, sizeof(buf));
                            while (state == BODY) {
                                putcomp (c1, &holder, BODYCOMP);
 -                              state = m_getfld (state, name, holder.c_text,
 -                                          sizeof(buf), fp);
 +                              bufsz = sizeof buf;
 +                              state = m_getfld (&gstate, name, holder.c_text,
 +                                          &bufsz, fp);
                            }
                            free (holder.c_text);
                            holder.c_text = NULL;
                                break;
                        }
                }
 +              m_getfld_state_destroy (&gstate);
                return;
  
            case LENERR: 
            case FMTERR: 
                advise (NULL, "format error in message %s", mname);
                exitstat++;
 +              m_getfld_state_destroy (&gstate);
                return;
  
            default: 
@@@ -1164,7 -1156,8 +1164,8 @@@ mcomp_format (struct mcomp *c1, struct 
            if (!cp[1])
                *cp = 0;
  
-       fmt_scan (c1->c_fmt, buffer, sizeof buffer - 1, sizeof buffer - 1, dat);
+       fmt_scan (c1->c_fmt, buffer, sizeof buffer - 1, sizeof buffer - 1,
+                 dat, NULL);
        /* Don't need to append a newline, dctime() already did */
        c2->c_text = getcpy (buffer);
  
            p->pq_error = NULL;
        }
  
-       fmt_scan (c1->c_fmt, buffer, sizeof buffer - 1, sizeof buffer - 1, dat);
+       fmt_scan (c1->c_fmt, buffer, sizeof buffer - 1, sizeof buffer - 1,
+                 dat, NULL);
        if (*buffer) {
            if (c2->c_text)
                c2->c_text = add (",\n", c2->c_text);
@@@ -1278,7 -1272,7 +1280,7 @@@ static voi
  putcomp (struct mcomp *c1, struct mcomp *c2, int flag)
  {
      int count, cchdr;
 -    unsigned char *cp;
 +    char *cp;
  
      cchdr = 0;
      lm = 0;
      if (!(c1->c_flags & HDROUTPUT) && !(c1->c_flags & NOCOMPONENT)) {
          if (c1->c_flags & UPPERCASE)          /* uppercase component also */
            for (cp = (c1->c_text ? c1->c_text : c1->c_name); *cp; cp++)
 -              if (islower (*cp))
 -                  *cp = toupper (*cp);
 +              if (islower ((unsigned char) *cp))
 +                  *cp = toupper ((unsigned char) *cp);
        putstr (c1->c_text ? c1->c_text : c1->c_name, c1->c_flags);
        if (flag != BODYCOMP) {
            putstr (": ", c1->c_flags);
            && !(c2->c_flags & NOCOMPONENT)) {
          if (c1->c_flags & UPPERCASE)
            for (cp = c2->c_name; *cp; cp++)
 -              if (islower (*cp))
 -                  *cp = toupper (*cp);
 +              if (islower ((unsigned char) *cp))
 +                  *cp = toupper ((unsigned char) *cp);
        putstr (c2->c_name, c1->c_flags);
        putstr (": ", c1->c_flags);
        if (!(c1->c_flags & SPLIT))
      }
      if (c1->c_flags & UPPERCASE)
        for (cp = c2->c_text; *cp; cp++)
 -          if (islower (*cp))
 -              *cp = toupper (*cp);
 +          if (islower ((unsigned char) *cp))
 +              *cp = toupper ((unsigned char) *cp);
  
      count = 0;
      if (cchdr) {
@@@ -1401,7 -1395,7 +1403,7 @@@ oneline (char *stuff, long flags
      term = 0;
      if (flags & COMPRESS) {
        for (spc = 1, cp = ret; *onelp; onelp++)
 -          if (isspace (*onelp)) {
 +          if (isspace ((unsigned char) *onelp)) {
                if (*onelp == '\n' && (!onelp[1] || (flags & ADDRFMT))) {
                    term = '\n';
                    *onelp++ = 0;
@@@ -1649,8 -1643,6 +1651,8 @@@ static voi
  m_popen (char *name)
  {
      int pd[2];
 +    char *file;
 +    char **arglist;
  
      if (mhl_action && (sd = dup (fileno (stdout))) == NOTOK)
        adios ("standard output", "unable to dup()");
      if (pipe (pd) == NOTOK)
        adios ("pipe", "unable to");
  
 -    switch (m_pid = vfork()) {
 +    switch (m_pid = fork()) {
        case NOTOK: 
            adios ("fork", "unable to");
  
                dup2 (pd[0], fileno (stdin));
                close (pd[0]);
            }
 -          execlp (name, r1bindex (name, '/'), NULL);
 +          arglist = argsplit(name, &file, NULL);
 +          execvp (file, arglist);
            fprintf (stderr, "unable to exec ");
            perror (name);
            _exit (-1);
@@@ -1778,8 -1769,7 +1780,8 @@@ compile_filterargs (void
   */
  
  static void
 -filterbody (struct mcomp *c1, char *buf, int bufsz, int state, FILE *fp)
 +filterbody (struct mcomp *c1, char *buf, int bufsz, int state, FILE *fp,
 +            m_getfld_state_t gstate)
  {
      struct mcomp holder;
      char name[NAMESZ];
         */
  
        while (state == BODY) {
 +          int bufsz2 = bufsz;
            write(fdinput[1], buf, strlen(buf));
 -          state = m_getfld(state, name, buf, bufsz, fp);
 +          state = m_getfld (&gstate, name, buf, &bufsz2, fp);
        }
  
        /*
       */
  
      switch (filterpid = fork()) {
 -        char **args;
 +        char **args, *program;
        struct arglist *a;
 -      int i, dat[5], s;
 +      int i, dat[5], s, argp;
  
      case 0:
        /*
 -       * Allocate an argument array for us
 +       * Configure an argument array for us
         */
  
 -      args = (char **) mh_xmalloc((filter_nargs + 2) * sizeof(char *));
 -      args[0] = formatproc;
 -      args[filter_nargs + 1] = NULL;
 +      args = argsplit(formatproc, &program, &argp);
 +      args[argp + filter_nargs] = NULL;
        dat[0] = 0;
        dat[1] = 0;
        dat[2] = 0;
         * Pull out each argument and scan them.
         */
  
 -      for (a = arglist_head, i = 1; a != NULL; a = a->a_next, i++) {
 +      for (a = arglist_head, i = argp; a != NULL; a = a->a_next, i++) {
            args[i] = mh_xmalloc(BUFSIZ);
-           fmt_scan(a->a_fmt, args[i], BUFSIZ - 1, BUFSIZ, dat);
+           fmt_scan(a->a_fmt, args[i], BUFSIZ - 1, BUFSIZ, dat, NULL);
            /*
             * fmt_scan likes to put a trailing newline at the end of the
             * format string.  If we have one, get rid of it.
diff --combined uip/rcvdist.c
index 3c017c4a36ae489298292892a190199e3103b008,2db1b0503a308363c3e14d8192be9c3c7ab9647e..6cc8e27764a3c11bac096440985ccb85dab964ca
@@@ -42,9 -42,9 +42,9 @@@ in
  main (int argc, char **argv)
  {
      pid_t child_id;
 -    int i, vecp = 1;
 -    char *addrs = NULL, *cp, *form = NULL, buf[BUFSIZ];
 -    char **argp, **arguments, *vec[MAXARGS];
 +    int i, vecp;
 +    char *addrs = NULL, *cp, *form = NULL, buf[BUFSIZ], *program;
 +    char **argp, **arguments, **vec;
      FILE *fp;
      char *tfile = NULL;
  
      /* read user profile/context */
      context_read();
  
 +    /*
 +     * Configure this now, since any unknown switches to rcvdist get
 +     * sent to postproc
 +     */
 +
 +    vec = argsplit(postproc, &program, &vecp);
 +
      mts_init (invo_name);
      arguments = getarguments (invo_name, argc, argv, 1);
      argp = arguments;
      if (distout (drft, tmpfil, backup) == NOTOK)
        done (1);
  
 -    vec[0] = r1bindex (postproc, '/');
      vec[vecp++] = "-dist";
      vec[vecp++] = drft;
      if ((cp = context_find ("mhlproc"))) {
        case NOTOK: 
            admonish (NULL, "unable to fork");/* fall */
        case OK: 
 -          execvp (postproc, vec);
 +          execvp (program, vec);
            fprintf (stderr, "unable to exec ");
            perror (postproc);
            _exit (1);
@@@ -182,7 -176,6 +182,7 @@@ rcvdistout (FILE *inb, char *form, cha
      char *cp, *scanl, name[NAMESZ], tmpbuf[SBUFSIZ];
      register struct comp *cptr;
      FILE *out;
 +    m_getfld_state_t gstate = 0;
  
      if (!(out = fopen (drft, "w")))
        adios (drft, "unable to create");
      if (cptr)
        cptr->c_text = addrs;
  
 -    for (state = FLD;;) {
 -      switch (state = m_getfld (state, name, tmpbuf, SBUFSIZ, inb)) {
 +    for (;;) {
 +      int msg_count = SBUFSIZ;
 +      switch (state = m_getfld (&gstate, name, tmpbuf, &msg_count, inb)) {
            case FLD: 
            case FLDPLUS: 
                i = fmt_addcomptext(name, tmpbuf);
                if (i != -1) {
                    char_read += msg_count;
                    while (state == FLDPLUS) {
 -                      state = m_getfld (state, name, tmpbuf, SBUFSIZ, inb);
 +                      msg_count = SBUFSIZ;
 +                      state = m_getfld (&gstate, name, tmpbuf, &msg_count, inb);
                        fmt_appendcomp(i, name, tmpbuf);
                        char_read += msg_count;
                    }
                }
  
 -              while (state == FLDPLUS)
 -                  state = m_getfld (state, name, tmpbuf, SBUFSIZ, inb);
 +              while (state == FLDPLUS) {
 +                  msg_count = SBUFSIZ;
 +                  state = m_getfld (&gstate, name, tmpbuf, &msg_count, inb);
 +              }
                break;
  
            case LENERR: 
        }
      }
  finished: ;
 +    m_getfld_state_destroy (&gstate);
  
      i = format_len + char_read + 256;
      scanl = mh_xmalloc ((size_t) i + 2);
      dat[0] = dat[1] = dat[2] = dat[4] = 0;
      dat[3] = outputlinelen;
-     fmt_scan (fmt, scanl, i + 1, i, dat);
+     fmt_scan (fmt, scanl, i + 1, i, dat, NULL);
      fputs (scanl, out);
  
      if (ferror (out))
diff --combined uip/replsbr.c
index eff1877e26d54f8faeb20431201d572f246a5790,2117037608c6d8b7f1526f9633e9544c46236c8b..a7a214bf538ad69ac735b7e420510148818d4e89
@@@ -57,6 -57,8 +57,8 @@@ static char *addrcomps[] = 
   */
  static int insert (struct mailname *);
  static void replfilter (FILE *, FILE *, char *, int);
+ static char *replformataddr(char *, char *);
+ static char *replconcataddr(char *, char *);
  
  
  void
@@@ -69,9 -71,10 +71,10 @@@ replout (FILE *inb, char *msg, char *dr
      struct format *fmt;
      register char **ap;
      int       char_read = 0, format_len, mask;
 -    char name[NAMESZ], *scanl;
 -    unsigned char *cp;
 +    char name[NAMESZ], *scanl, *cp;
      static int dat[5];                        /* aux. data for format routine */
 +    m_getfld_state_t gstate = 0;
+     struct fmt_callbacks cb;
  
      FILE *out;
      NMH_UNUSED (msg);
      /*
       * pick any interesting stuff out of msg "inb"
       */
 -    for (state = FLD;;) {
 -      state = m_getfld (state, name, tmpbuf, sizeof(tmpbuf), inb);
 +    for (;;) {
 +      int msg_count = sizeof tmpbuf;
 +      state = m_getfld (&gstate, name, tmpbuf, &msg_count, inb);
        switch (state) {
            case FLD: 
            case FLDPLUS: 
                if (i != -1) {
                    char_read += msg_count;
                    while (state == FLDPLUS) {
 -                      state = m_getfld(state, name, tmpbuf,
 -                                       sizeof(tmpbuf), inb);
 +                      msg_count= sizeof tmpbuf;
 +                      state = m_getfld (&gstate, name, tmpbuf, &msg_count, inb);
                        fmt_appendcomp(i, name, tmpbuf);
                        char_read += msg_count;
                    }
                }
  
 -              while (state == FLDPLUS)
 -                  state = m_getfld (state, name, tmpbuf, SBUFSIZ, inb);
 +              while (state == FLDPLUS) {
 +                  msg_count= sizeof tmpbuf;
 +                  state = m_getfld (&gstate, name, tmpbuf, &msg_count, inb);
 +              }
                break;
  
            case LENERR: 
       * format and output the header lines.
       */
  finished:
 +    m_getfld_state_destroy (&gstate);
  
      /*
       * if there's a "Subject" component, strip any "Re:"s off it
        register char *sp = cp;
  
        for (;;) {
 -          while (isspace(*cp))
 +          while (isspace((unsigned char) *cp))
                cp++;
            if(uprf(cp, "re:"))
                cp += 3;
      dat[2] = 0;
      dat[3] = outputlinelen;
      dat[4] = 0;
-     fmt_scan (fmt, scanl, i + 1, i, dat);
+     memset(&cb, 0, sizeof(cb));
+     cb.formataddr = replformataddr;
+     cb.concataddr = replconcataddr;
+     fmt_scan (fmt, scanl, i + 1, i, dat, &cb);
      fputs (scanl, out);
      if (badaddrs) {
        fputs ("\nrepl: bad addresses:\n", out);
@@@ -275,8 -277,8 +281,8 @@@ static unsigned int bufsiz=0;      /* curren
   * don't call "getcpy") but still place no upper limit on the
   * length of the result string.
   */
- char *
- formataddr (char *orig, char *str)
static char *
replformataddr (char *orig, char *str)
  {
      register int len;
      char baddr[BUFSIZ], error[BUFSIZ];
   * like formataddr, except that it does NOT suppress duplicate addresses
   * between calls.
   *
-  * As an implementation detail: I thought about splitting out formataddr()
+  * As an implementation detail: I thought about splitting out replformataddr()
   * into the generic part and duplicate-suppressing part, but the call to
   * insert() was buried deep within a couple of loops and I didn't see a
   * way to do it easily.  So instead we simply set a special flag to stop
-  * the duplicate check and call formataddr().
+  * the duplicate check and call replformataddr().
   */
- char *
- concataddr(char *orig, char *str)
static char *
replconcataddr(char *orig, char *str)
  {
      char *cp;
  
      nodupcheck = 1;
-     cp = formataddr(orig, str);
+     cp = replformataddr(orig, str);
      nodupcheck = 0;
      return cp;
  }
@@@ -411,8 -413,7 +417,8 @@@ replfilter (FILE *in, FILE *out, char *
      int       pid;
      char *mhl;
      char *errstr;
 -    char *arglist[7];
 +    char **arglist;
 +    int argnum;
  
      if (filter == NULL)
        return;
      if (access (filter, R_OK) == NOTOK)
        adios (filter, "unable to read");
  
 -    mhl = r1bindex (mhlproc, '/');
 -
      rewind (in);
      lseek (fileno(in), (off_t) 0, SEEK_SET);
  
 -    switch (pid = vfork()) {
 +    switch (pid = fork()) {
        case NOTOK: 
            adios ("fork", "unable to");
  
            dup2 (fileno (out), fileno (stdout));
            closefds (3);
  
 -          arglist[0] = mhl;
 -          arglist[1] = "-form";
 -          arglist[2] = filter;
 -          arglist[3] = "-noclear";
 +          /*
 +           * We're not allocating the memory for the extra arguments,
 +           * because we never call arglist_free().  But if we ever change
 +           * that be sure to use getcpy() for the extra arguments.
 +           */
 +          arglist = argsplit(mhlproc, &mhl, &argnum);
 +          arglist[argnum++] = "-form";
 +          arglist[argnum++] = filter;
 +          arglist[argnum++] = "-noclear";
  
            switch (fmtproc) {
            case 1:
 -              arglist[4] = "-fmtproc";
 -              arglist[5] = formatproc;
 -              arglist[6] = NULL;
 +              arglist[argnum++] = "-fmtproc";
 +              arglist[argnum++] = formatproc;
                break;
            case 0:
 -              arglist[4] = "-nofmtproc";
 -              arglist[5] = NULL;
 +              arglist[argnum++] = "-nofmtproc";
                break;
 -          default:
 -              arglist[4] = NULL;
            }
  
 -          execvp (mhlproc, arglist);
 +          arglist[argnum++] = NULL;
 +
 +          execvp (mhl, arglist);
            errstr = strerror(errno);
            write(2, "unable to exec ", 15);
            write(2, mhlproc, strlen(mhlproc));
diff --combined uip/scansbr.c
index 0f6cd7e0ca7d10bce6bfe91b9104be1ea7c2cdec,ddfdd841a374cfbbbafbaaf836884a38440fa42a..c038622e64eae05f8f502a71b3b9e8423b706619
@@@ -36,7 -36,6 +36,7 @@@ static struct comp **used_buf = 0;    /* s
  static int dat[5];                    /* aux. data for format routine    */
  
  char *scanl = 0;                      /* text of most recent scanline    */
 +m_getfld_state_t gstate;              /* for access by msh */
  
  #define DIEWRERR() adios (scnmsg, "write error on")
  
@@@ -61,14 -60,14 +61,14 @@@ scan (FILE *inb, int innum, int outnum
        int unseen, char *folder, long size, int noisy)
  {
      int i, compnum, encrypted, state;
 -    unsigned char *cp, *tmpbuf, *startbody;
 -    char **nxtbuf;
 +    char *cp, *tmpbuf, *startbody, **nxtbuf;
      char *saved_c_text = NULL;
      struct comp *cptr;
      struct comp **savecomp;
      char *scnmsg = NULL;
      FILE *scnout = NULL;
      char name[NAMESZ];
 +    int bufsz;
      static int rlwidth, slwidth;
      static size_t scanl_size;
  
       * Get the first field.  If the message is non-empty
       * and we're doing an "inc", open the output file.
       */
 -    if ((state = m_getfld (FLD, name, tmpbuf, rlwidth, inb)) == FILEEOF) {
 +    bufsz = rlwidth;
 +    m_getfld_state_reset (&gstate);
 +    if ((state = m_getfld (&gstate, name, tmpbuf, &bufsz, inb)) == FILEEOF) {
        if (ferror(inb)) {
            advise("read", "unable to"); /* "read error" */
            return SCNFAT;
      }
  
      /* scan - main loop */
 -    for (compnum = 1; ; state = m_getfld (state, name, tmpbuf, rlwidth, inb)) {
 +    for (compnum = 1; ;
 +      bufsz = rlwidth, state = m_getfld (&gstate, name, tmpbuf, &bufsz, inb)) {
        switch (state) {
            case FLD: 
            case FLDPLUS: 
                        cptr->c_text = tmpbuf;
                        for (cp = tmpbuf + strlen (tmpbuf) - 1; 
                                        cp >= tmpbuf; cp--)
 -                          if (isspace (*cp))
 +                          if (isspace ((unsigned char) *cp))
                                *cp = 0;
                            else
                                break;
                }
  
                while (state == FLDPLUS) {
 -                  state = m_getfld (state, name, tmpbuf, rlwidth, inb);
 +                  bufsz = rlwidth;
 +                  state = m_getfld (&gstate, name, tmpbuf, &bufsz, inb);
                    if (outnum)
                        FPUTS (tmpbuf);
                }
                 */
  
                if ((i = strlen(tmpbuf)) < rlwidth) {
 -                  state = m_getfld (state, name, tmpbuf + i,
 -                                    rlwidth - i, inb);
 +                  bufsz = rlwidth - i;
 +                  state = m_getfld (&gstate, name, tmpbuf + i, &bufsz, inb);
                }
  
                if (! outnum) {
@@@ -269,8 -264,7 +269,8 @@@ body:
                }
  
                while (state == BODY) {
 -                  state = m_getfld(state, name, tmpbuf, rlwidth, inb);
 +                  bufsz = rlwidth;
 +                  state = m_getfld (&gstate, name, tmpbuf, &bufsz, inb);
                    FPUTS(tmpbuf);
                }
                goto finished;
@@@ -344,7 -338,7 +344,7 @@@ finished
        }
      }
  
-     fmt_scan (fmt, scanl, scanl_size, slwidth, dat);
+     fmt_scan (fmt, scanl, scanl_size, slwidth, dat, NULL);
  
      if (bodycomp)
        bodycomp->c_text = saved_c_text;
@@@ -378,23 -372,3 +378,23 @@@ mh_fputs(char *s, FILE *stream
      return (0);
  }
  
 +/* The following three functions allow access to the global gstate above. */
 +void
 +scan_finished () {
 +    m_getfld_state_destroy (&gstate);
 +}
 +
 +void
 +scan_detect_mbox_style (FILE *f) {
 +    m_unknown (&gstate, f);
 +}
 +
 +void
 +scan_eom_action (int (*action)()) {
 +    m_eomsbr (gstate, action);
 +}
 +
 +void
 +scan_reset_m_getfld_state () {
 +    m_getfld_state_reset (&gstate);
 +}