}
struct format *
-fmt_scan (struct format *format, char *scanl, int width, int *dat)
+fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat)
{
char *cp, *ep;
unsigned char *sp;
struct tws *tws;
struct mailname *mn;
+ /* ep keeps track of displayed characters. They're limited by width.
+ The total number of characters, cp - scanl + 1 (for trailing NULL),
+ includes invisible control characters and is limited by max. */
cp = scanl;
- ep = scanl + width - 1;
+ ep = scanl + (width <= (int) max ? width : (int) max) - 1;
for (fmt = format; fmt->f_type != FT_DONE; fmt++)
switch (fmt->f_type) {
while ((c = *sp++) && cp < ep)
*cp++ = c;
break;
+ case FT_STRLITZ: {
+ size_t len = strlen (str);
+
+ /* Don't want to emit part of an escape sequence. So if
+ there isn't enough room in the buffer for the entire
+ string, skip it completely. */
+ if (cp - scanl + len + 1 < max) {
+ for (sp = str; *sp; *cp++ = *sp++) continue;
+
+ /* This string doesn't count against the width. So
+ increase ep the same amount as cp, only if the
+ scan buffer will always be large enough. */
+ if (ep - scanl + len + 1 < max) {
+ ep += len;
+ }
+ }
+
+ break;
+ }
case FT_STRFW:
adios (NULL, "internal error (FT_STRFW)");
fmt++;
}
#ifndef JLR
+ /* Emit any trailing sequences of zero display length. */
+ while (fmt->f_type != FT_DONE) {
+ if (fmt->f_type == FT_LS_LIT) {
+ str = fmt->f_text;
+ } else if (fmt->f_type == FT_STRLITZ) {
+ /* Don't want to emit part of an escape sequence. So if
+ there isn't enough room in the buffer for the entire
+ string, skip it completely. Need room for null
+ terminator, and maybe trailing newline (added below). */
+ if (cp - scanl + strlen (str) + 1 < max) {
+ for (sp = str; *sp; *cp++ = *sp++) continue;
+ }
+ }
+ fmt++;
+ }
+
finished:;
- if (cp[-1] != '\n')
- *cp++ = '\n';
- *cp = 0;
+ if (cp > scanl && cp[-1] != '\n') {
+ if (cp - scanl < (int) max - 1) {
+ *cp++ = '\n';
+ } else {
+ cp[-1] = '\n';
+ }
+ }
+ *cp = '\0';
return ((struct format *)0);
#else /* JLR */
if (cp[-1] != '\n')