* fmt_scan.c -- format string interpretation
*
* $Id$
+ *
+ * This code is Copyright (c) 2002, by the authors of nmh. See the
+ * COPYRIGHT file in the root directory of the nmh distribution for
+ * complete copyright information.
*/
#include <h/mh.h>
#include <h/addrsbr.h>
#include <h/fmt_scan.h>
-#include <zotnet/tws/tws.h>
+#include <h/tws.h>
#include <h/fmt_compile.h>
#ifdef TIME_WITH_SYS_TIME
/*
* macros to format data
*/
-
#define PUTDF(cp, num, wid, fill)\
if (cp + wid < ep) {\
if ((i = (num)) < 0)\
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 (c <= i) \
- c *= 10;\
- while (cp < ep && c > 1) {\
- c /= 10;\
- *cp++ = (i / c) + '0';\
- i %= c;\
- }\
- }\
- }
+char * PUTSF(char *cp, char *str, unsigned int wid, char fill) {
+
+ unsigned int i, j;
+ unsigned int char_len;
+ unsigned int term_len = 0;
+ wchar_t wide_char;
+
+ for (i = 0 ; i < wid && i < strlen(str) && term_len < wid; ) {
+ char_len = mblen(str + i, strlen(str + i));
+ if (char_len <= 0) {
+ continue;
+ }
+ mbtowc(&wide_char, str + i, strlen(str + i));
+ term_len += wcwidth(wide_char);
+
+ for (j = 0 ; j < char_len ; j++) {
+ *(cp + i) = *(str + i);
+ i++;
+ }
+ }
-#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;\
- }
+ if (term_len < wid) {
+ for (j = term_len ; j <= wid ; j++) {
+ *(cp + i++) = fill;
+ }
+ i--;
+ }
+
+ return cp + i;
+}
#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)) \
+ if (!iscntrl(c) && !isspace(c)) \
*cp++ = c;\
else {\
while ((c = (unsigned char) *sp) && (iscntrl(c) || isspace(c)))\
}\
}
-#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 = *sp) && c <= 32)\
- sp++;\
- }\
- while ((c = *sp++) && --i >= 0 && cp < ep)\
- if (c > 32) \
- *cp++ = c;\
- else {\
- while ((c = *sp) && c <= 32)\
- sp++;\
- *cp++ = ' ';\
- }\
- }\
- if (!ljust)\
- while( --i >= 0 && cp < ep)\
- *cp++ = fill;\
- }
-
-#define PUTS(cp, str) {\
- if (sp = (str)) {\
- while ((c = *sp) && c <= 32)\
- sp++;\
- while( (c = *sp++) && cp < ep)\
- if ( c > 32 ) \
- *cp++ = c;\
- else {\
- while ( (c = *sp) && c <= 32 )\
- sp++;\
- *cp++ = ' ';\
- }\
- }\
- }
-
-#endif /* LOCALE */
-
-
static char *lmonth[] = { "January", "February","March", "April",
"May", "June", "July", "August",
"September","October", "November","December" };
char *cp, *ep, *sp;
char *savestr, *str = NULL;
char buffer[BUFSIZ], buffer2[BUFSIZ];
- int i, c, ljust;
+ int i, c, ljust, n;
int value = 0;
time_t t;
struct format *fmt;
cp = scanl;
ep = scanl + width - 1;
+
+ for (fmt = format; fmt->f_type != FT_DONE; fmt++)
+ switch (fmt->f_type) {
+ case FT_PARSEADDR:
+ case FT_PARSEDATE:
+ fmt->f_comp->c_flags &= ~CF_PARSED;
+ break;
+ }
+
fmt = format;
while (cp < ep) {
PUTS (cp, fmt->f_comp->c_text);
break;
case FT_COMPF:
- PUTSF (cp, fmt->f_comp->c_text, fmt->f_width, fmt->f_fill);
+ cp = PUTSF(cp, fmt->f_comp->c_text, fmt->f_width, fmt->f_fill);
break;
case FT_LIT:
PUTS (cp, str);
break;
case FT_STRF:
- PUTSF (cp, str, fmt->f_width, fmt->f_fill);
+ cp =PUTSF (cp, str, fmt->f_width, fmt->f_fill);
break;
case FT_STRFW:
adios (NULL, "internal error (FT_STRFW)");
case FT_NUM:
- PUTD (cp, value);
+ n = snprintf(cp, ep - cp, "%d", value);
+ if (n >= 0) cp += n;
break;
case FT_NUMF:
PUTDF (cp, value, fmt->f_width, fmt->f_fill);
break;
case FT_LS_DECODECOMP:
- if (decode_rfc2047(fmt->f_comp->c_text, buffer2))
+ if (decode_rfc2047(fmt->f_comp->c_text, buffer2, sizeof(buffer2)))
str = buffer2;
else
str = fmt->f_comp->c_text;
break;
case FT_LS_DECODE:
- if (str && decode_rfc2047(str, buffer2))
+ if (str && decode_rfc2047(str, buffer2, sizeof(buffer2)))
str = buffer2;
break;
char *xp;
strncpy(buffer, str, sizeof(buffer));
+ buffer[sizeof(buffer)-1] = '\0';
str = buffer;
while (isspace(*str))
str++;
break;
case FT_LV_COMPFLAG:
- value = fmt->f_comp->c_flags;
+ value = (fmt->f_comp->c_flags & CF_TRUE) != 0;
break;
case FT_LV_COMP:
value = (comp = fmt->f_comp)->c_text ? atoi(comp->c_text) : 0;
value = dat[fmt->f_value];
break;
case FT_LV_STRLEN:
- value = strlen(str);
+ if (str != NULL)
+ value = strlen(str);
+ else
+ value = 0;
break;
case FT_LV_CHAR_LEFT:
value = width - (cp - scanl);
if ((str = mn->m_pers) == NULL) {
if ((str = mn->m_note)) {
strncpy (buffer, str, sizeof(buffer));
+ buffer[sizeof(buffer)-1] = '\0';
str = buffer;
if (*str == '(')
str++;
}
}
}
+ break;
+
+
+ /* UNQUOTEs RFC-2822 quoted-string and quoted-pair */
+ case FT_LS_UNQUOTE:
+ if (str) {
+ int m;
+ strncpy(buffer, str, sizeof(buffer));
+ /* strncpy doesn't NUL-terminate if it fills the buffer */
+ buffer[sizeof(buffer)-1] = '\0';
+ str = buffer;
+
+ /* we will parse from buffer to buffer2 */
+ n = 0; /* n is the input position in str */
+ m = 0; /* m is the ouput position in buffer2 */
+
+ while ( str[n] != '\0') {
+ switch ( str[n] ) {
+ case '\\':
+ n++;
+ if ( str[n] != '\0')
+ buffer2[m++] = str[n++];
+ break;
+ case '"':
+ n++;
+ break;
+ default:
+ buffer2[m++] = str[n++];
+ break;
+ }
+ }
+ buffer2[m] = '\0';
+ str = buffer2;
+ }
break;
case FT_LOCALDATE:
case FT_PARSEDATE:
comp = fmt->f_comp;
+ if (comp->c_flags & CF_PARSED)
+ break;
if ((sp = comp->c_text) && (tws = dparsetime(sp))) {
*comp->c_tws = *tws;
- comp->c_flags = 0;
- } else if (comp->c_flags >= 0) {
+ comp->c_flags &= ~CF_TRUE;
+ } else if ((comp->c_flags & CF_DATEFAB) == 0) {
memset ((char *) comp->c_tws, 0, sizeof *comp->c_tws);
- comp->c_flags = 1;
+ comp->c_flags = CF_TRUE;
}
+ comp->c_flags |= CF_PARSED;
break;
case FT_FORMATADDR:
len -= sp - lp + 1;
while (cp < ep && lp <= sp)
*cp++ = *lp++;
- *cp++ = '\n';
- for (i=indent; cp < ep && i > 0; i--)
- *cp++ = ' ';
while (isspace(*lp))
lp++, len--;
if (*lp) {
case FT_PARSEADDR:
comp = fmt->f_comp;
+ if (comp->c_flags & CF_PARSED)
+ break;
if (comp->c_mn != &fmt_mnull)
mnfree (comp->c_mn);
if ((sp = comp->c_text) && (sp = getname(sp)) &&
comp->c_mn = mn;
while (getname(""))
;
+ comp->c_flags |= CF_PARSED;
} else {
while (getname("")) /* XXX */
;
if ((sp = comp->c_text) && (sp = getname(sp)) &&
(mn = getm (sp, NULL, 0, AD_NAME, NULL))) {
comp->c_mn = mn;
- comp->c_flags = ismymbox(mn);
+ if (ismymbox(mn))
+ comp->c_flags |= CF_TRUE;
+ else
+ comp->c_flags &= ~CF_TRUE;
while ((sp = getname(sp)))
- if (comp->c_flags == 0 &&
+ if ((comp->c_flags & CF_TRUE) == 0 &&
(mn = getm (sp, NULL, 0, AD_NAME, NULL)))
- comp->c_flags |= ismymbox(mn);
+ if (ismymbox(mn))
+ comp->c_flags |= CF_TRUE;
} else {
while (getname("")) /* XXX */
;
- comp->c_flags = (comp->c_text == 0);
+ if (comp->c_text == 0)
+ comp->c_flags |= CF_TRUE;
+ else
+ comp->c_flags &= ~CF_TRUE;
comp->c_mn = &fmt_mnull;
}
break;