]> git.proxmox.com Git - mirror_frr.git/blob - lib/printf/vfprintf.c
lib: Hide list macros in linklist.c
[mirror_frr.git] / lib / printf / vfprintf.c
1 /*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1990, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Chris Torek.
9 *
10 * Copyright (c) 2011 The FreeBSD Foundation
11 * All rights reserved.
12 * Portions of this software were developed by David Chisnall
13 * under sponsorship from the FreeBSD Foundation.
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in the
22 * documentation and/or other materials provided with the distribution.
23 * 3. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 */
39
40 #ifdef HAVE_CONFIG_H
41 #include "config.h"
42 #endif
43
44 #ifdef HAVE_SYS_CDEFS_H
45 #include <sys/cdefs.h>
46 #endif
47
48 /*
49 * Actual printf innards.
50 *
51 * This code is large and complicated...
52 */
53
54 #include <sys/types.h>
55 #include <sys/uio.h>
56
57 #include <ctype.h>
58 #include <errno.h>
59 #include <limits.h>
60 #include <stddef.h>
61 #include <stdint.h>
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <string.h>
65 #include <wchar.h>
66
67 #include <stdarg.h>
68
69 #include "printflocal.h"
70
71 #define CHAR char
72 #include "printfcommon.h"
73
74 #ifdef WCHAR_SUPPORT
75 /*
76 * Convert a wide character string argument for the %ls format to a multibyte
77 * string representation. If not -1, prec specifies the maximum number of
78 * bytes to output, and also means that we can't assume that the wide char.
79 * string ends is null-terminated.
80 */
81 static char *
82 __wcsconv(wchar_t *wcsarg, int prec)
83 {
84 static const mbstate_t initial;
85 mbstate_t mbs;
86 char buf[MB_LEN_MAX];
87 wchar_t *p;
88 char *convbuf;
89 size_t clen, nbytes;
90
91 /* Allocate space for the maximum number of bytes we could output. */
92 if (prec < 0) {
93 p = wcsarg;
94 mbs = initial;
95 nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs);
96 if (nbytes == (size_t)-1)
97 return NULL;
98 } else {
99 /*
100 * Optimisation: if the output precision is small enough,
101 * just allocate enough memory for the maximum instead of
102 * scanning the string.
103 */
104 if (prec < 128)
105 nbytes = prec;
106 else {
107 nbytes = 0;
108 p = wcsarg;
109 mbs = initial;
110 for (;;) {
111 clen = wcrtomb(buf, *p++, &mbs);
112 if (clen == 0 || clen == (size_t)-1 ||
113 nbytes + clen > (size_t)prec)
114 break;
115 nbytes += clen;
116 }
117 }
118 }
119 if ((convbuf = malloc(nbytes + 1)) == NULL)
120 return NULL;
121
122 /* Fill the output buffer. */
123 p = wcsarg;
124 mbs = initial;
125 if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p,
126 nbytes, &mbs)) == (size_t)-1) {
127 free(convbuf);
128 return NULL;
129 }
130 convbuf[nbytes] = '\0';
131 return (convbuf);
132 }
133 #endif /* WCHAR_SUPPORT */
134
135 /*
136 * The size of the buffer we use as scratch space for integer
137 * conversions, among other things. We need enough space to
138 * write a uintmax_t in octal (plus one byte).
139 */
140 #if UINTMAX_MAX <= UINT64_MAX
141 #define BUF 80
142 #else
143 #error "BUF must be large enough to format a uintmax_t"
144 #endif
145
146 /*
147 * Non-MT-safe version
148 */
149 ssize_t
150 vbprintfrr(struct fbuf *cb_in, const char *fmt0, va_list ap)
151 {
152 const char *fmt; /* format string */
153 int ch; /* character from fmt */
154 int n, n2; /* handy integer (short term usage) */
155 const char *cp; /* handy char pointer (short term usage) */
156 int flags; /* flags as above */
157 int ret; /* return value accumulator */
158 int width; /* width from format (%8d), or 0 */
159 int prec; /* precision from format; <0 for N/A */
160 int saved_errno;
161 char sign; /* sign prefix (' ', '+', '-', or \0) */
162
163 u_long ulval = 0; /* integer arguments %[diouxX] */
164 uintmax_t ujval = 0; /* %j, %ll, %q, %t, %z integers */
165 void *ptrval; /* %p */
166 int base; /* base for [diouxX] conversion */
167 int dprec; /* a copy of prec if [diouxX], 0 otherwise */
168 int realsz; /* field size expanded by dprec, sign, etc */
169 int size; /* size of converted field or string */
170 int prsize; /* max size of printed field */
171 const char *xdigs; /* digits for %[xX] conversion */
172 struct io_state io; /* I/O buffering state */
173 char buf[BUF]; /* buffer with space for digits of uintmax_t */
174 char ox[2]; /* space for 0x; ox[1] is either x, X, or \0 */
175 union arg *argtable; /* args, built due to positional arg */
176 union arg statargtable [STATIC_ARG_TBL_SIZE];
177 int nextarg; /* 1-based argument index */
178 va_list orgap; /* original argument pointer */
179 char *convbuf; /* wide to multibyte conversion result */
180 char *extstart = NULL; /* where printfrr_ext* started printing */
181 struct fbuf cb_copy, *cb;
182 struct fmt_outpos *opos;
183
184 static const char xdigs_lower[16] = "0123456789abcdef";
185 static const char xdigs_upper[16] = "0123456789ABCDEF";
186
187 /* BEWARE, these `goto error' on error. */
188 #define PRINT(ptr, len) { \
189 if (io_print(&io, (ptr), (len))) \
190 goto error; \
191 }
192 #define PAD(howmany, with) { \
193 if (io_pad(&io, (howmany), (with))) \
194 goto error; \
195 }
196 #define PRINTANDPAD(p, ep, len, with) { \
197 if (io_printandpad(&io, (p), (ep), (len), (with))) \
198 goto error; \
199 }
200 #define FLUSH() do { } while (0)
201
202 /*
203 * Get the argument indexed by nextarg. If the argument table is
204 * built, use it to get the argument. If its not, get the next
205 * argument (and arguments must be gotten sequentially).
206 */
207 #define GETARG(type) \
208 ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \
209 (nextarg++, va_arg(ap, type)))
210
211 /*
212 * To extend shorts properly, we need both signed and unsigned
213 * argument extraction methods.
214 */
215 #define SARG() \
216 (flags&LONGINT ? GETARG(long) : \
217 flags&SHORTINT ? (long)(short)GETARG(int) : \
218 flags&CHARINT ? (long)(signed char)GETARG(int) : \
219 (long)GETARG(int))
220 #define UARG() \
221 (flags&LONGINT ? GETARG(u_long) : \
222 flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
223 flags&CHARINT ? (u_long)(u_char)GETARG(int) : \
224 (u_long)GETARG(u_int))
225 #define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT|LONGDBL)
226 #define SJARG() \
227 (flags&LONGDBL ? GETARG(int64_t) : \
228 flags&INTMAXT ? GETARG(intmax_t) : \
229 flags&SIZET ? (intmax_t)GETARG(ssize_t) : \
230 flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \
231 (intmax_t)GETARG(long long))
232 #define UJARG() \
233 (flags&LONGDBL ? GETARG(uint64_t) : \
234 flags&INTMAXT ? GETARG(uintmax_t) : \
235 flags&SIZET ? (uintmax_t)GETARG(size_t) : \
236 flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \
237 (uintmax_t)GETARG(unsigned long long))
238
239 /*
240 * Get * arguments, including the form *nn$. Preserve the nextarg
241 * that the argument can be gotten once the type is determined.
242 */
243 #define GETASTER(val) \
244 n2 = 0; \
245 cp = fmt; \
246 while (is_digit(*cp)) { \
247 n2 = 10 * n2 + to_digit(*cp); \
248 cp++; \
249 } \
250 if (*cp == '$') { \
251 int hold = nextarg; \
252 if (argtable == NULL) { \
253 argtable = statargtable; \
254 if (_frr_find_arguments (fmt0, orgap, &argtable)) { \
255 ret = EOF; \
256 goto error; \
257 } \
258 } \
259 nextarg = n2; \
260 val = GETARG (int); \
261 nextarg = hold; \
262 fmt = ++cp; \
263 } else { \
264 val = GETARG (int); \
265 }
266
267 xdigs = xdigs_lower;
268 saved_errno = errno;
269 convbuf = NULL;
270 fmt = (char *)fmt0;
271 argtable = NULL;
272 nextarg = 1;
273 va_copy(orgap, ap);
274
275 if (cb_in) {
276 /* prevent printfrr exts from polluting cb->outpos */
277 cb_copy = *cb_in;
278 cb_copy.outpos = NULL;
279 cb_copy.outpos_n = cb_copy.outpos_i = 0;
280 cb = &cb_copy;
281 } else
282 cb = NULL;
283
284 io_init(&io, cb);
285 ret = 0;
286
287 /*
288 * Scan the format for conversions (`%' character).
289 */
290 for (;;) {
291 for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
292 /* void */;
293 if ((n = fmt - cp) != 0) {
294 if ((unsigned)ret + n > INT_MAX) {
295 ret = EOF;
296 errno = EOVERFLOW;
297 goto error;
298 }
299 PRINT(cp, n);
300 ret += n;
301 }
302 if (ch == '\0')
303 goto done;
304 fmt++; /* skip over '%' */
305
306 flags = 0;
307 dprec = 0;
308 width = -1;
309 prec = -1;
310 sign = '\0';
311 ox[1] = '\0';
312
313 if (cb_in && cb_in->outpos_i < cb_in->outpos_n)
314 opos = &cb_in->outpos[cb_in->outpos_i];
315 else
316 opos = NULL;
317
318 rflag: ch = *fmt++;
319 reswitch: switch (ch) {
320 case ' ':
321 /*-
322 * ``If the space and + flags both appear, the space
323 * flag will be ignored.''
324 * -- ANSI X3J11
325 */
326 if (!sign)
327 sign = ' ';
328 goto rflag;
329 case '#':
330 flags |= ALT;
331 goto rflag;
332 case '*':
333 /*-
334 * ``A negative field width argument is taken as a
335 * - flag followed by a positive field width.''
336 * -- ANSI X3J11
337 * They don't exclude field widths read from args.
338 */
339 GETASTER (width);
340 if (width >= 0)
341 goto rflag;
342 width = -width;
343 /* FALLTHROUGH */
344 case '-':
345 flags |= LADJUST;
346 goto rflag;
347 case '+':
348 sign = '+';
349 goto rflag;
350 case '\'':
351 flags |= GROUPING;
352 goto rflag;
353 case '.':
354 if ((ch = *fmt++) == '*') {
355 GETASTER (prec);
356 goto rflag;
357 }
358 prec = 0;
359 while (is_digit(ch)) {
360 prec = 10 * prec + to_digit(ch);
361 ch = *fmt++;
362 }
363 goto reswitch;
364 case '0':
365 /*-
366 * ``Note that 0 is taken as a flag, not as the
367 * beginning of a field width.''
368 * -- ANSI X3J11
369 */
370 flags |= ZEROPAD;
371 goto rflag;
372 case '1': case '2': case '3': case '4':
373 case '5': case '6': case '7': case '8': case '9':
374 n = 0;
375 do {
376 n = 10 * n + to_digit(ch);
377 ch = *fmt++;
378 } while (is_digit(ch));
379 if (ch == '$') {
380 nextarg = n;
381 if (argtable == NULL) {
382 argtable = statargtable;
383 if (_frr_find_arguments (fmt0, orgap,
384 &argtable)) {
385 ret = EOF;
386 goto error;
387 }
388 }
389 goto rflag;
390 }
391 width = n;
392 goto reswitch;
393 case 'L':
394 flags |= LONGDBL;
395 goto rflag;
396 case 'h':
397 if (flags & SHORTINT) {
398 flags &= ~SHORTINT;
399 flags |= CHARINT;
400 } else
401 flags |= SHORTINT;
402 goto rflag;
403 case 'j':
404 flags |= INTMAXT;
405 goto rflag;
406 case 'l':
407 if (flags & LONGINT) {
408 flags &= ~LONGINT;
409 flags |= LLONGINT;
410 } else
411 flags |= LONGINT;
412 goto rflag;
413 case 'q':
414 flags |= LLONGINT; /* not necessarily */
415 goto rflag;
416 case 't':
417 flags |= PTRDIFFT;
418 goto rflag;
419 case 'z':
420 flags |= SIZET;
421 goto rflag;
422 case 'C':
423 flags |= LONGINT;
424 /*FALLTHROUGH*/
425 case 'c':
426 #ifdef WCHAR_SUPPORT
427 if (flags & LONGINT) {
428 static const mbstate_t initial;
429 mbstate_t mbs;
430 size_t mbseqlen;
431
432 mbs = initial;
433 mbseqlen = wcrtomb(cp = buf,
434 (wchar_t)GETARG(wint_t), &mbs);
435 if (mbseqlen == (size_t)-1) {
436 goto error;
437 }
438 size = (int)mbseqlen;
439 } else
440 #endif /* WCHAR_SUPPORT */
441 {
442 buf[0] = GETARG(int);
443 cp = buf;
444 size = 1;
445 }
446 sign = '\0';
447 break;
448 case 'D':
449 flags |= LONGINT;
450 /*FALLTHROUGH*/
451 case 'd':
452 case 'i':
453 if (flags & INTMAX_SIZE)
454 ujval = SJARG();
455 else
456 ulval = SARG();
457
458 if (printfrr_ext_char(fmt[0])) {
459 struct printfrr_eargs ea = {
460 .fmt = fmt,
461 .precision = prec,
462 .width = width,
463 .alt_repr = !!(flags & ALT),
464 .leftadj = !!(flags & LADJUST),
465 };
466
467 if (cb)
468 extstart = cb->pos;
469
470 size = printfrr_exti(cb, &ea,
471 (flags & INTMAX_SIZE) ? ujval
472 : (uintmax_t)ulval);
473 if (size >= 0) {
474 fmt = ea.fmt;
475 width = ea.width;
476 goto ext_printed;
477 }
478 }
479 if (flags & INTMAX_SIZE) {
480 if ((intmax_t)ujval < 0) {
481 ujval = -ujval;
482 sign = '-';
483 }
484 } else {
485 if ((long)ulval < 0) {
486 ulval = -ulval;
487 sign = '-';
488 }
489 }
490 base = 10;
491 goto number;
492 #ifndef NO_FLOATING_POINT
493 case 'a':
494 case 'A':
495 case 'e':
496 case 'E':
497 case 'f':
498 case 'F':
499 case 'g':
500 case 'G':
501 if (flags & LONGDBL) {
502 long double arg = GETARG(long double);
503 char fmt[6] = "%.*L";
504 fmt[4] = ch;
505 fmt[5] = '\0';
506
507 snprintf(buf, sizeof(buf), fmt, prec, arg);
508 } else {
509 double arg = GETARG(double);
510 char fmt[5] = "%.*";
511 fmt[3] = ch;
512 fmt[4] = '\0';
513
514 snprintf(buf, sizeof(buf), fmt, prec, arg);
515 }
516 cp = buf;
517 /* for proper padding */
518 if (*cp == '-') {
519 cp++;
520 sign = '-';
521 }
522 /* "inf" */
523 if (!is_digit(*cp) && *cp != '.')
524 flags &= ~ZEROPAD;
525 size = strlen(buf);
526 break;
527 #endif
528 case 'm':
529 cp = strerror(saved_errno);
530 size = (prec >= 0) ? strnlen(cp, prec) : strlen(cp);
531 sign = '\0';
532 break;
533 case 'O':
534 flags |= LONGINT;
535 /*FALLTHROUGH*/
536 case 'o':
537 if (flags & INTMAX_SIZE)
538 ujval = UJARG();
539 else
540 ulval = UARG();
541 base = 8;
542 goto nosign;
543 case 'p':
544 /*-
545 * ``The argument shall be a pointer to void. The
546 * value of the pointer is converted to a sequence
547 * of printable characters, in an implementation-
548 * defined manner.''
549 * -- ANSI X3J11
550 */
551 ptrval = GETARG(void *);
552 if (printfrr_ext_char(fmt[0])) {
553 struct printfrr_eargs ea = {
554 .fmt = fmt,
555 .precision = prec,
556 .width = width,
557 .alt_repr = !!(flags & ALT),
558 .leftadj = !!(flags & LADJUST),
559 };
560
561 if (cb)
562 extstart = cb->pos;
563
564 size = printfrr_extp(cb, &ea, ptrval);
565 if (size >= 0) {
566 fmt = ea.fmt;
567 width = ea.width;
568 goto ext_printed;
569 }
570 }
571 ujval = (uintmax_t)(uintptr_t)ptrval;
572 base = 16;
573 xdigs = xdigs_lower;
574 flags = flags | INTMAXT;
575 ox[1] = 'x';
576 goto nosign;
577 case 'S':
578 flags |= LONGINT;
579 /*FALLTHROUGH*/
580 case 's':
581 #ifdef WCHAR_SUPPORT
582 if (flags & LONGINT) {
583 wchar_t *wcp;
584
585 if (convbuf != NULL)
586 free(convbuf);
587 if ((wcp = GETARG(wchar_t *)) == NULL)
588 cp = "(null)";
589 else {
590 convbuf = __wcsconv(wcp, prec);
591 if (convbuf == NULL) {
592 goto error;
593 }
594 cp = convbuf;
595 }
596 } else
597 #endif
598 if ((cp = GETARG(char *)) == NULL)
599 cp = "(null)";
600 size = (prec >= 0) ? strnlen(cp, prec) : strlen(cp);
601 sign = '\0';
602 break;
603 case 'U':
604 flags |= LONGINT;
605 /*FALLTHROUGH*/
606 case 'u':
607 if (flags & INTMAX_SIZE)
608 ujval = UJARG();
609 else
610 ulval = UARG();
611 base = 10;
612 goto nosign;
613 case 'X':
614 xdigs = xdigs_upper;
615 goto hex;
616 case 'x':
617 xdigs = xdigs_lower;
618 hex:
619 if (flags & INTMAX_SIZE)
620 ujval = UJARG();
621 else
622 ulval = UARG();
623 base = 16;
624 /* leading 0x/X only if non-zero */
625 if (flags & ALT &&
626 (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0))
627 ox[1] = ch;
628
629 flags &= ~GROUPING;
630 /* unsigned conversions */
631 nosign: sign = '\0';
632 /*-
633 * ``... diouXx conversions ... if a precision is
634 * specified, the 0 flag will be ignored.''
635 * -- ANSI X3J11
636 */
637 number: if ((dprec = prec) >= 0)
638 flags &= ~ZEROPAD;
639
640 /*-
641 * ``The result of converting a zero value with an
642 * explicit precision of zero is no characters.''
643 * -- ANSI X3J11
644 *
645 * ``The C Standard is clear enough as is. The call
646 * printf("%#.0o", 0) should print 0.''
647 * -- Defect Report #151
648 */
649 cp = buf + BUF;
650 if (flags & INTMAX_SIZE) {
651 if (ujval != 0 || prec != 0 ||
652 (flags & ALT && base == 8))
653 cp = __ujtoa(ujval, buf + BUF, base,
654 flags & ALT, xdigs);
655 } else {
656 if (ulval != 0 || prec != 0 ||
657 (flags & ALT && base == 8))
658 cp = __ultoa(ulval, buf + BUF, base,
659 flags & ALT, xdigs);
660 }
661 size = buf + BUF - cp;
662 if (size > BUF) /* should never happen */
663 abort();
664 break;
665 default: /* "%?" prints ?, unless ? is NUL */
666 if (ch == '\0')
667 goto done;
668 /* pretend it was %c with argument ch */
669 buf[0] = ch;
670 cp = buf;
671 size = 1;
672 sign = '\0';
673 opos = NULL;
674 break;
675 }
676
677 /*
678 * All reasonable formats wind up here. At this point, `cp'
679 * points to a string which (if not flags&LADJUST) should be
680 * padded out to `width' places. If flags&ZEROPAD, it should
681 * first be prefixed by any sign or other prefix; otherwise,
682 * it should be blank padded before the prefix is emitted.
683 * After any left-hand padding and prefixing, emit zeroes
684 * required by a decimal [diouxX] precision, then print the
685 * string proper, then emit zeroes required by any leftover
686 * floating precision; finally, if LADJUST, pad with blanks.
687 *
688 * Compute actual size, so we know how much to pad.
689 * size excludes decimal prec; realsz includes it.
690 */
691 if (width < 0)
692 width = 0;
693
694 realsz = dprec > size ? dprec : size;
695 if (sign)
696 realsz++;
697 if (ox[1])
698 realsz += 2;
699
700 prsize = width > realsz ? width : realsz;
701 if ((unsigned int)ret + prsize > INT_MAX) {
702 ret = EOF;
703 errno = EOVERFLOW;
704 goto error;
705 }
706
707 /* right-adjusting blank padding */
708 if ((flags & (LADJUST|ZEROPAD)) == 0)
709 PAD(width - realsz, blanks);
710
711 if (opos)
712 opos->off_start = cb->pos - cb->buf;
713
714 /* prefix */
715 if (sign)
716 PRINT(&sign, 1);
717
718 if (ox[1]) { /* ox[1] is either x, X, or \0 */
719 ox[0] = '0';
720 PRINT(ox, 2);
721 }
722
723 /* right-adjusting zero padding */
724 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
725 PAD(width - realsz, zeroes);
726
727 /* the string or number proper */
728 /* leading zeroes from decimal precision */
729 PAD(dprec - size, zeroes);
730 PRINT(cp, size);
731
732 if (opos) {
733 opos->off_end = cb->pos - cb->buf;
734 cb_in->outpos_i++;
735 }
736
737 /* left-adjusting padding (always blank) */
738 if (flags & LADJUST)
739 PAD(width - realsz, blanks);
740
741 /* finally, adjust ret */
742 ret += prsize;
743
744 FLUSH(); /* copy out the I/O vectors */
745 continue;
746
747 ext_printed:
748 /* when we arrive here, a printfrr extension has written to cb
749 * (if non-NULL), but we still need to handle padding. The
750 * original cb->pos is in extstart; the return value from the
751 * ext is in size.
752 *
753 * Keep analogous to code above please.
754 */
755
756 if (width < 0)
757 width = 0;
758
759 realsz = size;
760 prsize = width > realsz ? width : realsz;
761 if ((unsigned int)ret + prsize > INT_MAX) {
762 ret = EOF;
763 errno = EOVERFLOW;
764 goto error;
765 }
766
767 /* right-adjusting blank padding - need to move the chars
768 * that the extension has already written. Should be very
769 * rare.
770 */
771 if (cb && width > size && (flags & (LADJUST|ZEROPAD)) == 0) {
772 size_t nwritten = cb->pos - extstart;
773 size_t navail = cb->buf + cb->len - extstart;
774 size_t npad = width - realsz;
775 size_t nmove;
776
777 if (navail < npad)
778 navail = 0;
779 else
780 navail -= npad;
781 nmove = MIN(nwritten, navail);
782
783 memmove(extstart + npad, extstart, nmove);
784
785 cb->pos = extstart;
786 PAD(npad, blanks);
787 cb->pos += nmove;
788 extstart += npad;
789 }
790
791 io.avail = cb ? cb->len - (cb->pos - cb->buf) : 0;
792
793 if (opos && extstart <= cb->pos) {
794 opos->off_start = extstart - cb->buf;
795 opos->off_end = cb->pos - cb->buf;
796 cb_in->outpos_i++;
797 }
798
799 /* left-adjusting padding (always blank) */
800 if (flags & LADJUST)
801 PAD(width - realsz, blanks);
802
803 /* finally, adjust ret */
804 ret += prsize;
805
806 FLUSH(); /* copy out the I/O vectors */
807 }
808 done:
809 FLUSH();
810 error:
811 va_end(orgap);
812 if (convbuf != NULL)
813 free(convbuf);
814 if ((argtable != NULL) && (argtable != statargtable))
815 free (argtable);
816 if (cb_in)
817 cb_in->pos = cb->pos;
818 return (ret);
819 /* NOTREACHED */
820 }
821