int __printf_out(struct __printf_io *io, const struct printf_info *pi, const void *ptr, int len) { int ret = 0; if ((!pi->left) && pi->width > len) ret += __printf_pad(io, pi->width - len, pi->pad == '0'); ret += __printf_puts(io, ptr, len); if (pi->left && pi->width > len) ret += __printf_pad(io, pi->width - len, pi->pad == '0'); return (ret); }
int __printf_pad(struct __printf_io *io, int howmany, int zero) { int n; const char *with; int ret = 0; if (zero) with = zeroes; else with = blanks; if ((n = (howmany)) > 0) { while (n > PADSIZE) { ret += __printf_puts(io, with, PADSIZE); n -= PADSIZE; } ret += __printf_puts(io, with, n); } return (ret); }
__private_extern__ int __printf_render_hexdump(struct __printf_io *io, const struct printf_info *pi, const void *const *arg) { unsigned char *p; unsigned u, l, j, a; char buf[100], *q; int ret; if (pi->width > 0 && pi->width < 16) l = pi->width; else l = 16; p = *((unsigned char **)arg[0]); u = *((unsigned *)arg[1]); ret = 0; a = 0; while (u > 0) { q = buf; if (pi->showsign) q += sprintf(q, " %04x", a); for (j = 0; j < l && j < u; j++) q += sprintf(q, " %02x", p[j]); if (pi->alt) { for (; j < l; j++) q += sprintf(q, " "); q += sprintf(q, " |"); for (j = 0; j < l && j < u; j++) { if (p[j] < ' ' || p[j] > '~') *q++ = '.'; else *q++ = p[j]; } for (; j < l; j++) *q++ = ' '; *q++ = '|'; } if (l < u) j = l; else j = u; p += j; u -= j; a += j; if (u > 0) *q++ = '\n'; ret += __printf_puts(io, buf + 1, q - (buf + 1)); __printf_flush(io); } return (ret); }
int __printf_render_float(struct __printf_io* io, const struct printf_info* pi, const void* const* arg) { int prec; /* precision from format; <0 for N/A */ char* dtoaresult; /* buffer allocated by dtoa */ char expchar; /* exponent character: [eEpP\0] */ char* cp; int expt; /* integer value of exponent */ int signflag; /* true if float is negative */ char* dtoaend; /* pointer to end of converted digits */ char sign; /* sign prefix (' ', '+', '-', or \0) */ int size; /* size of converted field or string */ int ndig; /* actual number of digits returned by dtoa */ int expsize; /* character count for expstr */ char expstr[MAXEXPDIG + 2]; /* buffer for exponent string: e+ZZZ */ int nseps; /* number of group separators with ' */ int nrepeats; /* number of repeats of the last group */ const char* grouping; /* locale specific numeric grouping rules */ int lead; /* sig figs before decimal or group sep */ long double ld; double d; int realsz; /* field size expanded by dprec, sign, etc */ int dprec; /* a copy of prec if [diouxX], 0 otherwise */ char ox[2]; /* space for 0x; ox[1] is either x, X, or \0 */ int prsize; /* max size of printed field */ int ret; /* return value accumulator */ char* decimal_point; /* locale specific decimal point */ int n2; /* XXX: for PRINTANDPAD */ char thousands_sep; /* locale specific thousands separator */ char buf[BUF]; /* buffer with space for digits of uintmax_t */ const char* xdigs; int flag; prec = pi->prec; ox[1] = '\0'; sign = pi->showsign; flag = 0; ret = 0; thousands_sep = *(localeconv()->thousands_sep); grouping = NULL; if (pi->alt) { grouping = localeconv()->grouping; } decimal_point = localeconv()->decimal_point; dprec = -1; switch (pi->spec) { case 'a': case 'A': if (pi->spec == 'a') { ox[1] = 'x'; xdigs = __lowercase_hex; expchar = 'p'; } else { ox[1] = 'X'; xdigs = __uppercase_hex; expchar = 'P'; } if (prec >= 0) { prec++; } if (pi->is_long_double) { ld = *((long double*)arg[0]); dtoaresult = cp = __hldtoa(ld, xdigs, prec, &expt, &signflag, &dtoaend); } else { d = *((double*)arg[0]); dtoaresult = cp = __hdtoa(d, xdigs, prec, &expt, &signflag, &dtoaend); } if (prec < 0) { prec = dtoaend - cp; } if (expt == INT_MAX) { ox[1] = '\0'; } goto fp_common; case 'e': case 'E': expchar = pi->spec; if (prec < 0) { /* account for digit before decpt */ prec = DEFPREC + 1; } else { prec++; } break; case 'f': case 'F': expchar = '\0'; break; case 'g': case 'G': expchar = pi->spec - ('g' - 'e'); if (prec == 0) { prec = 1; } break; default: assert(pi->spec == 'f'); } if (prec < 0) { prec = DEFPREC; } if (pi->is_long_double) { ld = *((long double*)arg[0]); dtoaresult = cp = __ldtoa(&ld, expchar ? 2 : 3, prec, &expt, &signflag, &dtoaend); } else { d = *((double*)arg[0]); dtoaresult = cp = dtoa(d, expchar ? 2 : 3, prec, &expt, &signflag, &dtoaend); if (expt == 9999) { expt = INT_MAX; } } fp_common: if (signflag) { sign = '-'; } if (expt == INT_MAX) { /* inf or nan */ if (*cp == 'N') { cp = (pi->spec >= 'a') ? "nan" : "NAN"; sign = '\0'; } else { cp = (pi->spec >= 'a') ? "inf" : "INF"; } size = 3; flag = 1; goto here; } ndig = dtoaend - cp; if (pi->spec == 'g' || pi->spec == 'G') { if (expt > -4 && expt <= prec) { /* Make %[gG] smell like %[fF] */ expchar = '\0'; if (pi->alt) { prec -= expt; } else { prec = ndig - expt; } if (prec < 0) { prec = 0; } } else { /* * Make %[gG] smell like %[eE], but * trim trailing zeroes if no # flag. */ if (!pi->alt) { prec = ndig; } } } if (expchar) { expsize = exponent(expstr, expt - 1, expchar); size = expsize + prec; if (prec > 1 || pi->alt) { ++size; } } else { /* space for digits before decimal point */ if (expt > 0) { size = expt; } else { /* "0" */ size = 1; } /* space for decimal pt and following digits */ if (prec || pi->alt) { size += prec + 1; } if (grouping && expt > 0) { /* space for thousands' grouping */ nseps = nrepeats = 0; lead = expt; while (*grouping != CHAR_MAX) { if (lead <= *grouping) { break; } lead -= *grouping; if (*(grouping + 1)) { nseps++; grouping++; } else { nrepeats++; } } size += nseps + nrepeats; } else { lead = expt; } } here: /* * All reasonable formats wind up here. At this point, `cp' * points to a string which (if not flags&LADJUST) should be * padded out to `width' places. If flags&ZEROPAD, it should * first be prefixed by any sign or other prefix; otherwise, * it should be blank padded before the prefix is emitted. * After any left-hand padding and prefixing, emit zeroes * required by a decimal [diouxX] precision, then print the * string proper, then emit zeroes required by any leftover * floating precision; finally, if LADJUST, pad with blanks. * * Compute actual size, so we know how much to pad. * size excludes decimal prec; realsz includes it. */ realsz = dprec > size ? dprec : size; if (sign) { realsz++; } if (ox[1]) { realsz += 2; } prsize = pi->width > realsz ? pi->width : realsz; /* right-adjusting blank padding */ if (pi->pad != '0' && pi->left == 0) { ret += __printf_pad(io, pi->width - realsz, 0); } /* prefix */ if (sign) { ret += __printf_puts(io, &sign, 1); } if (ox[1]) { /* ox[1] is either x, X, or \0 */ ox[0] = '0'; ret += __printf_puts(io, ox, 2); } /* right-adjusting zero padding */ if (pi->pad == '0' && pi->left == 0) { ret += __printf_pad(io, pi->width - realsz, 1); } /* leading zeroes from decimal precision */ ret += __printf_pad(io, dprec - size, 1); if (flag) { ret += __printf_puts(io, cp, size); } else { /* glue together f_p fragments */ if (!expchar) { /* %[fF] or sufficiently short %[gG] */ if (expt <= 0) { ret += __printf_puts(io, "0", 1); if (prec || pi->alt) { ret += __printf_puts(io, decimal_point, 1); } ret += __printf_pad(io, -expt, 1); /* already handled initial 0's */ prec += expt; } else { PRINTANDPAD(cp, dtoaend, lead, 1); cp += lead; if (grouping) { while (nseps > 0 || nrepeats > 0) { if (nrepeats > 0) { nrepeats--; } else { grouping--; nseps--; } ret += __printf_puts(io, &thousands_sep, 1); PRINTANDPAD(cp, dtoaend, *grouping, 1); cp += *grouping; } if (cp > dtoaend) { cp = dtoaend; } } if (prec || pi->alt) { ret += __printf_puts(io, decimal_point, 1); } } PRINTANDPAD(cp, dtoaend, prec, 1); } else { /* %[eE] or sufficiently long %[gG] */ if (prec > 1 || pi->alt) { buf[0] = *cp++; buf[1] = *decimal_point; ret += __printf_puts(io, buf, 2); ret += __printf_puts(io, cp, ndig - 1); ret += __printf_pad(io, prec - ndig, 1); } else { /* XeYYY */ ret += __printf_puts(io, cp, 1); } ret += __printf_puts(io, expstr, expsize); } } /* left-adjusting padding (always blank) */ if (pi->left) { ret += __printf_pad(io, pi->width - realsz, 0); } __printf_flush(io); if (dtoaresult != NULL) { freedtoa(dtoaresult); } return (ret); }
static int __v2printf(struct __printf_io *io, const char *fmt0, unsigned pct, va_list ap) { struct printf_info *pi, *pil; const char *fmt; int ch; struct printf_info pia[pct + 10]; int argt[pct + 10]; union arg args[pct + 10]; int nextarg; int maxarg; int ret = 0; int n; fmt = fmt0; maxarg = 0; nextarg = 1; memset(argt, 0, sizeof argt); for (pi = pia; ; pi++) { memset(pi, 0, sizeof *pi); pil = pi; if (*fmt == '\0') break; pil = pi + 1; pi->prec = -1; pi->pad = ' '; pi->begin = pi->end = fmt; while (*fmt != '\0' && *fmt != '%') pi->end = ++fmt; if (*fmt == '\0') break; fmt++; for (;;) { pi->spec = *fmt; switch (pi->spec) { case ' ': /*- * ``If the space and + flags both appear, the space * flag will be ignored.'' * -- ANSI X3J11 */ if (pi->showsign == 0) pi->showsign = ' '; fmt++; continue; case '#': pi->alt = 1; fmt++; continue; case '.': pi->prec = 0; fmt++; if (*fmt == '*') { fmt++; pi->get_prec = nextarg; argt[nextarg++] = PA_INT; continue; } while (*fmt != '\0' && is_digit(*fmt)) { pi->prec *= 10; pi->prec += to_digit(*fmt); fmt++; } continue; case '-': pi->left = 1; fmt++; continue; case '+': pi->showsign = '+'; fmt++; continue; case '*': fmt++; pi->get_width = nextarg; argt[nextarg++] = PA_INT; continue; case '%': fmt++; break; case '\'': pi->group = 1; fmt++; continue; case '0': /*- * ``Note that 0 is taken as a flag, not as the * beginning of a field width.'' * -- ANSI X3J11 */ pi->pad = '0'; fmt++; continue; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': n = 0; while (*fmt != '\0' && is_digit(*fmt)) { n *= 10; n += to_digit(*fmt); fmt++; } if (*fmt == '$') { if (nextarg > maxarg) maxarg = nextarg; nextarg = n; fmt++; } else pi->width = n; continue; case 'D': case 'O': case 'U': pi->spec += ('a' - 'A'); pi->is_intmax = 0; if (pi->is_long_double || pi->is_quad) { pi->is_long = 0; pi->is_long_double = 1; } else { pi->is_long = 1; pi->is_long_double = 0; } fmt++; break; case 'j': pi->is_intmax = 1; fmt++; continue; case 'q': pi->is_long = 0; pi->is_quad = 1; fmt++; continue; case 'L': pi->is_long_double = 1; fmt++; continue; case 'h': fmt++; if (*fmt == 'h') { fmt++; pi->is_char = 1; } else { pi->is_short = 1; } continue; case 'l': fmt++; if (*fmt == 'l') { fmt++; pi->is_long_double = 1; pi->is_quad = 0; } else { pi->is_quad = 0; pi->is_long = 1; } continue; case 't': pi->is_ptrdiff = 1; fmt++; continue; case 'z': pi->is_size = 1; fmt++; continue; default: fmt++; break; } if (printf_tbl[pi->spec].arginfo == NULL) errx(1, "arginfo[%c] = NULL", pi->spec); ch = printf_tbl[pi->spec].arginfo( pi, __PRINTFMAXARG, &argt[nextarg]); if (ch > 0) pi->arg[0] = &args[nextarg]; if (ch > 1) pi->arg[1] = &args[nextarg + 1]; nextarg += ch; break; } } if (nextarg > maxarg) maxarg = nextarg; #if 0 fprintf(stderr, "fmt0 <%s>\n", fmt0); fprintf(stderr, "pil %p\n", pil); #endif for (ch = 1; ch < maxarg; ch++) { #if 0 fprintf(stderr, "arg %d %x\n", ch, argt[ch]); #endif switch(argt[ch]) { case PA_CHAR: args[ch].intarg = (char)va_arg (ap, int); break; case PA_INT: args[ch].intarg = va_arg (ap, int); break; case PA_INT | PA_FLAG_SHORT: args[ch].intarg = (short)va_arg (ap, int); break; case PA_INT | PA_FLAG_LONG: args[ch].longarg = va_arg (ap, long); break; case PA_INT | PA_FLAG_INTMAX: args[ch].intmaxarg = va_arg (ap, intmax_t); break; case PA_INT | PA_FLAG_QUAD: args[ch].intmaxarg = va_arg (ap, long long); break; case PA_INT | PA_FLAG_LONG_LONG: args[ch].intmaxarg = va_arg (ap, long long); break; case PA_INT | PA_FLAG_SIZE: args[ch].intmaxarg = va_arg (ap, size_t); break; case PA_INT | PA_FLAG_PTRDIFF: args[ch].intmaxarg = va_arg (ap, ptrdiff_t); break; case PA_WCHAR: #ifdef HAVE_WCHAR args[ch].wintarg = va_arg (ap, wint_t); #endif break; case PA_POINTER: args[ch].pvoidarg = va_arg (ap, void *); break; case PA_STRING: args[ch].pchararg = va_arg (ap, char *); break; case PA_WSTRING: #ifdef HAVE_WCHAR args[ch].pwchararg = va_arg (ap, wchar_t *); #endif break; case PA_DOUBLE: #ifndef NO_FLOATING_POINT args[ch].doublearg = va_arg (ap, double); #endif break; case PA_DOUBLE | PA_FLAG_LONG_DOUBLE: #ifndef NO_FLOATING_POINT args[ch].longdoublearg = va_arg (ap, long double); #endif break; default: errx(1, "argtype = %x (fmt = \"%s\")\n", argt[ch], fmt0); } } for (pi = pia; pi < pil; pi++) { #if 0 fprintf(stderr, "pi %p", pi); fprintf(stderr, " spec '%c'", pi->spec); fprintf(stderr, " args %d", ((uintptr_t)pi->arg[0] - (uintptr_t)args) / sizeof args[0]); if (pi->width) fprintf(stderr, " width %d", pi->width); if (pi->pad) fprintf(stderr, " pad 0x%x", pi->pad); if (pi->left) fprintf(stderr, " left"); if (pi->showsign) fprintf(stderr, " showsign"); if (pi->prec != -1) fprintf(stderr, " prec %d", pi->prec); if (pi->is_char) fprintf(stderr, " char"); if (pi->is_short) fprintf(stderr, " short"); if (pi->is_long) fprintf(stderr, " long"); if (pi->is_long_double) fprintf(stderr, " long_double"); fprintf(stderr, "\n"); fprintf(stderr, "\t\"%.*s\"\n", pi->end - pi->begin, pi->begin); #endif if (pi->get_width) { pi->width = args[pi->get_width].intarg; /*- * ``A negative field width argument is taken as a * - flag followed by a positive field width.'' * -- ANSI X3J11 * They don't exclude field widths read from args. */ if (pi->width < 0) { pi->left = 1; pi->width = -pi->width; } } if (pi->get_prec) pi->prec = args[pi->get_prec].intarg; ret += __printf_puts(io, pi->begin, pi->end - pi->begin); if (printf_tbl[pi->spec].gnurender != NULL) { __printf_flush(io); pi->sofar = ret; ret += printf_tbl[pi->spec].gnurender( io->u.fp, pi, (const void *)pi->arg); } else if (printf_tbl[pi->spec].render != NULL) { pi->sofar = ret; n = printf_tbl[pi->spec].render( io, pi, (const void *)pi->arg); if (n < 0) ; // io.fp->_flags |= __SERR; else ret += n; } else if (pi->begin == pi->end) errx(1, "render[%c] = NULL", *fmt); } __printf_flush(io); return (ret); }
static int __printf_render_pct(struct __printf_io *io, const struct printf_info *pi, const void *const *arg) { return (__printf_puts(io, "%", 1)); }