138451Smsmith/*- 238451Smsmith * Copyright (c) 1986, 1988, 1991, 1993 338451Smsmith * The Regents of the University of California. All rights reserved. 438451Smsmith * (c) UNIX System Laboratories, Inc. 538451Smsmith * All or some portions of this file are derived from material licensed 638451Smsmith * to the University of California by American Telephone and Telegraph 738451Smsmith * Co. or Unix System Laboratories, Inc. and are reproduced herein with 838451Smsmith * the permission of UNIX System Laboratories, Inc. 938451Smsmith * 1038451Smsmith * Redistribution and use in source and binary forms, with or without 1138451Smsmith * modification, are permitted provided that the following conditions 1238451Smsmith * are met: 1338451Smsmith * 1. Redistributions of source code must retain the above copyright 1438451Smsmith * notice, this list of conditions and the following disclaimer. 1538451Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1638451Smsmith * notice, this list of conditions and the following disclaimer in the 1738451Smsmith * documentation and/or other materials provided with the distribution. 1838451Smsmith * 4. Neither the name of the University nor the names of its contributors 1938451Smsmith * may be used to endorse or promote products derived from this software 2038451Smsmith * without specific prior written permission. 2138451Smsmith * 2238451Smsmith * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2338451Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2438451Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2538451Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2638451Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2738451Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2838451Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2938451Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3038451Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3138451Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3238451Smsmith * SUCH DAMAGE. 3338451Smsmith * 3438451Smsmith * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94 3538451Smsmith */ 3638451Smsmith 3784221Sdillon#include <sys/cdefs.h> 3884221Sdillon__FBSDID("$FreeBSD$"); 3984221Sdillon 4038451Smsmith/* 4138451Smsmith * Standaloneified version of the FreeBSD kernel printf family. 4238451Smsmith */ 4338451Smsmith 4438451Smsmith#include <sys/types.h> 45113159Speter#include <sys/stddef.h> 46113159Speter#include <sys/stdint.h> 47103949Smike#include <limits.h> 4855137Speter#include <string.h> 4938451Smsmith#include "stand.h" 5038451Smsmith 5138451Smsmith/* 5238451Smsmith * Note that stdarg.h and the ANSI style va_start macro is used for both 5338451Smsmith * ANSI and traditional C compilers. 5438451Smsmith */ 5538451Smsmith#include <machine/stdarg.h> 5638451Smsmith 57113159Speter#define MAXNBUF (sizeof(intmax_t) * CHAR_BIT + 1) 58113159Speter 59273664Siantypedef void (kvprintf_fn_t)(int, void *); 60273664Sian 61156518Sjkimstatic char *ksprintn (char *buf, uintmax_t num, int base, int *len, int upper); 62273664Sianstatic int kvprintf(char const *fmt, kvprintf_fn_t *func, void *arg, int radix, va_list ap); 6338451Smsmith 64273664Sianstatic void 65273664Sianputchar_wrapper(int cc, void *arg) 66273664Sian{ 67273664Sian 68273664Sian putchar(cc); 69273664Sian} 70273664Sian 7138451Smsmithint 7238451Smsmithprintf(const char *fmt, ...) 7338451Smsmith{ 7438451Smsmith va_list ap; 7538451Smsmith int retval; 7638451Smsmith 7738451Smsmith va_start(ap, fmt); 78273664Sian retval = kvprintf(fmt, putchar_wrapper, NULL, 10, ap); 7938451Smsmith va_end(ap); 8038451Smsmith return retval; 8138451Smsmith} 8238451Smsmith 8338451Smsmithvoid 8438451Smsmithvprintf(const char *fmt, va_list ap) 8538451Smsmith{ 8638451Smsmith 87273664Sian kvprintf(fmt, putchar_wrapper, NULL, 10, ap); 8838451Smsmith} 8938451Smsmith 9038451Smsmithint 9138451Smsmithsprintf(char *buf, const char *cfmt, ...) 9238451Smsmith{ 9338451Smsmith int retval; 9438451Smsmith va_list ap; 9538451Smsmith 9638451Smsmith va_start(ap, cfmt); 9738451Smsmith retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); 9838451Smsmith buf[retval] = '\0'; 9938451Smsmith va_end(ap); 10038451Smsmith return retval; 10138451Smsmith} 10238451Smsmith 103273664Sianstruct print_buf { 104273664Sian char *buf; 105273664Sian size_t size; 106273664Sian}; 107273664Sian 108273664Sianstatic void 109273664Siansnprint_func(int ch, void *arg) 110273664Sian{ 111273664Sian struct print_buf *pbuf = arg; 112273664Sian 113273664Sian if (pbuf->size < 2) { 114273664Sian /* 115273664Sian * Reserve last buffer position for the terminating 116273664Sian * character: 117273664Sian */ 118273664Sian return; 119273664Sian } 120273664Sian *(pbuf->buf)++ = ch; 121273664Sian pbuf->size--; 122273664Sian} 123273664Sian 124273664Sianint 125273664Siansnprintf(char *buf, size_t size, const char *cfmt, ...) 126273664Sian{ 127273664Sian int retval; 128273664Sian va_list ap; 129273664Sian struct print_buf arg; 130273664Sian 131273664Sian arg.buf = buf; 132273664Sian arg.size = size; 133273664Sian 134273664Sian va_start(ap, cfmt); 135273664Sian retval = kvprintf(cfmt, &snprint_func, &arg, 10, ap); 136273664Sian va_end(ap); 137273664Sian 138273664Sian if (arg.size >= 1) 139273664Sian *(arg.buf)++ = 0; 140273664Sian return retval; 141273664Sian} 142273664Sian 14340805Smsmithvoid 14440805Smsmithvsprintf(char *buf, const char *cfmt, va_list ap) 14540805Smsmith{ 14640805Smsmith int retval; 14740805Smsmith 14840805Smsmith retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); 14940805Smsmith buf[retval] = '\0'; 15040805Smsmith} 15140805Smsmith 15238451Smsmith/* 153113159Speter * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse 154113159Speter * order; return an optional length and a pointer to the last character 155113159Speter * written in the buffer (i.e., the first character of the string). 156113159Speter * The buffer pointed to by `nbuf' must have length >= MAXNBUF. 15738451Smsmith */ 15838451Smsmithstatic char * 159156518Sjkimksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper) 160113159Speter{ 161156518Sjkim char *p, c; 16238451Smsmith 163113159Speter p = nbuf; 164113159Speter *p = '\0'; 16538451Smsmith do { 166156518Sjkim c = hex2ascii(num % base); 167156518Sjkim *++p = upper ? toupper(c) : c; 168113159Speter } while (num /= base); 16938451Smsmith if (lenp) 170113159Speter *lenp = p - nbuf; 17138451Smsmith return (p); 17238451Smsmith} 17338451Smsmith 17438451Smsmith/* 17538451Smsmith * Scaled down version of printf(3). 17638451Smsmith * 17738451Smsmith * Two additional formats: 17838451Smsmith * 17938451Smsmith * The format %b is supported to decode error registers. 18038451Smsmith * Its usage is: 18138451Smsmith * 18238451Smsmith * printf("reg=%b\n", regval, "<base><arg>*"); 18338451Smsmith * 18438451Smsmith * where <base> is the output base expressed as a control character, e.g. 18538451Smsmith * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, 18638451Smsmith * the first of which gives the bit number to be inspected (origin 1), and 18738451Smsmith * the next characters (up to a control character, i.e. a character <= 32), 18838451Smsmith * give the name of the register. Thus: 18938451Smsmith * 19038451Smsmith * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 19138451Smsmith * 19238451Smsmith * would produce output: 19338451Smsmith * 19438451Smsmith * reg=3<BITTWO,BITONE> 19538451Smsmith * 19638451Smsmith * XXX: %D -- Hexdump, takes pointer and separator string: 19738451Smsmith * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX 19838451Smsmith * ("%*D", len, ptr, " " -> XX XX XX XX ... 19938451Smsmith */ 20038451Smsmithstatic int 201273664Siankvprintf(char const *fmt, kvprintf_fn_t *func, void *arg, int radix, va_list ap) 20238451Smsmith{ 203273664Sian#define PCHAR(c) {int cc=(c); if (func) (*func)(cc, arg); else *d++ = cc; retval++; } 204113159Speter char nbuf[MAXNBUF]; 205113159Speter char *d; 206113159Speter const char *p, *percent, *q; 20738451Smsmith u_char *up; 20838451Smsmith int ch, n; 209113159Speter uintmax_t num; 210113159Speter int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot; 211209837Sjkim int cflag, hflag, jflag, tflag, zflag; 212156518Sjkim int dwidth, upper; 21338451Smsmith char padc; 214209837Sjkim int stop = 0, retval = 0; 21538451Smsmith 216113159Speter num = 0; 21738451Smsmith if (!func) 21838451Smsmith d = (char *) arg; 21938451Smsmith else 22038451Smsmith d = NULL; 22138451Smsmith 22238451Smsmith if (fmt == NULL) 22338451Smsmith fmt = "(fmt null)\n"; 22438451Smsmith 22538451Smsmith if (radix < 2 || radix > 36) 22638451Smsmith radix = 10; 22738451Smsmith 22838451Smsmith for (;;) { 22938451Smsmith padc = ' '; 23038451Smsmith width = 0; 231209837Sjkim while ((ch = (u_char)*fmt++) != '%' || stop) { 232113159Speter if (ch == '\0') 233113159Speter return (retval); 23438451Smsmith PCHAR(ch); 23538451Smsmith } 236113159Speter percent = fmt - 1; 237113159Speter qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; 238156518Sjkim sign = 0; dot = 0; dwidth = 0; upper = 0; 239209837Sjkim cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0; 24038451Smsmithreswitch: switch (ch = (u_char)*fmt++) { 24138451Smsmith case '.': 24238451Smsmith dot = 1; 24338451Smsmith goto reswitch; 24438451Smsmith case '#': 24538451Smsmith sharpflag = 1; 24638451Smsmith goto reswitch; 24738451Smsmith case '+': 24838451Smsmith sign = 1; 24938451Smsmith goto reswitch; 25038451Smsmith case '-': 25138451Smsmith ladjust = 1; 25238451Smsmith goto reswitch; 25338451Smsmith case '%': 25438451Smsmith PCHAR(ch); 25538451Smsmith break; 25638451Smsmith case '*': 25738451Smsmith if (!dot) { 25838451Smsmith width = va_arg(ap, int); 25938451Smsmith if (width < 0) { 26038451Smsmith ladjust = !ladjust; 26138451Smsmith width = -width; 26238451Smsmith } 26338451Smsmith } else { 26438451Smsmith dwidth = va_arg(ap, int); 26538451Smsmith } 26638451Smsmith goto reswitch; 26738451Smsmith case '0': 26838451Smsmith if (!dot) { 26938451Smsmith padc = '0'; 27038451Smsmith goto reswitch; 27138451Smsmith } 27238451Smsmith case '1': case '2': case '3': case '4': 27338451Smsmith case '5': case '6': case '7': case '8': case '9': 27438451Smsmith for (n = 0;; ++fmt) { 27538451Smsmith n = n * 10 + ch - '0'; 27638451Smsmith ch = *fmt; 27738451Smsmith if (ch < '0' || ch > '9') 27838451Smsmith break; 27938451Smsmith } 28038451Smsmith if (dot) 28138451Smsmith dwidth = n; 28238451Smsmith else 28338451Smsmith width = n; 28438451Smsmith goto reswitch; 28538451Smsmith case 'b': 286209837Sjkim num = (u_int)va_arg(ap, int); 28738451Smsmith p = va_arg(ap, char *); 288156518Sjkim for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;) 28938451Smsmith PCHAR(*q--); 29038451Smsmith 291113159Speter if (num == 0) 29238451Smsmith break; 29338451Smsmith 29438451Smsmith for (tmp = 0; *p;) { 29538451Smsmith n = *p++; 296113159Speter if (num & (1 << (n - 1))) { 29738451Smsmith PCHAR(tmp ? ',' : '<'); 29838451Smsmith for (; (n = *p) > ' '; ++p) 29938451Smsmith PCHAR(n); 30038451Smsmith tmp = 1; 30138451Smsmith } else 30238451Smsmith for (; *p > ' '; ++p) 30338451Smsmith continue; 30438451Smsmith } 30538451Smsmith if (tmp) 30638451Smsmith PCHAR('>'); 30738451Smsmith break; 30838451Smsmith case 'c': 30938451Smsmith PCHAR(va_arg(ap, int)); 31038451Smsmith break; 31138451Smsmith case 'D': 31238451Smsmith up = va_arg(ap, u_char *); 31338451Smsmith p = va_arg(ap, char *); 31438451Smsmith if (!width) 31538451Smsmith width = 16; 31638451Smsmith while(width--) { 31738451Smsmith PCHAR(hex2ascii(*up >> 4)); 31838451Smsmith PCHAR(hex2ascii(*up & 0x0f)); 31938451Smsmith up++; 32038451Smsmith if (width) 32138451Smsmith for (q=p;*q;q++) 32238451Smsmith PCHAR(*q); 32338451Smsmith } 32438451Smsmith break; 32538451Smsmith case 'd': 326113159Speter case 'i': 327113159Speter base = 10; 32838451Smsmith sign = 1; 329113159Speter goto handle_sign; 330209837Sjkim case 'h': 331209837Sjkim if (hflag) { 332209837Sjkim hflag = 0; 333209837Sjkim cflag = 1; 334209837Sjkim } else 335209837Sjkim hflag = 1; 336209837Sjkim goto reswitch; 337113159Speter case 'j': 338113159Speter jflag = 1; 339113159Speter goto reswitch; 34038451Smsmith case 'l': 341113159Speter if (lflag) { 342113159Speter lflag = 0; 343113159Speter qflag = 1; 344113159Speter } else 345113159Speter lflag = 1; 34638451Smsmith goto reswitch; 34738451Smsmith case 'n': 348113159Speter if (jflag) 349113159Speter *(va_arg(ap, intmax_t *)) = retval; 350113159Speter else if (qflag) 351113159Speter *(va_arg(ap, quad_t *)) = retval; 352113159Speter else if (lflag) 353113159Speter *(va_arg(ap, long *)) = retval; 354113159Speter else if (zflag) 355113159Speter *(va_arg(ap, size_t *)) = retval; 356209837Sjkim else if (hflag) 357209837Sjkim *(va_arg(ap, short *)) = retval; 358209837Sjkim else if (cflag) 359209837Sjkim *(va_arg(ap, char *)) = retval; 360113159Speter else 361113159Speter *(va_arg(ap, int *)) = retval; 362113159Speter break; 36338451Smsmith case 'o': 36438451Smsmith base = 8; 365113159Speter goto handle_nosign; 36638451Smsmith case 'p': 36738451Smsmith base = 16; 368113159Speter sharpflag = (width == 0); 369113159Speter sign = 0; 370113159Speter num = (uintptr_t)va_arg(ap, void *); 37138451Smsmith goto number; 372113159Speter case 'q': 373113159Speter qflag = 1; 374113159Speter goto reswitch; 375113159Speter case 'r': 376113159Speter base = radix; 377113159Speter if (sign) 378113159Speter goto handle_sign; 379113159Speter goto handle_nosign; 38038451Smsmith case 's': 38138451Smsmith p = va_arg(ap, char *); 38238451Smsmith if (p == NULL) 38338451Smsmith p = "(null)"; 38438451Smsmith if (!dot) 38538451Smsmith n = strlen (p); 38638451Smsmith else 38738451Smsmith for (n = 0; n < dwidth && p[n]; n++) 38838451Smsmith continue; 38938451Smsmith 39038451Smsmith width -= n; 39138451Smsmith 39238451Smsmith if (!ladjust && width > 0) 39338451Smsmith while (width--) 39438451Smsmith PCHAR(padc); 39538451Smsmith while (n--) 39638451Smsmith PCHAR(*p++); 39738451Smsmith if (ladjust && width > 0) 39838451Smsmith while (width--) 39938451Smsmith PCHAR(padc); 40038451Smsmith break; 401113159Speter case 't': 402113159Speter tflag = 1; 403113159Speter goto reswitch; 40438451Smsmith case 'u': 40538451Smsmith base = 10; 406113159Speter goto handle_nosign; 407156518Sjkim case 'X': 408156518Sjkim upper = 1; 40938451Smsmith case 'x': 41038451Smsmith base = 16; 411113159Speter goto handle_nosign; 412113159Speter case 'y': 413113159Speter base = 16; 414113159Speter sign = 1; 415113159Speter goto handle_sign; 416113159Speter case 'z': 417113159Speter zflag = 1; 418113159Speter goto reswitch; 419113159Speterhandle_nosign: 420113159Speter sign = 0; 421113159Speter if (jflag) 422113159Speter num = va_arg(ap, uintmax_t); 423113159Speter else if (qflag) 424113159Speter num = va_arg(ap, u_quad_t); 425113159Speter else if (tflag) 426113159Speter num = va_arg(ap, ptrdiff_t); 427113159Speter else if (lflag) 428113159Speter num = va_arg(ap, u_long); 429113159Speter else if (zflag) 430113159Speter num = va_arg(ap, size_t); 431209837Sjkim else if (hflag) 432209837Sjkim num = (u_short)va_arg(ap, int); 433209837Sjkim else if (cflag) 434209837Sjkim num = (u_char)va_arg(ap, int); 435113159Speter else 436113159Speter num = va_arg(ap, u_int); 437113159Speter goto number; 438113159Speterhandle_sign: 439113159Speter if (jflag) 440113159Speter num = va_arg(ap, intmax_t); 441113159Speter else if (qflag) 442113159Speter num = va_arg(ap, quad_t); 443113159Speter else if (tflag) 444113159Speter num = va_arg(ap, ptrdiff_t); 445113159Speter else if (lflag) 446113159Speter num = va_arg(ap, long); 447113159Speter else if (zflag) 448185037Sdelphij num = va_arg(ap, ssize_t); 449209837Sjkim else if (hflag) 450209837Sjkim num = (short)va_arg(ap, int); 451209837Sjkim else if (cflag) 452209837Sjkim num = (char)va_arg(ap, int); 453113159Speter else 454113159Speter num = va_arg(ap, int); 455113159Speternumber: 456113159Speter if (sign && (intmax_t)num < 0) { 45738451Smsmith neg = 1; 458113159Speter num = -(intmax_t)num; 45938451Smsmith } 460209837Sjkim p = ksprintn(nbuf, num, base, &n, upper); 461209837Sjkim tmp = 0; 462113159Speter if (sharpflag && num != 0) { 46338451Smsmith if (base == 8) 46438451Smsmith tmp++; 46538451Smsmith else if (base == 16) 46638451Smsmith tmp += 2; 46738451Smsmith } 46838451Smsmith if (neg) 46938451Smsmith tmp++; 47038451Smsmith 471209837Sjkim if (!ladjust && padc == '0') 472209837Sjkim dwidth = width - tmp; 473209949Sjkim width -= tmp + imax(dwidth, n); 474209837Sjkim dwidth -= n; 475209837Sjkim if (!ladjust) 476209837Sjkim while (width-- > 0) 477209837Sjkim PCHAR(' '); 47838451Smsmith if (neg) 47938451Smsmith PCHAR('-'); 480113159Speter if (sharpflag && num != 0) { 48138451Smsmith if (base == 8) { 48238451Smsmith PCHAR('0'); 48338451Smsmith } else if (base == 16) { 48438451Smsmith PCHAR('0'); 48538451Smsmith PCHAR('x'); 48638451Smsmith } 48738451Smsmith } 488209837Sjkim while (dwidth-- > 0) 489209837Sjkim PCHAR('0'); 49038451Smsmith 49138451Smsmith while (*p) 49238451Smsmith PCHAR(*p--); 49338451Smsmith 494209837Sjkim if (ladjust) 495209837Sjkim while (width-- > 0) 496209837Sjkim PCHAR(' '); 49738451Smsmith 49838451Smsmith break; 49938451Smsmith default: 500113159Speter while (percent < fmt) 501113159Speter PCHAR(*percent++); 502209837Sjkim /* 503209837Sjkim * Since we ignore an formatting argument it is no 504209837Sjkim * longer safe to obey the remaining formatting 505209837Sjkim * arguments as the arguments will no longer match 506209837Sjkim * the format specs. 507209837Sjkim */ 508209837Sjkim stop = 1; 50938451Smsmith break; 51038451Smsmith } 51138451Smsmith } 51238451Smsmith#undef PCHAR 51338451Smsmith} 514