Line data Source code
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 426 : vbprintfrr(struct fbuf *cb_in, const char *fmt0, va_list ap)
151 752 : {
152 426 : const char *fmt; /* format string */
153 426 : int ch; /* character from fmt */
154 426 : int n, n2; /* handy integer (short term usage) */
155 426 : const char *cp; /* handy char pointer (short term usage) */
156 426 : int flags; /* flags as above */
157 426 : int ret; /* return value accumulator */
158 426 : int width; /* width from format (%8d), or 0 */
159 426 : int prec; /* precision from format; <0 for N/A */
160 426 : int saved_errno;
161 426 : char sign; /* sign prefix (' ', '+', '-', or \0) */
162 :
163 426 : u_long ulval = 0; /* integer arguments %[diouxX] */
164 426 : uintmax_t ujval = 0; /* %j, %ll, %q, %t, %z integers */
165 426 : void *ptrval; /* %p */
166 426 : int base; /* base for [diouxX] conversion */
167 426 : int dprec; /* a copy of prec if [diouxX], 0 otherwise */
168 426 : int realsz; /* field size expanded by dprec, sign, etc */
169 426 : int size; /* size of converted field or string */
170 426 : int prsize; /* max size of printed field */
171 426 : const char *xdigs; /* digits for %[xX] conversion */
172 426 : struct io_state io; /* I/O buffering state */
173 426 : char buf[BUF]; /* buffer with space for digits of uintmax_t */
174 426 : char ox[2]; /* space for 0x; ox[1] is either x, X, or \0 */
175 426 : union arg *argtable; /* args, built due to positional arg */
176 426 : union arg statargtable [STATIC_ARG_TBL_SIZE];
177 426 : int nextarg; /* 1-based argument index */
178 426 : va_list orgap; /* original argument pointer */
179 426 : char *convbuf; /* wide to multibyte conversion result */
180 426 : char *extstart = NULL; /* where printfrr_ext* started printing */
181 426 : struct fbuf cb_copy, *cb;
182 426 : struct fmt_outpos *opos;
183 :
184 426 : static const char xdigs_lower[16] = "0123456789abcdef";
185 426 : 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 426 : xdigs = xdigs_lower;
268 426 : saved_errno = errno;
269 426 : convbuf = NULL;
270 426 : fmt = (char *)fmt0;
271 426 : argtable = NULL;
272 426 : nextarg = 1;
273 426 : va_copy(orgap, ap);
274 :
275 426 : if (cb_in) {
276 : /* prevent printfrr exts from polluting cb->outpos */
277 426 : cb_copy = *cb_in;
278 426 : cb_copy.outpos = NULL;
279 426 : cb_copy.outpos_n = cb_copy.outpos_i = 0;
280 426 : cb = &cb_copy;
281 : } else
282 : cb = NULL;
283 :
284 426 : io_init(&io, cb);
285 426 : ret = 0;
286 :
287 : /*
288 : * Scan the format for conversions (`%' character).
289 : */
290 1200 : for (;;) {
291 4804 : for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
292 : /* void */;
293 1200 : if ((n = fmt - cp) != 0) {
294 606 : if ((unsigned)ret + n > INT_MAX) {
295 0 : ret = EOF;
296 0 : errno = EOVERFLOW;
297 0 : goto error;
298 : }
299 606 : PRINT(cp, n);
300 606 : ret += n;
301 : }
302 1200 : if (ch == '\0')
303 426 : goto done;
304 774 : fmt++; /* skip over '%' */
305 :
306 774 : flags = 0;
307 774 : dprec = 0;
308 774 : width = -1;
309 774 : prec = -1;
310 774 : sign = '\0';
311 774 : ox[1] = '\0';
312 :
313 774 : if (cb_in && cb_in->outpos_i < cb_in->outpos_n)
314 320 : opos = &cb_in->outpos[cb_in->outpos_i];
315 : else
316 774 : opos = NULL;
317 :
318 1440 : rflag: ch = *fmt++;
319 1850 : reswitch: switch (ch) {
320 0 : case ' ':
321 : /*-
322 : * ``If the space and + flags both appear, the space
323 : * flag will be ignored.''
324 : * -- ANSI X3J11
325 : */
326 0 : if (!sign)
327 0 : sign = ' ';
328 0 : goto rflag;
329 0 : case '#':
330 0 : flags |= ALT;
331 0 : 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 0 : GETASTER (width);
340 0 : if (width >= 0)
341 0 : goto rflag;
342 0 : width = -width;
343 : /* FALLTHROUGH */
344 49 : case '-':
345 49 : flags |= LADJUST;
346 49 : goto rflag;
347 104 : case '+':
348 104 : sign = '+';
349 104 : goto rflag;
350 0 : case '\'':
351 0 : flags |= GROUPING;
352 0 : goto rflag;
353 8 : case '.':
354 8 : if ((ch = *fmt++) == '*') {
355 8 : GETASTER (prec);
356 8 : goto rflag;
357 : }
358 : prec = 0;
359 0 : while (is_digit(ch)) {
360 0 : prec = 10 * prec + to_digit(ch);
361 0 : ch = *fmt++;
362 : }
363 0 : goto reswitch;
364 312 : 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 312 : flags |= ZEROPAD;
371 312 : 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 459 : do {
376 459 : n = 10 * n + to_digit(ch);
377 459 : ch = *fmt++;
378 459 : } while (is_digit(ch));
379 410 : if (ch == '$') {
380 0 : nextarg = n;
381 0 : if (argtable == NULL) {
382 0 : argtable = statargtable;
383 0 : if (_frr_find_arguments (fmt0, orgap,
384 : &argtable)) {
385 0 : ret = EOF;
386 0 : goto error;
387 : }
388 : }
389 0 : goto rflag;
390 : }
391 410 : width = n;
392 410 : goto reswitch;
393 0 : case 'L':
394 0 : flags |= LONGDBL;
395 0 : goto rflag;
396 0 : case 'h':
397 0 : if (flags & SHORTINT) {
398 0 : flags &= ~SHORTINT;
399 0 : flags |= CHARINT;
400 : } else
401 0 : flags |= SHORTINT;
402 0 : goto rflag;
403 28 : case 'j':
404 28 : flags |= INTMAXT;
405 28 : goto rflag;
406 116 : case 'l':
407 116 : if (flags & LONGINT) {
408 0 : flags &= ~LONGINT;
409 0 : flags |= LLONGINT;
410 : } else
411 116 : flags |= LONGINT;
412 116 : goto rflag;
413 0 : case 'q':
414 0 : flags |= LLONGINT; /* not necessarily */
415 0 : goto rflag;
416 0 : case 't':
417 0 : flags |= PTRDIFFT;
418 0 : goto rflag;
419 49 : case 'z':
420 49 : flags |= SIZET;
421 49 : goto rflag;
422 0 : case 'C':
423 0 : flags |= LONGINT;
424 : /*FALLTHROUGH*/
425 0 : 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 0 : buf[0] = GETARG(int);
443 0 : cp = buf;
444 0 : size = 1;
445 : }
446 0 : sign = '\0';
447 0 : break;
448 0 : case 'D':
449 0 : flags |= LONGINT;
450 : /*FALLTHROUGH*/
451 260 : case 'd':
452 : case 'i':
453 260 : if (flags & INTMAX_SIZE)
454 28 : ujval = SJARG();
455 : else
456 232 : ulval = SARG();
457 :
458 260 : if (printfrr_ext_char(fmt[0])) {
459 0 : struct printfrr_eargs ea = {
460 : .fmt = fmt,
461 : .precision = prec,
462 : .width = width,
463 0 : .alt_repr = !!(flags & ALT),
464 0 : .leftadj = !!(flags & LADJUST),
465 : };
466 :
467 0 : if (cb)
468 0 : extstart = cb->pos;
469 :
470 0 : size = printfrr_exti(cb, &ea,
471 : (flags & INTMAX_SIZE) ? ujval
472 : : (uintmax_t)ulval);
473 0 : if (size >= 0) {
474 0 : fmt = ea.fmt;
475 0 : width = ea.width;
476 0 : goto ext_printed;
477 : }
478 : }
479 260 : if (flags & INTMAX_SIZE) {
480 28 : if ((intmax_t)ujval < 0) {
481 0 : ujval = -ujval;
482 0 : sign = '-';
483 : }
484 : } else {
485 232 : if ((long)ulval < 0) {
486 0 : ulval = -ulval;
487 0 : sign = '-';
488 : }
489 : }
490 260 : base = 10;
491 260 : goto number;
492 : #ifndef NO_FLOATING_POINT
493 0 : case 'a':
494 : case 'A':
495 : case 'e':
496 : case 'E':
497 : case 'f':
498 : case 'F':
499 : case 'g':
500 : case 'G':
501 0 : if (flags & LONGDBL) {
502 0 : long double arg = GETARG(long double);
503 0 : char fmt[6] = "%.*L";
504 0 : fmt[4] = ch;
505 0 : fmt[5] = '\0';
506 :
507 : #pragma GCC diagnostic push
508 : #pragma GCC diagnostic ignored "-Wformat-nonliteral"
509 0 : snprintf(buf, sizeof(buf), fmt, prec, arg);
510 : #pragma GCC diagnostic pop
511 : } else {
512 0 : double arg = GETARG(double);
513 0 : char fmt[5] = "%.*";
514 0 : fmt[3] = ch;
515 0 : fmt[4] = '\0';
516 :
517 : #pragma GCC diagnostic push
518 : #pragma GCC diagnostic ignored "-Wformat-nonliteral"
519 0 : snprintf(buf, sizeof(buf), fmt, prec, arg);
520 : #pragma GCC diagnostic pop
521 : }
522 0 : cp = buf;
523 : /* for proper padding */
524 0 : if (*cp == '-') {
525 0 : cp++;
526 0 : sign = '-';
527 : }
528 : /* "inf" */
529 0 : if (!is_digit(*cp) && *cp != '.')
530 0 : flags &= ~ZEROPAD;
531 0 : size = strlen(buf);
532 0 : break;
533 : #endif
534 0 : case 'm':
535 0 : cp = strerror(saved_errno);
536 0 : size = (prec >= 0) ? strnlen(cp, prec) : strlen(cp);
537 0 : sign = '\0';
538 0 : break;
539 0 : case 'O':
540 0 : flags |= LONGINT;
541 : /*FALLTHROUGH*/
542 0 : case 'o':
543 0 : if (flags & INTMAX_SIZE)
544 0 : ujval = UJARG();
545 : else
546 0 : ulval = UARG();
547 0 : base = 8;
548 0 : goto nosign;
549 22 : case 'p':
550 : /*-
551 : * ``The argument shall be a pointer to void. The
552 : * value of the pointer is converted to a sequence
553 : * of printable characters, in an implementation-
554 : * defined manner.''
555 : * -- ANSI X3J11
556 : */
557 22 : ptrval = GETARG(void *);
558 22 : if (printfrr_ext_char(fmt[0])) {
559 22 : struct printfrr_eargs ea = {
560 : .fmt = fmt,
561 : .precision = prec,
562 : .width = width,
563 22 : .alt_repr = !!(flags & ALT),
564 22 : .leftadj = !!(flags & LADJUST),
565 : };
566 :
567 22 : if (cb)
568 22 : extstart = cb->pos;
569 :
570 22 : size = printfrr_extp(cb, &ea, ptrval);
571 22 : if (size >= 0) {
572 22 : fmt = ea.fmt;
573 22 : width = ea.width;
574 22 : goto ext_printed;
575 : }
576 : }
577 0 : ujval = (uintmax_t)(uintptr_t)ptrval;
578 0 : base = 16;
579 0 : xdigs = xdigs_lower;
580 0 : flags = flags | INTMAXT;
581 0 : ox[1] = 'x';
582 0 : goto nosign;
583 0 : case 'S':
584 0 : flags |= LONGINT;
585 : /*FALLTHROUGH*/
586 293 : case 's':
587 : #ifdef WCHAR_SUPPORT
588 : if (flags & LONGINT) {
589 : wchar_t *wcp;
590 :
591 : if (convbuf != NULL)
592 : free(convbuf);
593 : if ((wcp = GETARG(wchar_t *)) == NULL)
594 : cp = "(null)";
595 : else {
596 : convbuf = __wcsconv(wcp, prec);
597 : if (convbuf == NULL) {
598 : goto error;
599 : }
600 : cp = convbuf;
601 : }
602 : } else
603 : #endif
604 293 : if ((cp = GETARG(char *)) == NULL)
605 0 : cp = "(null)";
606 293 : size = (prec >= 0) ? strnlen(cp, prec) : strlen(cp);
607 293 : sign = '\0';
608 293 : break;
609 0 : case 'U':
610 0 : flags |= LONGINT;
611 : /*FALLTHROUGH*/
612 199 : case 'u':
613 199 : if (flags & INTMAX_SIZE)
614 49 : ujval = UJARG();
615 : else
616 150 : ulval = UARG();
617 199 : base = 10;
618 199 : goto nosign;
619 0 : case 'X':
620 0 : xdigs = xdigs_upper;
621 0 : goto hex;
622 : case 'x':
623 : xdigs = xdigs_lower;
624 0 : hex:
625 0 : if (flags & INTMAX_SIZE)
626 0 : ujval = UJARG();
627 : else
628 0 : ulval = UARG();
629 0 : base = 16;
630 : /* leading 0x/X only if non-zero */
631 0 : if (flags & ALT &&
632 : (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0))
633 0 : ox[1] = ch;
634 :
635 0 : flags &= ~GROUPING;
636 : /* unsigned conversions */
637 199 : nosign: sign = '\0';
638 : /*-
639 : * ``... diouXx conversions ... if a precision is
640 : * specified, the 0 flag will be ignored.''
641 : * -- ANSI X3J11
642 : */
643 459 : number: if ((dprec = prec) >= 0)
644 0 : flags &= ~ZEROPAD;
645 :
646 : /*-
647 : * ``The result of converting a zero value with an
648 : * explicit precision of zero is no characters.''
649 : * -- ANSI X3J11
650 : *
651 : * ``The C Standard is clear enough as is. The call
652 : * printf("%#.0o", 0) should print 0.''
653 : * -- Defect Report #151
654 : */
655 459 : cp = buf + BUF;
656 459 : if (flags & INTMAX_SIZE) {
657 77 : if (ujval != 0 || prec != 0 ||
658 0 : (flags & ALT && base == 8))
659 77 : cp = __ujtoa(ujval, buf + BUF, base,
660 : flags & ALT, xdigs);
661 : } else {
662 382 : if (ulval != 0 || prec != 0 ||
663 0 : (flags & ALT && base == 8))
664 382 : cp = __ultoa(ulval, buf + BUF, base,
665 : flags & ALT, xdigs);
666 : }
667 459 : size = buf + BUF - cp;
668 459 : if (size > BUF) /* should never happen */
669 0 : abort();
670 : break;
671 0 : default: /* "%?" prints ?, unless ? is NUL */
672 0 : if (ch == '\0')
673 0 : goto done;
674 : /* pretend it was %c with argument ch */
675 0 : buf[0] = ch;
676 0 : cp = buf;
677 0 : size = 1;
678 0 : sign = '\0';
679 0 : opos = NULL;
680 0 : break;
681 : }
682 :
683 : /*
684 : * All reasonable formats wind up here. At this point, `cp'
685 : * points to a string which (if not flags&LADJUST) should be
686 : * padded out to `width' places. If flags&ZEROPAD, it should
687 : * first be prefixed by any sign or other prefix; otherwise,
688 : * it should be blank padded before the prefix is emitted.
689 : * After any left-hand padding and prefixing, emit zeroes
690 : * required by a decimal [diouxX] precision, then print the
691 : * string proper, then emit zeroes required by any leftover
692 : * floating precision; finally, if LADJUST, pad with blanks.
693 : *
694 : * Compute actual size, so we know how much to pad.
695 : * size excludes decimal prec; realsz includes it.
696 : */
697 752 : if (width < 0)
698 : width = 0;
699 :
700 752 : realsz = dprec > size ? dprec : size;
701 752 : if (sign)
702 104 : realsz++;
703 752 : if (ox[1])
704 0 : realsz += 2;
705 :
706 752 : prsize = width > realsz ? width : realsz;
707 752 : if ((unsigned int)ret + prsize > INT_MAX) {
708 0 : ret = EOF;
709 0 : errno = EOVERFLOW;
710 0 : goto error;
711 : }
712 :
713 : /* right-adjusting blank padding */
714 752 : if ((flags & (LADJUST|ZEROPAD)) == 0)
715 391 : PAD(width - realsz, blanks);
716 :
717 752 : if (opos)
718 316 : opos->off_start = cb->pos - cb->buf;
719 :
720 : /* prefix */
721 752 : if (sign)
722 104 : PRINT(&sign, 1);
723 :
724 752 : if (ox[1]) { /* ox[1] is either x, X, or \0 */
725 0 : ox[0] = '0';
726 0 : PRINT(ox, 2);
727 : }
728 :
729 : /* right-adjusting zero padding */
730 752 : if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
731 312 : PAD(width - realsz, zeroes);
732 :
733 : /* the string or number proper */
734 : /* leading zeroes from decimal precision */
735 752 : PAD(dprec - size, zeroes);
736 752 : PRINT(cp, size);
737 :
738 752 : if (opos) {
739 316 : opos->off_end = cb->pos - cb->buf;
740 316 : cb_in->outpos_i++;
741 : }
742 :
743 : /* left-adjusting padding (always blank) */
744 752 : if (flags & LADJUST)
745 49 : PAD(width - realsz, blanks);
746 :
747 : /* finally, adjust ret */
748 752 : ret += prsize;
749 :
750 752 : FLUSH(); /* copy out the I/O vectors */
751 752 : continue;
752 :
753 22 : ext_printed:
754 : /* when we arrive here, a printfrr extension has written to cb
755 : * (if non-NULL), but we still need to handle padding. The
756 : * original cb->pos is in extstart; the return value from the
757 : * ext is in size.
758 : *
759 : * Keep analogous to code above please.
760 : */
761 :
762 22 : if (width < 0)
763 : width = 0;
764 :
765 22 : realsz = size;
766 22 : prsize = width > realsz ? width : realsz;
767 22 : if ((unsigned int)ret + prsize > INT_MAX) {
768 0 : ret = EOF;
769 0 : errno = EOVERFLOW;
770 0 : goto error;
771 : }
772 :
773 : /* right-adjusting blank padding - need to move the chars
774 : * that the extension has already written. Should be very
775 : * rare.
776 : */
777 22 : if (cb && width > size && (flags & (LADJUST|ZEROPAD)) == 0) {
778 0 : size_t nwritten = cb->pos - extstart;
779 0 : size_t navail = cb->buf + cb->len - extstart;
780 0 : size_t npad = width - realsz;
781 0 : size_t nmove;
782 :
783 0 : if (navail < npad)
784 : navail = 0;
785 : else
786 0 : navail -= npad;
787 0 : nmove = MIN(nwritten, navail);
788 :
789 0 : memmove(extstart + npad, extstart, nmove);
790 :
791 0 : cb->pos = extstart;
792 0 : PAD(npad, blanks);
793 0 : cb->pos += nmove;
794 0 : extstart += npad;
795 : }
796 :
797 22 : io.avail = cb ? cb->len - (cb->pos - cb->buf) : 0;
798 :
799 22 : if (opos && extstart <= cb->pos) {
800 4 : opos->off_start = extstart - cb->buf;
801 4 : opos->off_end = cb->pos - cb->buf;
802 4 : cb_in->outpos_i++;
803 : }
804 :
805 : /* left-adjusting padding (always blank) */
806 22 : if (flags & LADJUST)
807 0 : PAD(width - realsz, blanks);
808 :
809 : /* finally, adjust ret */
810 22 : ret += prsize;
811 :
812 : FLUSH(); /* copy out the I/O vectors */
813 : }
814 426 : done:
815 426 : FLUSH();
816 426 : error:
817 426 : va_end(orgap);
818 426 : if (convbuf != NULL)
819 : free(convbuf);
820 426 : if ((argtable != NULL) && (argtable != statargtable))
821 0 : free (argtable);
822 426 : if (cb_in)
823 426 : cb_in->pos = cb->pos;
824 426 : return (ret);
825 : /* NOTREACHED */
826 : }
827 :
|