X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/dc4d0c4bf247cfc88e1f3f9463fa2264d3d226b5..366cc6fc4c7bf1eed47cc9b52d0ef809b2e90174:/sbr/fmt_scan.c diff --git a/sbr/fmt_scan.c b/sbr/fmt_scan.c index 207692fc..f9aee54b 100644 --- a/sbr/fmt_scan.c +++ b/sbr/fmt_scan.c @@ -8,12 +8,19 @@ * fmt_compile (found in fmt_compile.c). */ -#include -#include -#include -#include -#include -#include +#include "h/mh.h" +#include "fmt_addr.h" +#include "dtime.h" +#include "strindex.h" +#include "fmt_rfc2047.h" +#include "uprf.h" +#include "context_find.h" +#include "error.h" +#include "h/addrsbr.h" +#include "h/fmt_scan.h" +#include "h/tws.h" +#include "h/fmt_compile.h" +#include "h/utils.h" #include "unquote.h" #ifdef HAVE_SYS_TIME_H @@ -63,56 +70,66 @@ match (char *str, char *sub) return 1; } -/* - * copy a number to the destination subject to a maximum width - */ +/* cpnumber formats num as a signed decimal, + * appending it to dest if the result doesn't exceed max. + * The absolute value of width is the minimum width to produce. + * A smaller string is padded; + * on the left if width is positive, else the right. + * Left-padding uses fill. It is either ' ' or '0'. + * Right-padding is always with space. */ void -cpnumber(charstring_t dest, int num, int wid, char fill, size_t max) +cpnumber(charstring_t dest, int num, int width, 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; - - do { - charstring_push_back (rev, i % 10 + '0'); - i /= 10; - } while (--wid > 0 && i > 0); - if (i > 0) { - /* Overflowed the field (wid). */ - charstring_push_back (rev, '?'); - } else if (num < 0 && wid > 0) { - /* Shouldn't need the wid > 0 check, that's why the condition - at the top checks wid < max-1 when num < 0. */ - --wid; - if (fill == ' ') { - charstring_push_back (rev, '-'); - } - } - while (wid-- > 0 && fill != 0) { - charstring_push_back (rev, fill); - } - if (num < 0 && fill == '0') { - charstring_push_back (rev, '-'); - } + if (width == 0 || width == INT_MIN) { + return; + } - { - /* Output the string in reverse. */ - size_t b = charstring_bytes (rev); - const char *cp = b ? &charstring_buffer (rev)[b] : NULL; + bool padright = width < 0; + if (padright) { + width = -width; /* Can't overflow after above check. */ + } + size_t w = width; + if (w > max) { + return; /* The padded result can't fit. */ + } + if (num < 0 && w == 1) { + return; /* No room for `-' and a digit or `?'. */ + } - for (; b > 0; --b) { - charstring_push_back (dest, *--cp); - } - } + char *s = m_str(num); + size_t len = strlen(s); + if (len == w) { + charstring_append_cstring(dest, s); + return; + } - charstring_free (rev); + bool neg = *s == '-'; + if (len < w) { + if (padright) { + charstring_append_cstring(dest, s); + while (len++ < w) { + charstring_push_back(dest, ' '); + } + return; + } + + if (neg && fill == '0') { + charstring_push_back(dest, *s++); + } + while (len++ < w) { + charstring_push_back(dest, fill); + } + charstring_append_cstring(dest, s); + return; + } + + /* Transform 1234567 -> 1234?67 and -1234567 -> 1234-?7. */ + char *news = s + len - w; + if (neg) { + *news = '-'; } + news[neg] = '?'; + charstring_append_cstring(dest, news); } /* @@ -230,9 +247,9 @@ static void cpstripped (charstring_t dest, size_t max, char *str) { static bool deja_vu; - static char *oddchar; + static char oddchar[MB_LEN_MAX * 2]; static size_t oddlen; - static char *spacechar; + static char spacechar[MB_LEN_MAX * 2]; static size_t spacelen; char *end; bool squash; @@ -242,19 +259,12 @@ cpstripped (charstring_t dest, size_t max, char *str) int w; if (!deja_vu) { - size_t two; - deja_vu = true; - two = MB_CUR_MAX * 2; /* Varies at run-time. */ - - oddchar = mh_xmalloc(two); - oddlen = wcstombs(oddchar, L"?", two); + oddlen = wcstombs(oddchar, L"?", sizeof oddchar); assert(oddlen > 0); - assert(wcwidth(L' ') == 1); /* Need to pad in ones. */ - spacechar = mh_xmalloc(two); - spacelen = wcstombs(spacechar, L" ", two); + spacelen = wcstombs(spacechar, L" ", sizeof spacechar); assert(spacelen > 0); } @@ -396,7 +406,10 @@ fmt_scan (struct format *format, charstring_t scanlp, int width, int *dat, struct fmt_callbacks *callbacks) { char *sp; - char *savestr, *str; + /* If str points to part of buffer[] or buffer2[] then it must only + * ever point at their first element as otherwise undefined + * behaviour from overlapping strncpy(3)s can result. */ + char *str, *savestr; char buffer[NMH_BUFSIZ], buffer2[NMH_BUFSIZ]; int i, c; bool rjust; @@ -740,6 +753,7 @@ fmt_scan (struct format *format, charstring_t scanlp, int width, int *dat, *xp-- = '\0'; if (rjust && i > 0 && (int) strlen(str) > i) str += strlen(str) - i; + str = memmove(buffer, str, strlen(str) + 1); } break; @@ -774,15 +788,18 @@ fmt_scan (struct format *format, charstring_t scanlp, int width, int *dat, value *= fmt->f_value; break; case FT_LV_DIVIDE_L: - if (fmt->f_value) - value /= fmt->f_value; - else + if (fmt->f_value == 0 || (fmt->f_value == -1 && value == INT_MIN)) { + // FIXME: Tell the user, and probably stop. value = 0; + } else { + value /= fmt->f_value; + } break; case FT_LV_MODULO_L: if (fmt->f_value) value %= fmt->f_value; else + // FIXME: Tell the user, and probably stop. value = 0; break; case FT_SAVESTR: @@ -929,6 +946,7 @@ fmt_scan (struct format *format, charstring_t scanlp, int width, int *dat, else break; } + str = memmove(buffer, str, strlen(str) + 1); } else if (!(str = get_x400_friendly (mn->m_mbox, buffer, sizeof(buffer)))) { unfriendly: @@ -1130,7 +1148,11 @@ fmt_scan (struct format *format, charstring_t scanlp, int width, int *dat, comp->c_mn will be run through FT_LS_ADDR, which will strip off any pers name. */ - free (comp->c_text); + /* NB: We remove the call to free() here + because it interferes with the buffer + management in scansbr.c. Revisit this + when we clean up memory handling */ + /* free (comp->c_text); */ comp->c_text = str = strdup (mn->m_text); comp->c_mn = mn; }