diff options
Diffstat (limited to 'lib/printf/vfprintf.c')
| -rw-r--r-- | lib/printf/vfprintf.c | 84 |
1 files changed, 67 insertions, 17 deletions
diff --git a/lib/printf/vfprintf.c b/lib/printf/vfprintf.c index a0634cde4b..3b5bda965a 100644 --- a/lib/printf/vfprintf.c +++ b/lib/printf/vfprintf.c @@ -177,6 +177,7 @@ vbprintfrr(struct fbuf *cb, const char *fmt0, va_list ap) int nextarg; /* 1-based argument index */ va_list orgap; /* original argument pointer */ char *convbuf; /* wide to multibyte conversion result */ + char *extstart = NULL; /* where printfrr_ext* started printing */ static const char xdigs_lower[16] = "0123456789abcdef"; static const char xdigs_upper[16] = "0123456789ABCDEF"; @@ -438,16 +439,14 @@ reswitch: switch (ch) { ulval = SARG(); if (printfrr_ext_char(fmt[0])) { - n2 = printfrr_exti(buf, sizeof(buf), fmt, prec, + if (cb) + extstart = cb->pos; + + size = printfrr_exti(cb, &fmt, prec, (flags & INTMAX_SIZE) ? ujval : (uintmax_t)ulval); - if (n2 > 0) { - fmt += n2; - cp = buf; - size = strlen(cp); - sign = '\0'; - break; - } + if (size >= 0) + goto ext_printed; } if (flags & INTMAX_SIZE) { if ((intmax_t)ujval < 0) { @@ -551,14 +550,13 @@ reswitch: switch (ch) { * -- ANSI X3J11 */ ptrval = GETARG(void *); - if (printfrr_ext_char(fmt[0]) && - (n2 = printfrr_extp(buf, sizeof(buf), - fmt, prec, ptrval)) > 0) { - fmt += n2; - cp = buf; - size = strlen(cp); - sign = '\0'; - break; + if (printfrr_ext_char(fmt[0])) { + if (cb) + extstart = cb->pos; + + size = printfrr_extp(cb, &fmt, prec, ptrval); + if (size >= 0) + goto ext_printed; } ujval = (uintmax_t)(uintptr_t)ptrval; base = 16; @@ -686,7 +684,7 @@ number: if ((dprec = prec) >= 0) realsz += 2; prsize = width > realsz ? width : realsz; - if ((unsigned)ret + prsize > INT_MAX) { + if ((unsigned int)ret + prsize > INT_MAX) { ret = EOF; errno = EOVERFLOW; goto error; @@ -721,6 +719,58 @@ number: if ((dprec = prec) >= 0) ret += prsize; FLUSH(); /* copy out the I/O vectors */ + continue; + +ext_printed: + /* when we arrive here, a printfrr extension has written to cb + * (if non-NULL), but we still need to handle padding. The + * original cb->pos is in extstart; the return value from the + * ext is in size. + * + * Keep analogous to code above please. + */ + + realsz = size; + prsize = width > realsz ? width : realsz; + if ((unsigned int)ret + prsize > INT_MAX) { + ret = EOF; + errno = EOVERFLOW; + goto error; + } + + /* right-adjusting blank padding - need to move the chars + * that the extension has already written. Should be very + * rare. + */ + if (cb && width > size && (flags & (LADJUST|ZEROPAD)) == 0) { + size_t nwritten = cb->pos - extstart; + size_t navail = cb->buf + cb->len - extstart; + size_t npad = width - realsz; + size_t nmove; + + if (navail < npad) + navail = 0; + else + navail -= npad; + nmove = MIN(nwritten, navail); + + memmove(extstart + npad, extstart, nmove); + + cb->pos = extstart; + PAD(npad, blanks); + cb->pos += nmove; + } + + io.avail = cb ? cb->len - (cb->pos - cb->buf) : 0; + + /* left-adjusting padding (always blank) */ + if (flags & LADJUST) + PAD(width - realsz, blanks); + + /* finally, adjust ret */ + ret += prsize; + + FLUSH(); /* copy out the I/O vectors */ } done: FLUSH(); |
