* fmt_compile (found in fmt_compile.c).
*/
-#include <h/mh.h>
-#include <h/addrsbr.h>
-#include <h/fmt_scan.h>
-#include <h/tws.h>
-#include <h/fmt_compile.h>
-#include <h/utils.h>
+#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
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) {
- /* 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, '-');
- }
+cpnumber(charstring_t dest, int num, int width, char fill, size_t max)
+{
+ 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);
}
/*
* aligned no more than max characters are copied
*/
void
-cptrimmed(charstring_t dest, char *str, int wid, char fill, size_t max) {
+cptrimmed(charstring_t dest, char *str, int wid, char fill, size_t max)
+{
int remaining; /* remaining output width available */
- int rjust;
+ bool rjust;
struct charstring *trimmed;
size_t end; /* number of input bytes remaining in str */
#ifdef MULTIBYTE_SUPPORT
char *sp; /* current position in source string */
/* get alignment */
- rjust = 0;
+ rjust = false;
if ((remaining = wid) < 0) {
remaining = -remaining;
- rjust++;
+ rjust = true;
}
if (remaining > (int) max) { remaining = max; }
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;
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);
}
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, rjust;
+ int i, c;
+ bool rjust;
int value;
time_t t;
size_t max;
break;
case FT_LITF:
sp = fmt->f_text;
- rjust = 0;
+ rjust = false;
i = fmt->f_width;
if (i < 0) {
i = -i;
- rjust++; /* XXX should do something with this */
+ rjust = true; /* XXX should do something with this */
}
while ((c = *sp++) && --i >= 0 && charstring_chars (scanlp) < max) {
charstring_push_back (scanlp, c);
str = buffer;
while (isspace((unsigned char) *str))
str++;
- rjust = 0;
+ rjust = false;
if ((i = fmt->f_width) < 0) {
i = -i;
- rjust++;
+ rjust = true;
}
if (!rjust && i > 0 && (int) strlen(str) > i)
*xp-- = '\0';
if (rjust && i > 0 && (int) strlen(str) > i)
str += strlen(str) - i;
+ str = memmove(buffer, str, strlen(str) + 1);
}
break;
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:
else
break;
}
+ str = memmove(buffer, str, strlen(str) + 1);
} else if (!(str = get_x400_friendly (mn->m_mbox,
buffer, sizeof(buffer)))) {
unfriendly:
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;
}