X-Git-Url: http://git.marmaro.de/?p=mmh;a=blobdiff_plain;f=sbr%2Ffmt_scan.c;h=c049ad43b73fbfe261d86e1384a35a1eb5b61e80;hp=4365e350c39f8b1aae6bd457ebb089e0379cdcf7;hb=84591551ae36c592f59bd369027397ef9f934602;hpb=b3f36786e62ff7b708849e05d0cac2f55f37e6a5 diff --git a/sbr/fmt_scan.c b/sbr/fmt_scan.c index 4365e35..c049ad4 100644 --- a/sbr/fmt_scan.c +++ b/sbr/fmt_scan.c @@ -25,6 +25,7 @@ # include # endif #endif +#include #define NFMTS MAXARGS @@ -86,111 +87,146 @@ match (char *str, char *sub) } /* - * macros to format data + * copy a number to the destination subject to a maximum width */ +static void +cpnumber(char **dest, int num, unsigned int wid, char fill, size_t n) { + int i, c; + char *sp; + char *cp = *dest; + char *ep = cp + n; + + 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; + } + *dest = cp; +} -#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;\ - } +/* + * copy string from str to dest padding with the fill character to a size + * of wid characters. if wid is negative, the string is right aligned + * no more than n bytes are copied + */ +static void +cptrimmed(char **dest, char *str, unsigned int wid, char fill, size_t n) { + int remaining; /* remaining output width available */ + int c, ljust, w; + int end; /* number of input bytes remaining in str */ + int char_len; /* bytes in current character */ + wchar_t wide_char; + char *sp; /* current position in source string */ + char *cp = *dest; /* current position in destination string */ + char *ep = cp + n; /* end of destination buffer */ + int prevCtrl = 1; + + /* get alignment */ + ljust = 0; + if ((remaining = (wid)) < 0) { + remaining = -remaining; + ljust++; + } + if ((sp = (str))) { + mbtowc(NULL, NULL, 0); /* reset shift state */ + end = strlen(str); + while (*sp && remaining > 0 && end > 0) { + char_len = mbtowc(&wide_char, sp, end); + if (char_len <= 0 || (cp + char_len > ep)) + break; -#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++ = ' ';\ - }\ - }\ - } + end -= char_len; -#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;\ + if (iswcntrl(wide_char) || iswspace(wide_char)) { + sp += char_len; + if (!prevCtrl) { + *cp++ = ' '; + remaining--; } -#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++ = ' ';\ - }\ - }\ - } + prevCtrl = 1; + continue; + } + prevCtrl = 0; + + w = wcwidth(wide_char); + if (w >= 0 && remaining >= w) { + strncpy(cp, sp, char_len); + cp += char_len; + remaining -= w; + } + sp += char_len; + } + } -#endif /* LOCALE */ + if (ljust) { + if (cp + remaining > ep) + remaining = ep - cp; + ep = cp + remaining; + if (remaining > 0) { + /* copy string to the right */ + while (--cp >= *dest) + *(cp + remaining) = *cp; + /* add padding at the beginning */ + cp += remaining; + for (c=remaining; c>0; c--) + *cp-- = fill; + } + *dest = ep; + } else { + /* pad remaining space */ + while (remaining-- > 0 && cp < ep) + *cp++ = fill; + *dest = cp; + } +} +static void +cpstripped (char **start, char *end, char *str) +{ + int c; + char *s = str; + + if (!s) + return; + + /* skip any initial control characters or spaces */ + while ((c = (unsigned char) *s) && +#ifdef LOCALE + (iscntrl(c) || isspace(c))) +#else + (c <= 32)) +#endif + s++; + + /* compact repeated control characters and spaces into a single space */ + while((c = (unsigned char) *s++) && *start < end) + if (!iscntrl(c) && !isspace(c)) + *(*start)++ = c; + else { + while ((c = (unsigned char) *s) && +#ifdef LOCALE + (iscntrl(c) || isspace(c))) +#else + (c <= 32)) +#endif + s++; + *(*start)++ = ' '; + } +} static char *lmonth[] = { "January", "February","March", "April", "May", "June", "July", "August", @@ -271,10 +307,10 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) switch (fmt->f_type) { case FT_COMP: - PUTS (cp, fmt->f_comp->c_text); + cpstripped (&cp, ep, fmt->f_comp->c_text); break; case FT_COMPF: - PUTSF (cp, fmt->f_comp->c_text, fmt->f_width, fmt->f_fill); + cptrimmed (&cp, fmt->f_comp->c_text, fmt->f_width, fmt->f_fill, ep - cp); break; case FT_LIT: @@ -297,10 +333,10 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) break; case FT_STR: - PUTS (cp, str); + cpstripped (&cp, ep, str); break; case FT_STRF: - PUTSF (cp, str, fmt->f_width, fmt->f_fill); + cptrimmed (&cp, str, fmt->f_width, fmt->f_fill, ep - cp); break; case FT_STRFW: adios (NULL, "internal error (FT_STRFW)"); @@ -310,12 +346,7 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) if (n >= 0) cp += n; break; case FT_NUMF: - n = snprintf(cp, ep - cp, "%d", value); - if (n >= 0) { - cp += n; - } else n = 0; - c = abs(fmt->f_width) - n; - for (; (c > 0) && (cp < ep); c--) *cp++ = fmt->f_fill; + cpnumber (&cp, value, fmt->f_width, fmt->f_fill, ep - cp); break; case FT_CHAR: @@ -428,14 +459,14 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) 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; @@ -444,6 +475,7 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) char *xp; strncpy(buffer, str, sizeof(buffer)); + buffer[sizeof(buffer)-1] = '\0'; str = buffer; while (isspace(*str)) str++; @@ -632,6 +664,7 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) 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++; @@ -670,6 +703,40 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) } 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: comp = fmt->f_comp; if ((t = comp->c_tws->tw_clock) == 0) @@ -754,7 +821,7 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) *cp++ = ' '; } } - PUTS (cp, lp); + cpstripped (&cp, ep, lp); } break; @@ -776,7 +843,7 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) comp->c_mn = &fmt_mnull; } break; - + case FT_MYMBOX: /* * if there's no component, we say true. Otherwise we @@ -834,7 +901,7 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) while (fmt->f_type != FT_DONE) fmt++; - finished:; + finished:; *cp = '\0'; return (fmt->f_value ? ++fmt : (struct format *) 0);