X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/275cd091960ac836c4ccb3b7e07ceeda6df7ddd7..94187a80bd60baab4b9c4b949ad820d730578123:/sbr/fmt_scan.c diff --git a/sbr/fmt_scan.c b/sbr/fmt_scan.c index ec60e1ba..791146a2 100644 --- a/sbr/fmt_scan.c +++ b/sbr/fmt_scan.c @@ -1,6 +1,4 @@ - -/* - * fmt_scan.c -- format string interpretation +/* fmt_scan.c -- format string interpretation * * This code is Copyright (c) 2002, by the authors of nmh. See the * COPYRIGHT file in the root directory of the nmh distribution for @@ -16,6 +14,7 @@ #include #include #include +#include "unquote.h" #ifdef HAVE_SYS_TIME_H # include @@ -32,7 +31,7 @@ struct mailname fmt_mnull = { NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, /* * static prototypes */ -static int match (char *, char *); +static int match (char *, char *) PURE; static char *get_x400_friendly (char *, char *, int); static int get_x400_comp (char *, char *, char *, int); @@ -49,24 +48,14 @@ match (char *str, char *sub) char *s1, *s2; while ((c1 = *sub)) { - 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)) + c1 = tolower((unsigned char)c1); + while ((c2 = *str++) && c1 != tolower((unsigned char)c2)) ; if (! c2) return 0; s1 = sub + 1; s2 = str; - 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)) + while ((c1 = *s1++) && + tolower((unsigned char)c1) == tolower((unsigned char)(c2 = *s2++))) ; if (! c1) return 1; @@ -78,8 +67,13 @@ match (char *str, char *sub) * copy a number to the destination subject to a maximum width */ void -cpnumber(charstring_t dest, int num, unsigned int wid, char fill, size_t max) { - if (wid < (num >= 0 ? max : max-1)) { +cpnumber(charstring_t dest, int num, int wid, char fill, size_t max) { + /* Maybe we should handle left padding at some point? */ + if (wid == 0) + return; + if (wid < 0) + wid = -wid; /* OK because wid originally a short. */ + if ((size_t)wid < (num >= 0 ? max : max-1)) { /* Build up the string representation of num in reverse. */ charstring_t rev = charstring_create (0); int i = num >= 0 ? num : -num; @@ -129,6 +123,7 @@ void cptrimmed(charstring_t dest, char *str, int wid, char fill, size_t max) { int remaining; /* remaining output width available */ int rjust; + struct charstring *trimmed; size_t end; /* number of input bytes remaining in str */ #ifdef MULTIBYTE_SUPPORT int char_len; /* bytes in current character */ @@ -147,6 +142,8 @@ cptrimmed(charstring_t dest, char *str, int wid, char fill, size_t max) { } if (remaining > (int) max) { remaining = max; } + trimmed = rjust ? charstring_create(remaining) : dest; + if ((sp = str)) { #ifdef MULTIBYTE_SUPPORT if (mbtowc(NULL, NULL, 0)) {} /* reset shift state */ @@ -192,7 +189,7 @@ cptrimmed(charstring_t dest, char *str, int wid, char fill, size_t max) { sp++; #endif if (!prevCtrl) { - charstring_push_back (dest, ' '); + charstring_push_back (trimmed, ' '); remaining--; } @@ -203,122 +200,146 @@ cptrimmed(charstring_t dest, char *str, int wid, char fill, size_t max) { #ifdef MULTIBYTE_SUPPORT if (w >= 0 && remaining >= w) { - charstring_push_back_chars (dest, altstr ? altstr : sp, + charstring_push_back_chars (trimmed, altstr ? altstr : sp, char_len, w); remaining -= w; altstr = NULL; } sp += char_len; #else - charstring_push_back (dest, *sp++); + charstring_push_back (trimmed, *sp++); remaining--; #endif } } - if (rjust) { - if (remaining > 0) { - /* copy string to the right */ - charstring_t copy = charstring_copy (dest); - - /* add padding at the beginning */ - charstring_clear (dest); - for (; remaining > 0; --remaining) { - charstring_push_back (dest, fill); - } - - charstring_append (dest, copy); + while (remaining-- > 0) { + charstring_push_back(dest, fill); + } - charstring_free (copy); - } - } else { - /* pad remaining space */ - while (remaining-- > 0) { - charstring_push_back (dest, fill); - } + if (rjust) { + charstring_append(dest, trimmed); + charstring_free(trimmed); } } +#ifdef MULTIBYTE_SUPPORT static void cpstripped (charstring_t dest, size_t max, char *str) { - int prevCtrl = 1; /* This is 1 so we strip out leading spaces */ - int len; -#ifdef MULTIBYTE_SUPPORT - int char_len, w; - wchar_t wide_char; - char *altstr = NULL; -#endif /* MULTIBYTE_SUPPORT */ + static bool deja_vu; + static char *oddchar; + static size_t oddlen; + static char *spacechar; + static size_t spacelen; + char *end; + bool squash; + char *src; + int srclen; + wchar_t rune; + int w; - if (!str) { - return; - } + if (!deja_vu) { + size_t two; - len = strlen(str); + deja_vu = true; -#ifdef MULTIBYTE_SUPPORT - if (mbtowc(NULL, NULL, 0)) {} /* Reset shift state */ -#endif /* MULTIBYTE_SUPPORT */ + two = MB_CUR_MAX * 2; /* Varies at run-time. */ - /* - * Process each character at a time; if we have multibyte support - * then deal with that here. - */ + oddchar = mh_xmalloc(two); + oddlen = wcstombs(oddchar, L"?", two); + assert(oddlen > 0); - while (*str != '\0' && len > 0 && max > 0) { -#ifdef MULTIBYTE_SUPPORT - char_len = mbtowc(&wide_char, str, len); - w = wcwidth(wide_char); + assert(wcwidth(L' ') == 1); /* Need to pad in ones. */ + spacechar = mh_xmalloc(two); + spacelen = wcstombs(spacechar, L" ", two); + assert(spacelen > 0); + } - /* - * If mbrtowc() failed, then we have a character that isn't valid - * in the current encoding. Replace it with a '?'. We do that by - * setting the alstr variable to the value of the replacement string; - * altstr is used below when the bytes are copied into the output - * buffer. - */ + if (!str) + return; /* It's unclear why no padding in this case. */ + end = str + strlen(str); + + if (mbtowc(NULL, NULL, 0)) + {} /* Reset shift state. */ + + squash = true; /* Trim `space' or `cntrl' from the start. */ + while (max) { + if (!*str) + return; /* It's unclear why no padding in this case. */ + + srclen = mbtowc(&rune, str, end - str); + if (srclen == -1) { + /* Invalid rune, or not enough bytes to finish it. */ + rune = L'?'; + src = oddchar; + srclen = oddlen; + str++; /* Skip one byte. */ + } else { + src = str; + str += srclen; + } - if (char_len < 0) { - altstr = "?"; - char_len = mbtowc(&wide_char, altstr, 1); - } + if (iswspace(rune) || iswcntrl(rune)) { + if (squash) + continue; /* Amidst a run of these. */ + rune = L' '; + src = spacechar; + srclen = spacelen; + squash = true; + } else + squash = false; + + w = wcwidth(rune); + if (w == -1) { + rune = L'?'; + w = wcwidth(rune); + assert(w != -1); + src = oddchar; + srclen = oddlen; + } - if (char_len <= 0) { - break; - } + if ((size_t)w > max) { + /* No room for rune; pad. */ + while (max--) + charstring_push_back_chars(dest, spacechar, spacelen, 1); + return; + } - len -= char_len; - - if (iswcntrl(wide_char) || iswspace(wide_char)) { - str += char_len; -#else /* MULTIBYTE_SUPPORT */ - int c = (unsigned char) *str; - len--; - if (iscntrl(c) || isspace(c)) { - str++; -#endif /* MULTIBYTE_SUPPORT */ - if (! prevCtrl) { - charstring_push_back (dest, ' '); - --max; - } + charstring_push_back_chars(dest, src, srclen, w); + max -= w; + } +} +#endif - prevCtrl = 1; - continue; - } +#ifndef MULTIBYTE_SUPPORT +static void +cpstripped (charstring_t dest, size_t max, char *str) +{ + bool squash; + int c; - prevCtrl = 0; + if (!str) + return; -#ifdef MULTIBYTE_SUPPORT - charstring_push_back_chars (dest, altstr ? altstr : str, char_len, w); - max -= w; - str += char_len; - altstr = NULL; -#else /* MULTIBYE_SUPPORT */ - charstring_push_back (dest, *str++); - --max; -#endif /* MULTIBYTE_SUPPORT */ + squash = true; /* Strip leading cases. */ + while (max--) { + c = (unsigned char)*str++; + if (!c) + return; + + if (isspace(c) || iscntrl(c)) { + if (squash) + continue; + c = ' '; + squash = true; + } else + squash = false; + + charstring_push_back(dest, (char)c); } } +#endif static char *lmonth[] = { "January", "February","March", "April", "May", "June", "July", "August", @@ -374,7 +395,7 @@ fmt_scan (struct format *format, charstring_t scanlp, int width, int *dat, { char *sp; char *savestr, *str; - char buffer[BUFSIZ], buffer2[BUFSIZ]; + char buffer[NMH_BUFSIZ], buffer2[NMH_BUFSIZ]; int i, c, rjust; int value; time_t t; @@ -482,7 +503,7 @@ fmt_scan (struct format *format, charstring_t scanlp, int width, int *dat, int num = value; unsigned int wid; - for (wid = num <= 0 ? 1 : 0; num; ++wid, num /= 10) {} + for (wid = num <= 0; num; ++wid, num /= 10) {} cpnumber (scanlp, value, wid, ' ', max - charstring_chars (scanlp)); break; @@ -696,7 +717,8 @@ fmt_scan (struct format *format, charstring_t scanlp, int width, int *dat, if (str) { char *xp; - strncpy(buffer, str, sizeof(buffer)); + if (str != buffer) + strncpy(buffer, str, sizeof(buffer)); buffer[sizeof(buffer)-1] = '\0'; str = buffer; while (isspace((unsigned char) *str)) @@ -750,13 +772,13 @@ fmt_scan (struct format *format, charstring_t scanlp, int width, int *dat, break; case FT_LV_DIVIDE_L: if (fmt->f_value) - value = value / fmt->f_value; + value /= fmt->f_value; else value = 0; break; case FT_LV_MODULO_L: if (fmt->f_value) - value = value % fmt->f_value; + value %= fmt->f_value; else value = 0; break; @@ -819,7 +841,7 @@ fmt_scan (struct format *format, charstring_t scanlp, int width, int *dat, case FT_LV_RCLOCK: if ((value = fmt->f_comp->c_tws->tw_clock) == 0) value = dmktime(fmt->f_comp->c_tws); - value = time((time_t *) 0) - value; + value = time(NULL) - value; break; case FT_LV_DAYF: if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP))) @@ -834,7 +856,7 @@ fmt_scan (struct format *format, charstring_t scanlp, int width, int *dat, } break; case FT_LV_ZONEF: - if ((fmt->f_comp->c_tws->tw_flags & TW_SZONE) == TW_SZEXP) + if (fmt->f_comp->c_tws->tw_flags & TW_SZEXP) value = 1; else value = -1; @@ -889,7 +911,8 @@ fmt_scan (struct format *format, charstring_t scanlp, int width, int *dat, goto unfriendly; if ((str = mn->m_pers) == NULL) { if ((str = mn->m_note)) { - strncpy (buffer, str, sizeof(buffer)); + if (str != buffer) + strncpy (buffer, str, sizeof(buffer)); buffer[sizeof(buffer)-1] = '\0'; str = buffer; if (*str == '(') @@ -933,7 +956,8 @@ fmt_scan (struct format *format, charstring_t scanlp, int width, int *dat, /* UNQUOTEs RFC-2822 quoted-string and quoted-pair */ case FT_LS_UNQUOTE: if (str) { - strncpy(buffer, str, sizeof(buffer)); + if (str != buffer) + strncpy(buffer, str, sizeof(buffer)); /* strncpy doesn't NUL-terminate if it fills the buffer */ buffer[sizeof(buffer)-1] = '\0'; unquote_string(buffer, buffer2); @@ -965,7 +989,7 @@ fmt_scan (struct format *format, charstring_t scanlp, int width, int *dat, *comp->c_tws = *tws; comp->c_flags &= ~CF_TRUE; } else if ((comp->c_flags & CF_DATEFAB) == 0) { - memset (comp->c_tws, 0, sizeof *comp->c_tws); + ZERO(comp->c_tws); comp->c_flags = CF_TRUE; } comp->c_flags |= CF_PARSED; @@ -1182,5 +1206,5 @@ fmt_scan (struct format *format, charstring_t scanlp, int width, int *dat, } } - return ((struct format *)0); + return NULL; }