diff sbr/formatsbr.c @ 0:bce86c4163a3

Initial revision
author kono
date Mon, 18 Apr 2005 23:46:02 +0900
parents
children 441a2190cfae
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sbr/formatsbr.c	Mon Apr 18 23:46:02 2005 +0900
@@ -0,0 +1,1129 @@
+/* formatsbr.c - format string interpretation */
+#ifndef	lint
+static char ident[] = "@(#)$Id$";
+#endif	/* lint */
+
+#include "../h/mh.h"
+#include "../h/addrsbr.h"
+#include "../h/formatsbr.h"
+#include "../zotnet/tws.h"
+#include "../h/fmtcompile.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+/*  */
+
+
+#define	NFMTS	MAXARGS
+#define QUOTE '\\'
+
+static char  *formats = 0;
+extern char *formataddr ();	/* hook for custom address formatting */
+#ifdef	LBL
+struct msgs *fmt_current_folder; /* current folder (set by main program) */
+#endif
+
+static normalize();
+static int   get_x400_comp();
+
+extern int fmt_norm;		/* defined in sbr/formatdef.c = AD_NAME */
+struct mailname fmt_mnull;
+
+#ifdef JAPAN
+extern int japan_environ;
+#endif /* JAPAN */
+
+time_t	time ();
+
+/*  */
+
+/* MAJOR HACK:	See MHCHANGES for discussion */
+
+char  *new_fs (form, format, def)
+register char  *form,
+               *format,
+               *def;
+{
+    struct stat st;
+    register    FILE *fp;
+
+    if (formats)
+	free (formats);
+
+    if (form) {
+	if ((fp = fopen (libpath (form), "r")) == NULL)
+	    adios (form, "unable to open format file");
+
+	if (fstat (fileno (fp), &st) == NOTOK)
+	    adios (form, "unable to stat format file");
+
+	if ((formats = malloc ((unsigned) st.st_size + 1)) == NULLCP)
+	    adios (form, "unable to allocate space for format");
+
+	if (read (fileno(fp), formats, (int) st.st_size) != st.st_size)
+	    adios (form, "error reading format file");
+
+	formats[st.st_size] = '\0';
+
+	(void) fclose (fp);
+    }
+    else {
+	formats = getcpy (format ? format : def);
+    }
+
+#ifdef JAPAN
+    (void) ml_conv(formats);
+#endif /* JAPAN */
+
+    normalize (formats);
+
+    return formats;
+}
+
+/*  */
+
+static  normalize (cp)
+register char  *cp;
+{
+    register char  *dp;
+
+    for (dp = cp; *cp; cp++)
+	if (*cp != QUOTE)
+	    *dp++ = *cp;
+	else
+	    switch (*++cp) {
+#define	grot(y,z) case y: *dp++ = z; break;
+		grot ('b', '\b');
+		grot ('f', '\f');
+		grot ('n', '\n');
+		grot ('r', '\r');
+		grot ('t', '\t');
+
+		case '\n':
+		    break;
+
+		case 0: 
+		    cp--;	/* fall */
+		default: 
+		    *dp++ = *cp;
+		    break;
+	    }
+
+    *dp = 0;
+}
+
+/*  */
+/*
+ * test if string "sub" appears anywhere in string "str"
+ * (case insensitive).
+ */
+
+static int match (str, sub)
+register unsigned char  *str,
+                        *sub;
+{
+    register unsigned int    c1;
+    register unsigned int    c2;
+    register unsigned char   *s1;
+    register unsigned char   *s2;
+
+#ifdef JAPAN
+    while (c1 = *sub) {
+	c1 = (isalpha(c1) && isupper(c1)) ? tolower(c1) : c1;
+	while ((c2 = *str++)
+	       && c1 != ((isalpha(c2) && isupper(c2)) ? tolower(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))
+	  ;
+	if (! c1)
+	  return 1;
+    }
+#else /* JAPAN */
+#ifdef LOCALE
+    while (c1 = *sub) {
+	c1 = (isalpha(c1) && isupper(c1)) ? tolower(c1) : c1;
+	while ((c2 = *str++) && c1 != ((isalpha(c2) && isupper(c2)) ? tolower(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))
+	    ;
+	if (! c1)
+	    return 1;
+    }
+#else
+    while (c1 = *sub) {
+	while ((c2 = *str++) && (c1 | 040) != (c2 | 040))
+	    ;
+	if (! c2)
+	    return 0;
+	s1 = sub + 1; s2 = str;
+	while ((c1 = *s1++) && (c1 | 040) == (*s2++ | 040))
+	    ;
+	if (! c1)
+	    return 1;
+    }
+#endif
+#endif /* JAPAN */
+    return 1;
+}
+/*  */
+
+/* macros to format data */
+
+#define PUTDF(cp, num, wid, fill) if (cp + wid < ep){\
+		if((i = (num))<0) i = -(num);\
+		if((c = (wid))<0) c = -c;\
+		sp = cp + c;\
+		do {\
+		    *--sp = (i % 10) + '0';\
+		    i /= 10;\
+		} while (i > 0 && sp > cp);\
+		if (i > 0)\
+		    *sp = '?';\
+		else if ((num) < 0 && sp > cp)\
+		    *--sp = '-';\
+		while (sp > cp)\
+		    *--sp = fill;\
+		cp += c;\
+		}
+#define PUTD(cp, num) if (cp < ep){\
+		if((i = (num))==0) *cp++ = '0';\
+		else {\
+		    if((i = (num))<0) \
+			*cp++ = '-', i = -(num);\
+		    c = 10;\
+		    while (1) {\
+			int j;\
+			if (c > i) {\
+			    c /= 10; break;\
+			}\
+			j = c;\
+			c *= 10;\
+			if (c % 10) { /* overflow */\
+			    c = j; break;\
+			}\
+		    }\
+		    while (cp < ep && c > 0) {\
+			*cp++ = (i / c) + '0';\
+			i %= c;\
+			c /= 10;\
+			}\
+		    }\
+		}
+#ifdef LOCALE
+#define PUTSF(cp, str, wid, fill) {\
+		ljust = 0;\
+		if ((i = (wid)) < 0) {\
+			i = -i;\
+			ljust++;\
+		}\
+		if (sp = (str)) {\
+			if (ljust) {\
+				c = strlen(sp);\
+				if (c > i)\
+					sp += c - i;\
+				else {\
+					while( --i >= c && cp < ep)\
+						*cp++ = fill;\
+					i++;\
+				}\
+			} else {\
+			    while ((c = (unsigned char) *sp) && (iscntrl(c) || isspace(c)))\
+				sp++;\
+			}\
+			while ((c = (unsigned char) *sp++) && --i >= 0 && cp < ep)\
+				if (isgraph(c)) \
+				    *cp++ = c;\
+				else {\
+					while ((c = (unsigned char) *sp) && (iscntrl(c) || isspace(c)))\
+						sp++;\
+					    *cp++ = ' ';\
+				}\
+		}\
+		if (!ljust)\
+		while( --i >= 0 && cp < ep)\
+		    *cp++ = fill;\
+	}
+#define PUTS(cp, str) {\
+		if (sp = (str)) {\
+		    while ((c = (unsigned char) *sp) && (iscntrl(c) || isspace(c)))\
+			sp++;\
+		    while((c = (unsigned char) *sp++) && cp < ep)\
+			if (isgraph(c)) \
+			    *cp++ = c;\
+			else {\
+			    while ((c = (unsigned char) *sp) && (iscntrl(c) || isspace(c)))\
+				sp++;\
+			    *cp++ = ' ';\
+			}\
+		}\
+	}
+#else /* LOCALE */
+#define PUTSF(cp, str, wid, fill) {\
+		ljust = 0;\
+		if ((i = (wid)) < 0) {\
+			i = -i;\
+			ljust++;\
+		}\
+		if (sp = (str)) {\
+			if (ljust) {\
+				c = strlen(sp);\
+				if (c > i)\
+					sp += c - i;\
+				else {\
+					while( --i >= c && cp < ep)\
+						*cp++ = fill;\
+					i++;\
+				}\
+			} else {\
+		    while ((c = (unsigned char) *sp) && c <= 32)\
+			sp++;\
+			}\
+			while ((c = (unsigned char) *sp++) && --i >= 0 && cp < ep)\
+				if (c > 32) \
+			    *cp++ = c;\
+			else {\
+					while ((c = (unsigned char) *sp) && c <= 32)\
+				sp++;\
+			    *cp++ = ' ';\
+			}\
+		}\
+		if (!ljust)\
+		while( --i >= 0 && cp < ep)\
+		    *cp++ = fill;\
+		}
+#define PUTS(cp, str) {\
+		if (sp = (str)) {\
+		    while ((c = (unsigned char) *sp) && c <= 32)\
+			sp++;\
+		    while( (c = (unsigned char) *sp++) && cp < ep)\
+			if ( c > 32 ) \
+			    *cp++ = c;\
+			else {\
+			    while ( (c = (unsigned char) *sp) && c <= 32 )\
+				sp++;\
+			    *cp++ = ' ';\
+			}\
+		}\
+		}
+#endif
+
+#ifdef JAPAN
+
+#undef PUTSF
+#undef PUTS
+
+#ifndef isgraph
+#define isgraph(c) ((040<(c))&&((c)!=0177))
+#endif
+
+#define ISSPACE(c1)	(isspace((c1) & 0x7f))
+#define ISGRAPH(c1)	((isgraph((c1) & 0x7f))\
+			   || (japan_environ && (((c1) & 0xff) == 0x1b)))
+#define ISCNTRL(c1)	((((c1) & 0xff) == 0x1b)\
+			 ? !japan_environ : (iscntrl((c1) & 0x7f)))
+#define ISJSPACE(c1,c2) ((((c1) & 0xff) == 0xa1) && (((c2) & 0xff) == 0xa1))
+#define ISJGRAPH(c1,c2) ((isgraph((c1) & 0x7f)) &&\
+			 (isgraph((c2) & 0x7f)) &&\
+			 (!ISJSPACE((c1), (c2))))
+
+#define SKIP_SPACE(sp) {\
+    while (ch = *(sp)) {\
+	if (ISCNTRL(ch) || ISSPACE(ch)) {\
+	    (sp)++;\
+	} else if (ch2 = *((sp)+1)) {\
+	    if (ISJSPACE(ch, ch2)) {\
+		(sp) += 2;\
+	    } else {\
+		break;\
+	    }\
+	} else {\
+	    break;\
+	}\
+    }\
+}
+
+#define PUTSF(cp, str, wid, fill) {\
+    ljust = 0;\
+    if ((i = (wid)) < 0) {\
+	i = -i; ljust++;\
+    }\
+    if (sp = (str)) {\
+	if (ljust) {\
+	    c = strlen(sp);\
+	    if (c > i)\
+	      sp += c - i;\
+	    else {\
+		while (--i >= c && cp < ep)\
+		  *cp++ = fill;\
+		i++;\
+	    }\
+	} else {\
+	    SKIP_SPACE(sp);\
+	}\
+	while ((ch = *sp++) && (--i >= 0) && (cp < ep)) {\
+	    if (ml_ismlchar(ch)) {\
+		if ((ch2 = *sp) && ((i-1) >= 0) && ((cp+1) < ep)) {\
+		    if (ISJGRAPH(ch, ch2)) {\
+			*cp++ = ch; *cp++ = ch2; sp++; --i;\
+		    } else {\
+			sp++; SKIP_SPACE(sp); *cp++ = ' ';\
+		    }\
+		} else {\
+		    *cp++ = ' ';\
+		}\
+	    } else {\
+		if (ISGRAPH(ch)) {\
+		    *cp++ = ch;\
+		} else {\
+		    SKIP_SPACE(sp); *cp++ = ' ';\
+		}\
+	    }\
+	}\
+    }\
+    if (!ljust)\
+      while ((--i >= 0) && (cp < ep))\
+	*cp++ = fill;\
+}
+
+#define PUTS(cp, str) {\
+    if (sp = (str)) {\
+	SKIP_SPACE(sp);\
+	while ((ch = *sp++) && (cp < ep)) {\
+	    if (ml_ismlchar(ch)) {\
+		if ((ch2 = *sp) && ((cp+1) < ep)) {\
+		    if (ISJGRAPH(ch, ch2)) {\
+			*cp++ = ch; *cp++ = ch2; sp++;\
+		    } else {\
+			sp++; SKIP_SPACE(sp); *cp++ = ' ';\
+		    }\
+		} else {\
+		    *cp++ = ' ';\
+		}\
+	    } else {\
+		if (ISGRAPH(ch)) {\
+		    *cp++ = ch;\
+		} else {\
+		    SKIP_SPACE(sp); *cp++ = ' ';\
+		}\
+	    }\
+	}\
+    }\
+}
+
+#endif /* JAPAN */
+
+static char *lmonth[] = { "January",  "February","March",   "April",
+			  "May",      "June",    "July",    "August",
+			  "September","October", "November","December" };
+
+static char *get_x400_friendly (mbox, buffer)
+char   *mbox,
+       *buffer;
+{
+    char    given[BUFSIZ],
+	    surname[BUFSIZ];
+
+    if (mbox == NULLCP)
+	return NULLCP;
+    if (*mbox == '"')
+	mbox++;
+    if (*mbox != '/')
+	return NULLCP;
+
+    if (get_x400_comp (mbox, "/PN=", buffer)) {
+	for (mbox = buffer; mbox = index (mbox, '.'); )
+	    *mbox++ = ' ';
+
+	return buffer;
+    }
+
+    if (!get_x400_comp (mbox, "/S=", surname))
+	return NULLCP;
+
+    if (get_x400_comp (mbox, "/G=", given))
+	(void) sprintf (buffer, "%s %s", given, surname);
+    else
+	(void) strcpy (buffer, surname);
+
+    return buffer;
+}
+
+static int get_x400_comp (mbox, key, buffer)
+char   *mbox,
+       *key,
+       *buffer;
+{
+    int	    idx;
+    char   *cp;
+
+    if ((idx = stringdex (key, mbox)) < 0
+	    || !(cp = index (mbox += idx + strlen (key), '/')))
+	return 0;
+
+    (void) sprintf (buffer, "%*.*s", cp - mbox, cp - mbox, mbox);
+    return 1;
+}
+
+struct format *
+fmtscan (format, scanl, width, dat)
+	struct format *format;
+	char	*scanl;
+	int	width;
+	int	dat[];
+{
+    register char	*cp = scanl;
+    register char	*ep = scanl + width - 1;
+    register struct format *fmt = format;
+    register char	*str = NULLCP;
+    register int	value = 0;
+    register char	*sp;
+    register int	i;
+    register int	c;
+    register unsigned char ch, ch2;
+    register struct comp *comp;
+    register struct tws *tws;
+    register struct mailname *mn;
+    int ljust;
+    time_t l;
+    char        *savestr;
+    char	buffer[BUFSIZ];
+
+    while (cp < ep) {
+	switch (fmt->f_type) {
+
+	case FT_COMP:
+	    PUTS (cp, fmt->f_comp->c_text);
+	    break;
+	case FT_COMPF:
+	    PUTSF (cp, fmt->f_comp->c_text, fmt->f_width, fmt->f_fill);
+	    break;
+
+	case FT_LIT:
+	    sp = fmt->f_text;
+	    while( (ch = *sp++) && cp < ep)
+		*cp++ = ch;
+	    break;
+	case FT_LITF:
+	    sp = fmt->f_text;
+	    ljust = 0;
+	    i = fmt->f_width;
+	    if (i < 0) {
+		i = -i;
+		ljust++;		/* XXX should do something with this */
+	    }
+	    while ((ch = *sp++) && --i >= 0 && cp < ep)
+		*cp++ = ch;
+	    while( --i >= 0 && cp < ep)
+		*cp++ = fmt->f_fill;
+	    break;
+
+	case FT_STR:
+	    PUTS (cp, str);
+	    break;
+	case FT_STRF:
+	    PUTSF (cp, str, fmt->f_width, fmt->f_fill);
+	    break;
+	case FT_STRFW:
+	    adios (NULLCP, "internal error (FT_STRFW)");
+
+	case FT_NUM:
+	    PUTD (cp, value);
+	    break;
+	case FT_NUMF:
+	    PUTDF (cp, value, fmt->f_width, fmt->f_fill);
+	    break;
+
+	case FT_CHAR:
+	    *cp++ = fmt->f_char;
+	    break;
+
+	case FT_DONE:
+	    goto finished;
+
+	case FT_IF_S:
+	    if (!(value = (str && *str))) {
+		fmt += fmt->f_skip;
+		continue;
+	    }
+	    break;
+
+	case FT_IF_S_NULL:
+	    if (!(value = (str == NULLCP || *str == 0))) {
+		fmt += fmt->f_skip;
+		continue;
+	    }
+	    break;
+
+	case FT_IF_V_EQ:
+	    if (value != fmt->f_value) {
+		fmt += fmt->f_skip;
+		continue;
+	    }
+	    break;
+
+	case FT_IF_V_NE:
+	    if (value == fmt->f_value) {
+		fmt += fmt->f_skip;
+		continue;
+	    }
+	    break;
+
+	case FT_IF_V_GT:
+	    if (value <= fmt->f_value) {
+		fmt += fmt->f_skip;
+		continue;
+	    }
+	    break;
+
+	case FT_IF_MATCH:
+	    if (!(value = (str && match (str, fmt->f_text)))) {
+		fmt += fmt->f_skip;
+		continue;
+	    }
+	    break;
+
+	case FT_V_MATCH:
+	    if (str)
+		value = match (str, fmt->f_text);
+	    else
+		value = 0;
+	    break;
+
+	case FT_IF_AMATCH:
+	    if (!(value = (str && uprf (str, fmt->f_text)))) {
+		fmt += fmt->f_skip;
+		continue;
+	    }
+	    break;
+
+	case FT_V_AMATCH:
+	    value = uprf (str, fmt->f_text);
+	    break;
+
+	case FT_S_NONNULL:
+	    value = (str != NULLCP && *str != 0);
+	    break;
+
+	case FT_S_NULL:
+	    value = (str == NULLCP || *str == 0);
+	    break;
+
+	case FT_V_EQ:
+	    value = (fmt->f_value == value);
+	    break;
+
+	case FT_V_NE:
+	    value = (fmt->f_value != value);
+	    break;
+
+	case FT_V_GT:
+	    value = (fmt->f_value > value);
+	    break;
+
+	case FT_GOTO:
+	    fmt += fmt->f_skip;
+	    continue;
+
+	case FT_NOP:
+	    break;
+
+#ifdef MIME_HEADERS
+	case FT_LS_HENCODE:
+	    if (str) {
+		char *ep;
+		if ((ep = malloc((unsigned)strlen(str)*10+1)) == NULL)
+		    adios(NULLCP, "out of memory");
+		(void) exthdr_encode(str, ep, 0, "");
+		(void) strncpy(buffer, ep, BUFSIZ);
+		buffer[BUFSIZ-1] = '\0';
+		str = buffer;
+	    }
+	    break;
+	case FT_LS_HDECODE:
+	    if (str) {
+		char *ep;
+		if ((ep = malloc((unsigned)strlen(str)+1)) == NULL)
+		    adios(NULLCP, "out of memory");
+		(void) exthdr_decode(str, ep);
+		(void) strncpy(buffer, ep, BUFSIZ);
+		buffer[BUFSIZ-1] = '\0';
+		str = buffer;
+	    }
+	    break;
+#endif /* MIME_HEADERS */
+
+	case FT_LS_COMP:
+	    str = fmt->f_comp->c_text;
+	    break;
+	case FT_LS_LIT:
+	    str = fmt->f_text;
+	    break;
+	case FT_LS_GETENV:
+	    if (!(str = getenv (fmt->f_text)))
+		str = "";
+	    break;
+	case FT_LS_MFIND:
+	    if (!(str = m_find (fmt->f_text)))
+		str = "";
+	    break;
+	case FT_LS_TRIM:
+	    if (str) {
+		    register char *xp;
+
+#if 1
+		    (void) strncpy(buffer, str, BUFSIZ);
+		    buffer[BUFSIZ-1] = '\0';
+#else
+		    (void) strcpy(buffer, str);
+#endif
+		    str = buffer;
+#ifdef JAPAN
+		    SKIP_SPACE(str);
+#else /* JAPAN */
+		    while (isspace(*str & 0xff))
+			    str++;
+#endif /* JAPAN */
+		    ljust = 0;
+		    if ((i = fmt->f_width) < 0) {
+			    i = -i;
+			    ljust++;
+		    }
+
+		    if (!ljust && i > 0 && strlen(str) > i)
+			    str[i] = '\0';
+		    xp = str;
+#ifdef JAPAN
+		    sp = str + strlen(str);
+		    while (ch = *xp++) {
+			if (ISCNTRL(ch) || ISSPACE(ch))
+			    continue;
+			if (ch & 0x80) {
+			    if (ch2 = *xp++) {
+				if (! ISJSPACE(ch, ch2))
+				    sp = xp;
+			    } else {
+				sp = xp - 2;
+				break;
+			    }
+			} else
+			    sp = xp;
+		    }
+		    *sp = '\0';
+		    if (ljust && i > 0 && strlen(str) > i) {
+			sp = str + strlen(str) - i;
+			while (ch = *str) {
+			    str++;
+			    if (ch & 0x80)
+				str++;
+			    if (str >= sp)
+				break;
+			}
+		    }
+#else /* JAPAN */
+		    xp += strlen(str) - 1;
+		    while (xp > str && isspace(*xp & 0xff))
+			    *xp-- = '\0';
+		    if (ljust && i > 0 && strlen(str) > i)
+			str += strlen(str) - i;
+#endif /* JAPAN */
+	    }
+	    break;
+
+	case FT_LV_COMPFLAG:
+	    value = fmt->f_comp->c_flags;
+	    break;
+	case FT_LV_COMP:
+	    value = (comp = fmt->f_comp)->c_text ? atoi(comp->c_text) : 0;
+	    break;
+	case FT_LV_LIT:
+	    value = fmt->f_value;
+	    break;
+	case FT_LV_DAT:
+	    value = dat[fmt->f_value];
+	    break;
+	case FT_LV_STRLEN:
+	    value = strlen(str);
+	    break;
+	case FT_LV_CHAR_LEFT:
+	    value = width - (cp - scanl);
+	    break;
+	case FT_LV_PLUS_L:
+	    value += fmt->f_value;
+	    break;
+	case FT_LV_MINUS_L:
+	    value = fmt->f_value - value;
+	    break;
+	case FT_LV_DIVIDE_L:
+	    if (fmt->f_value)
+		value = value / fmt->f_value;
+	    else
+		value = 0;
+	    break;
+	case FT_LV_MODULO_L:
+	    if (fmt->f_value)
+		value = value % fmt->f_value;
+	    else
+		value = 0;
+	    break;
+	case FT_SAVESTR:
+	    savestr = str;
+	    break;
+
+	case FT_LV_SEC:
+	    value = fmt->f_comp->c_tws->tw_sec;
+	    break;
+	case FT_LV_MIN:
+	    value = fmt->f_comp->c_tws->tw_min;
+	    break;
+	case FT_LV_HOUR:
+	    value = fmt->f_comp->c_tws->tw_hour;
+	    break;
+	case FT_LV_MDAY:
+	    value = fmt->f_comp->c_tws->tw_mday;
+	    break;
+	case FT_LV_MON:
+	    value = fmt->f_comp->c_tws->tw_mon + 1;
+	    break;
+	case FT_LS_MONTH:
+	    str = tw_moty[fmt->f_comp->c_tws->tw_mon];
+	    break;
+	case FT_LS_LMONTH:
+	    str = lmonth[fmt->f_comp->c_tws->tw_mon];
+	    break;
+	case FT_LS_ZONE:
+	    str = dtwszone (fmt->f_comp->c_tws);
+	    break;
+	case FT_LV_YEAR:
+#ifndef	YEARMOD
+	    value = fmt->f_comp->c_tws->tw_year;
+#else	/* YEARMOD */
+	    value = (fmt->f_comp->c_tws->tw_year) % 100;
+#endif	/* YEARMOD */
+	    break;
+	case FT_LV_WDAY:
+	    if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP)))
+		set_dotw (tws);
+	    value = tws->tw_wday;
+	    break;
+	case FT_LS_DAY:
+	    if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP)))
+		set_dotw (tws);
+	    str = tw_dotw[tws->tw_wday];
+	    break;
+	case FT_LS_WEEKDAY:
+	    if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP)))
+		set_dotw (tws);
+	    str = tw_ldotw[tws->tw_wday];
+	    break;
+	case FT_LV_YDAY:
+	    value = fmt->f_comp->c_tws->tw_yday;
+	    break;
+	case FT_LV_ZONE:
+	    value = fmt->f_comp->c_tws->tw_zone;
+	    break;
+	case FT_LV_CLOCK:
+	    if ((value = fmt->f_comp->c_tws->tw_clock) == 0)
+		value = twclock(fmt->f_comp->c_tws);
+	    break;
+	case FT_LV_RCLOCK:
+	    if ((l = fmt->f_comp->c_tws->tw_clock) == 0)
+		l = twclock(fmt->f_comp->c_tws);
+	    value = time((time_t *) 0) - l;
+	    break;
+	case FT_LV_DAYF:
+	    if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP)))
+		set_dotw (tws);
+	    switch (fmt->f_comp->c_tws->tw_flags & TW_SDAY) {
+		case TW_SEXP:
+		    value = 1; break;
+		case TW_SIMP:
+		    value = 0; break;
+		default:
+		    value = -1; break;
+	    }
+	case FT_LV_ZONEF:
+	    if ((fmt->f_comp->c_tws->tw_flags & TW_SZONE) == TW_SZEXP)
+		    value = 1;
+	    else
+		    value = -1;
+	    break;
+	case FT_LV_DST:
+	    value = fmt->f_comp->c_tws->tw_flags & TW_DST;
+	    break;
+	case FT_LS_822DATE:
+	    str = dasctime ( fmt->f_comp->c_tws , TW_ZONE);
+	    break;
+	case FT_LS_PRETTY:
+	    str = dasctime ( fmt->f_comp->c_tws, TW_NULL);
+	    break;
+
+	case FT_LS_PERS:
+	    str = fmt->f_comp->c_mn->m_pers;
+	    break;
+	case FT_LS_MBOX:
+	    str = fmt->f_comp->c_mn->m_mbox;
+	    break;
+	case FT_LS_HOST:
+	    str = fmt->f_comp->c_mn->m_host;
+	    break;
+	case FT_LS_PATH:
+	    str = fmt->f_comp->c_mn->m_path;
+	    break;
+	case FT_LS_GNAME:
+	    str = fmt->f_comp->c_mn->m_gname;
+	    break;
+	case FT_LS_NOTE:
+	    str = fmt->f_comp->c_mn->m_note;
+	    break;
+	case FT_LS_822ADDR:
+	    str = adrformat( fmt->f_comp->c_mn );
+	    break;
+	case FT_LV_HOSTTYPE:
+	    value = fmt->f_comp->c_mn->m_type;
+	    break;
+	case FT_LV_INGRPF:
+	    value = fmt->f_comp->c_mn->m_ingrp;
+	    break;
+	case FT_LV_NOHOSTF:
+	    value = fmt->f_comp->c_mn->m_nohost;
+	    break;
+	case FT_LS_ADDR:
+	case FT_LS_FRIENDLY:
+#ifdef BERK
+	    str = fmt->f_comp->c_mn->m_mbox;
+#else	/* not BERK */
+	    if ((mn = fmt -> f_comp -> c_mn) == &fmt_mnull) {
+		str = fmt -> f_comp -> c_text;
+		break;
+	    }
+	    if (fmt -> f_type == FT_LS_ADDR)
+		goto unfriendly;
+	    if (!(str = mn -> m_pers)
+		    && (!(str = get_x400_friendly (mn -> m_mbox, buffer)))) {
+		if (str = mn -> m_note) {
+		    (void) strcpy (buffer, str);
+		    str = buffer;
+		    if (*str == '(')
+			str++;
+		    sp = str + strlen (str) - 1;
+		    if (*sp == ')') {
+			*sp-- = '\0';
+			while (sp >= str)
+			    if (*sp == ' ')
+				*sp-- = '\0';
+			    else
+				break;
+		    }
+		    if (*str)
+			break;
+		}	    
+
+unfriendly: ;
+		switch (mn -> m_type) {
+		    case LOCALHOST:
+		        str = mn -> m_mbox;
+			break;
+		    case UUCPHOST:
+			(void) sprintf (str = buffer, "%s!%s",
+					mn -> m_host, mn -> m_mbox);
+			break;
+		    default:
+			if (mn -> m_mbox)
+			    (void) sprintf (str= buffer, "%s@%s", mn -> m_mbox,
+					    mn -> m_host);
+			else
+			    str = mn -> m_text;
+			break;
+		}
+	    }
+#endif	/* BERK */
+	    break;
+
+	case FT_LOCALDATE:
+	    comp = fmt->f_comp;
+	    if ((l = comp->c_tws->tw_clock) == 0)
+		l = twclock(comp->c_tws);
+	    tws = dlocaltime(&l);
+	    *comp->c_tws = *tws;
+	    break;
+
+	case FT_GMTDATE:
+	    comp = fmt->f_comp;
+	    if ((l = comp->c_tws->tw_clock) == 0)
+		l = twclock(comp->c_tws);
+	    tws = dgmtime(&l);
+	    *comp->c_tws = *tws;
+	    break;
+
+	case FT_PARSEDATE:
+	    comp = fmt->f_comp;
+	    if ((sp = comp->c_text) && (tws = dparsetime(sp))) {
+		*comp->c_tws = *tws;
+		comp->c_flags = 0;
+	    } else if (comp->c_flags >= 0) {
+		bzero ((char *) comp -> c_tws, sizeof *comp -> c_tws);
+		comp->c_flags = 1;
+	    }
+	    break;
+
+	case FT_FORMATADDR:
+	    /* hook for custom address list formatting (see replsbr.c) */
+	    str = formataddr (savestr, str);
+	    break;
+
+	case FT_PUTADDR:
+	    /* output the str register as an address component,
+	     * splitting it into multiple lines if necessary.  The
+	     * value reg. contains the max line length.  The lit.
+	     * field may contain a string to prepend to the result
+	     * (e.g., "To: ")
+	     */
+	    {
+	    register char *lp = str;
+	    register int indent;
+	    register int wid = value;
+	    register int len = strlen (str);
+	    register char *lastb;
+
+	    sp = fmt->f_text;
+	    indent = strlen (sp);
+	    wid -= indent;
+	    if (wid <= 0) wid = 1; /* avoid core dump */
+	    while ((ch = *sp++) && (cp < ep))
+		*cp++ = ch;
+	    while (len > wid) {
+		/* try to break at a comma; failing that, break at a
+		 * space, failing that, just split the line.
+		 */
+		lastb = 0; sp = lp + wid;
+		while (sp > lp && (ch = *--sp) != ',') {
+		    if (! lastb && isspace(ch))
+			lastb = sp - 1;
+		}
+		if (sp == lp)
+		    if (! (sp = lastb)) {
+			sp = lp + wid - 1;
+#ifdef MIME_HEADERS
+			if (uprf(lp + (*lp == '(' ? 1 : 0), "=?")) {
+			    /* avoid to split MIME encoded-word */
+			    char *pp;
+			    for (pp = sp + 1; *pp && !isspace(*pp & 0xff); pp++)
+				;
+			    if (uprf(pp - (*(pp-1) == ')' ? 3 : 2), "?=")) {
+				int l = pp - lp;
+				if (l <= 75 && indent + l > 76) {
+				    int i;
+				    for (i = indent + l - 76; i > 0; i--)
+					if (*(cp - i) != ' ') {
+					    *cp++ = '\n';
+					    for (i = 0; i < 76 - l; i++)
+						*cp++ = ' ';
+					    break;
+					}
+				    if (i == 0)
+					cp -= indent + l - 76;
+				}
+				sp = pp - 1;
+			    }
+			}
+#endif /* MIME_HEADERS */
+		    } else
+			while (sp >= lp && isspace(*sp & 0xff))
+			    sp--;
+		len -= sp - lp + 1;
+		while (cp < ep && lp <= sp)
+		    *cp++ = *lp++;
+		while (isspace(*lp & 0xff))
+		    lp++, len--;
+		if (*lp) {
+		    *cp++ = '\n';
+		    for (i=indent; cp < ep && i > 0; i--)
+			*cp++ = ' ';
+		}
+	    }
+	    PUTS (cp, lp);
+	    }
+	    break;
+
+	case FT_PARSEADDR:
+	    comp = fmt->f_comp;
+	    if (comp->c_mn != &fmt_mnull)
+		mnfree (comp->c_mn);
+	    if ((sp = comp->c_text) && (sp = getname(sp)) &&
+		(mn = getm (sp, NULLCP, 0, fmt_norm, NULLCP))) {
+		comp->c_mn = mn;
+		while (getname(""))
+		    ;
+	    } else {
+		while (getname(""))		/* XXX */
+		    ;
+		comp->c_mn = &fmt_mnull;
+	    }
+	    break;
+	    
+	case FT_MYMBOX:
+	    /*
+	     * if there's no component, we say true.  Otherwise we
+	     * say "true" only if we can parse the address and it
+	     * matches one of our addresses.
+	     */
+	    comp = fmt->f_comp;
+	    if (comp->c_mn != &fmt_mnull)
+		mnfree (comp->c_mn);
+	    if ((sp = comp->c_text) && (sp = getname(sp)) &&
+		(mn = getm (sp, NULLCP, 0, AD_NAME, NULLCP))) {
+		comp->c_mn = mn;
+		comp->c_flags = ismymbox(mn);
+		while (sp = getname(sp))
+		    if (comp->c_flags == 0 &&
+			(mn = getm (sp, NULLCP, 0, AD_NAME, NULLCP)))
+			comp->c_flags |= ismymbox(mn);
+	    } else {
+		while (getname(""))		/* XXX */
+		    ;
+		comp->c_flags = (comp->c_text == 0);
+		comp->c_mn = &fmt_mnull;
+	    }
+	    break;
+
+	case FT_ADDTOSEQ:
+#ifdef	LBL
+	    /* If we're working on a folder (as opposed to a file), add the
+	     * current msg to sequence given in literal field.  Don't
+	     * disturb string or value registers.
+	     */
+	    if (fmt_current_folder)
+		    (void)m_seqadd(fmt_current_folder, fmt->f_text, dat[0], -1);
+#endif
+	    break;
+	}
+	fmt++;
+    }
+#ifndef JLR
+    finished:;
+    if (cp[-1] != '\n')
+	*cp++ = '\n';
+    *cp   = 0;
+    return ((struct format *)0);
+#else	/* JLR */
+    if (cp[-1] != '\n')
+	*cp++ = '\n';
+    while (fmt->f_type != FT_DONE)
+	fmt++;
+
+    finished:;    
+    *cp = '\0';
+    return (fmt -> f_value ? ++fmt : (struct format *)0);
+
+#endif /* JLR */
+}