printf.c revision 185037
1251877Speter/*- 2251877Speter * Copyright (c) 1986, 1988, 1991, 1993 3251877Speter * The Regents of the University of California. All rights reserved. 4251877Speter * (c) UNIX System Laboratories, Inc. 5251877Speter * All or some portions of this file are derived from material licensed 6251877Speter * to the University of California by American Telephone and Telegraph 7251877Speter * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8251877Speter * the permission of UNIX System Laboratories, Inc. 9251877Speter * 10251877Speter * Redistribution and use in source and binary forms, with or without 11251877Speter * modification, are permitted provided that the following conditions 12251877Speter * are met: 13251877Speter * 1. Redistributions of source code must retain the above copyright 14251877Speter * notice, this list of conditions and the following disclaimer. 15251877Speter * 2. Redistributions in binary form must reproduce the above copyright 16251877Speter * notice, this list of conditions and the following disclaimer in the 17251877Speter * documentation and/or other materials provided with the distribution. 18251877Speter * 4. Neither the name of the University nor the names of its contributors 19251877Speter * may be used to endorse or promote products derived from this software 20251877Speter * without specific prior written permission. 21251877Speter * 22251877Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23251877Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24251877Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25251877Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26251877Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27251877Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28251877Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29251877Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30251877Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31251877Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32251877Speter * SUCH DAMAGE. 33251877Speter * 34251877Speter * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94 35251877Speter */ 36251877Speter 37251877Speter#include <sys/cdefs.h> 38251877Speter__FBSDID("$FreeBSD: head/lib/libstand/printf.c 185037 2008-11-18 00:01:16Z delphij $"); 39251877Speter 40251877Speter/* 41251877Speter * Standaloneified version of the FreeBSD kernel printf family. 42251877Speter */ 43251877Speter 44251877Speter#include <sys/types.h> 45251877Speter#include <sys/stddef.h> 46251877Speter#include <sys/stdint.h> 47251877Speter#include <limits.h> 48251877Speter#include <string.h> 49251877Speter#include "stand.h" 50251877Speter 51251877Speter/* 52251877Speter * Note that stdarg.h and the ANSI style va_start macro is used for both 53251877Speter * ANSI and traditional C compilers. 54251877Speter */ 55251877Speter#include <machine/stdarg.h> 56251877Speter 57251877Speter#define MAXNBUF (sizeof(intmax_t) * CHAR_BIT + 1) 58251877Speter 59251877Speterstatic char *ksprintn (char *buf, uintmax_t num, int base, int *len, int upper); 60251877Speterstatic int kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap); 61251877Speter 62251877Speterint 63251877Speterprintf(const char *fmt, ...) 64251877Speter{ 65251877Speter va_list ap; 66251877Speter int retval; 67251877Speter 68251877Speter va_start(ap, fmt); 69251877Speter retval = kvprintf(fmt, putchar, NULL, 10, ap); 70251877Speter va_end(ap); 71251877Speter return retval; 72251877Speter} 73251877Speter 74251877Spetervoid 75251877Spetervprintf(const char *fmt, va_list ap) 76251877Speter{ 77251877Speter 78251877Speter kvprintf(fmt, putchar, NULL, 10, ap); 79251877Speter} 80251877Speter 81251877Speterint 82251877Spetersprintf(char *buf, const char *cfmt, ...) 83251877Speter{ 84251877Speter int retval; 85251877Speter va_list ap; 86251877Speter 87251877Speter va_start(ap, cfmt); 88251877Speter retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); 89251877Speter buf[retval] = '\0'; 90251877Speter va_end(ap); 91251877Speter return retval; 92251877Speter} 93251877Speter 94251877Spetervoid 95251877Spetervsprintf(char *buf, const char *cfmt, va_list ap) 96251877Speter{ 97251877Speter int retval; 98251877Speter 99251877Speter retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); 100251877Speter buf[retval] = '\0'; 101251877Speter} 102251877Speter 103251877Speter/* 104251877Speter * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse 105251877Speter * order; return an optional length and a pointer to the last character 106251877Speter * written in the buffer (i.e., the first character of the string). 107251877Speter * The buffer pointed to by `nbuf' must have length >= MAXNBUF. 108251877Speter */ 109251877Speterstatic char * 110251877Speterksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper) 111251877Speter{ 112251877Speter char *p, c; 113251877Speter 114251877Speter p = nbuf; 115251877Speter *p = '\0'; 116251877Speter do { 117251877Speter c = hex2ascii(num % base); 118251877Speter *++p = upper ? toupper(c) : c; 119251877Speter } while (num /= base); 120251877Speter if (lenp) 121251877Speter *lenp = p - nbuf; 122251877Speter return (p); 123251877Speter} 124251877Speter 125251877Speter/* 126251877Speter * Scaled down version of printf(3). 127251877Speter * 128251877Speter * Two additional formats: 129251877Speter * 130251877Speter * The format %b is supported to decode error registers. 131251877Speter * Its usage is: 132251877Speter * 133251877Speter * printf("reg=%b\n", regval, "<base><arg>*"); 134251877Speter * 135251877Speter * where <base> is the output base expressed as a control character, e.g. 136251877Speter * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, 137251877Speter * the first of which gives the bit number to be inspected (origin 1), and 138251877Speter * the next characters (up to a control character, i.e. a character <= 32), 139251877Speter * give the name of the register. Thus: 140251877Speter * 141251877Speter * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 142251877Speter * 143251877Speter * would produce output: 144251877Speter * 145251877Speter * reg=3<BITTWO,BITONE> 146251877Speter * 147251877Speter * XXX: %D -- Hexdump, takes pointer and separator string: 148251877Speter * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX 149251877Speter * ("%*D", len, ptr, " " -> XX XX XX XX ... 150251877Speter */ 151251877Speterstatic int 152251877Speterkvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap) 153251877Speter{ 154251877Speter#define PCHAR(c) {int cc=(c); if (func) (*func)(cc); else *d++ = cc; retval++; } 155251877Speter char nbuf[MAXNBUF]; 156251877Speter char *d; 157251877Speter const char *p, *percent, *q; 158251877Speter u_char *up; 159251877Speter int ch, n; 160251877Speter uintmax_t num; 161251877Speter int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot; 162251877Speter int jflag, tflag, zflag; 163251877Speter int dwidth, upper; 164251877Speter char padc; 165251877Speter int retval = 0; 166251877Speter 167251877Speter num = 0; 168251877Speter if (!func) 169251877Speter d = (char *) arg; 170251877Speter else 171251877Speter d = NULL; 172251877Speter 173251877Speter if (fmt == NULL) 174251877Speter fmt = "(fmt null)\n"; 175251877Speter 176251877Speter if (radix < 2 || radix > 36) 177251877Speter radix = 10; 178251877Speter 179251877Speter for (;;) { 180251877Speter padc = ' '; 181251877Speter width = 0; 182251877Speter while ((ch = (u_char)*fmt++) != '%') { 183251877Speter if (ch == '\0') 184251877Speter return (retval); 185251877Speter PCHAR(ch); 186251877Speter } 187251877Speter percent = fmt - 1; 188251877Speter qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; 189251877Speter sign = 0; dot = 0; dwidth = 0; upper = 0; 190251877Speter jflag = 0; tflag = 0; zflag = 0; 191251877Speterreswitch: switch (ch = (u_char)*fmt++) { 192251877Speter case '.': 193251877Speter dot = 1; 194251877Speter goto reswitch; 195251877Speter case '#': 196251877Speter sharpflag = 1; 197251877Speter goto reswitch; 198251877Speter case '+': 199251877Speter sign = 1; 200251877Speter goto reswitch; 201251877Speter case '-': 202 ladjust = 1; 203 goto reswitch; 204 case '%': 205 PCHAR(ch); 206 break; 207 case '*': 208 if (!dot) { 209 width = va_arg(ap, int); 210 if (width < 0) { 211 ladjust = !ladjust; 212 width = -width; 213 } 214 } else { 215 dwidth = va_arg(ap, int); 216 } 217 goto reswitch; 218 case '0': 219 if (!dot) { 220 padc = '0'; 221 goto reswitch; 222 } 223 case '1': case '2': case '3': case '4': 224 case '5': case '6': case '7': case '8': case '9': 225 for (n = 0;; ++fmt) { 226 n = n * 10 + ch - '0'; 227 ch = *fmt; 228 if (ch < '0' || ch > '9') 229 break; 230 } 231 if (dot) 232 dwidth = n; 233 else 234 width = n; 235 goto reswitch; 236 case 'b': 237 num = va_arg(ap, int); 238 p = va_arg(ap, char *); 239 for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;) 240 PCHAR(*q--); 241 242 if (num == 0) 243 break; 244 245 for (tmp = 0; *p;) { 246 n = *p++; 247 if (num & (1 << (n - 1))) { 248 PCHAR(tmp ? ',' : '<'); 249 for (; (n = *p) > ' '; ++p) 250 PCHAR(n); 251 tmp = 1; 252 } else 253 for (; *p > ' '; ++p) 254 continue; 255 } 256 if (tmp) 257 PCHAR('>'); 258 break; 259 case 'c': 260 PCHAR(va_arg(ap, int)); 261 break; 262 case 'D': 263 up = va_arg(ap, u_char *); 264 p = va_arg(ap, char *); 265 if (!width) 266 width = 16; 267 while(width--) { 268 PCHAR(hex2ascii(*up >> 4)); 269 PCHAR(hex2ascii(*up & 0x0f)); 270 up++; 271 if (width) 272 for (q=p;*q;q++) 273 PCHAR(*q); 274 } 275 break; 276 case 'd': 277 case 'i': 278 base = 10; 279 sign = 1; 280 goto handle_sign; 281 case 'j': 282 jflag = 1; 283 goto reswitch; 284 case 'l': 285 if (lflag) { 286 lflag = 0; 287 qflag = 1; 288 } else 289 lflag = 1; 290 goto reswitch; 291 case 'n': 292 if (jflag) 293 *(va_arg(ap, intmax_t *)) = retval; 294 else if (qflag) 295 *(va_arg(ap, quad_t *)) = retval; 296 else if (lflag) 297 *(va_arg(ap, long *)) = retval; 298 else if (zflag) 299 *(va_arg(ap, size_t *)) = retval; 300 else 301 *(va_arg(ap, int *)) = retval; 302 break; 303 case 'o': 304 base = 8; 305 goto handle_nosign; 306 case 'p': 307 base = 16; 308 sharpflag = (width == 0); 309 sign = 0; 310 num = (uintptr_t)va_arg(ap, void *); 311 goto number; 312 case 'q': 313 qflag = 1; 314 goto reswitch; 315 case 'r': 316 base = radix; 317 if (sign) 318 goto handle_sign; 319 goto handle_nosign; 320 case 's': 321 p = va_arg(ap, char *); 322 if (p == NULL) 323 p = "(null)"; 324 if (!dot) 325 n = strlen (p); 326 else 327 for (n = 0; n < dwidth && p[n]; n++) 328 continue; 329 330 width -= n; 331 332 if (!ladjust && width > 0) 333 while (width--) 334 PCHAR(padc); 335 while (n--) 336 PCHAR(*p++); 337 if (ladjust && width > 0) 338 while (width--) 339 PCHAR(padc); 340 break; 341 case 't': 342 tflag = 1; 343 goto reswitch; 344 case 'u': 345 base = 10; 346 goto handle_nosign; 347 case 'X': 348 upper = 1; 349 case 'x': 350 base = 16; 351 goto handle_nosign; 352 case 'y': 353 base = 16; 354 sign = 1; 355 goto handle_sign; 356 case 'z': 357 zflag = 1; 358 goto reswitch; 359handle_nosign: 360 sign = 0; 361 if (jflag) 362 num = va_arg(ap, uintmax_t); 363 else if (qflag) 364 num = va_arg(ap, u_quad_t); 365 else if (tflag) 366 num = va_arg(ap, ptrdiff_t); 367 else if (lflag) 368 num = va_arg(ap, u_long); 369 else if (zflag) 370 num = va_arg(ap, size_t); 371 else 372 num = va_arg(ap, u_int); 373 goto number; 374handle_sign: 375 if (jflag) 376 num = va_arg(ap, intmax_t); 377 else if (qflag) 378 num = va_arg(ap, quad_t); 379 else if (tflag) 380 num = va_arg(ap, ptrdiff_t); 381 else if (lflag) 382 num = va_arg(ap, long); 383 else if (zflag) 384 num = va_arg(ap, ssize_t); 385 else 386 num = va_arg(ap, int); 387number: 388 if (sign && (intmax_t)num < 0) { 389 neg = 1; 390 num = -(intmax_t)num; 391 } 392 p = ksprintn(nbuf, num, base, &tmp, upper); 393 if (sharpflag && num != 0) { 394 if (base == 8) 395 tmp++; 396 else if (base == 16) 397 tmp += 2; 398 } 399 if (neg) 400 tmp++; 401 402 if (!ladjust && width && (width -= tmp) > 0) 403 while (width--) 404 PCHAR(padc); 405 if (neg) 406 PCHAR('-'); 407 if (sharpflag && num != 0) { 408 if (base == 8) { 409 PCHAR('0'); 410 } else if (base == 16) { 411 PCHAR('0'); 412 PCHAR('x'); 413 } 414 } 415 416 while (*p) 417 PCHAR(*p--); 418 419 if (ladjust && width && (width -= tmp) > 0) 420 while (width--) 421 PCHAR(padc); 422 423 break; 424 default: 425 while (percent < fmt) 426 PCHAR(*percent++); 427 break; 428 } 429 } 430#undef PCHAR 431} 432