1 /*- 2 * Copyright (c) 1986, 1988, 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * (c) UNIX System Laboratories, Inc. 5 * All or some portions of this file are derived from material licensed 6 * to the University of California by American Telephone and Telegraph 7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 * the permission of UNIX System Laboratories, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 4. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94 35 */ 36 37 /* 38 * Portions copyright (c) 2009-2014, ARM Limited and Contributors. 39 * All rights reserved. 40 */ 41 42 #include <stdio.h> 43 #include <stdint.h> 44 #include <stdarg.h> 45 #include <stddef.h> 46 #include <string.h> 47 #include <ctype.h> 48 49 typedef unsigned char u_char; 50 typedef unsigned int u_int; 51 typedef int64_t quad_t; 52 typedef uint64_t u_quad_t; 53 typedef unsigned long u_long; 54 typedef unsigned short u_short; 55 56 static inline int imax(int a, int b) { return (a > b ? a : b); } 57 58 /* 59 * Note that stdarg.h and the ANSI style va_start macro is used for both 60 * ANSI and traditional C compilers. 61 */ 62 63 #define TOCONS 0x01 64 #define TOTTY 0x02 65 #define TOLOG 0x04 66 67 /* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */ 68 #define MAXNBUF (sizeof(intmax_t) * 8 + 1) 69 70 struct putchar_arg { 71 int flags; 72 int pri; 73 struct tty *tty; 74 char *p_bufr; 75 size_t n_bufr; 76 char *p_next; 77 size_t remain; 78 }; 79 80 struct snprintf_arg { 81 char *str; 82 size_t remain; 83 }; 84 85 extern int log_open; 86 87 static char *ksprintn(char *nbuf, uintmax_t num, int base, int *len, int upper); 88 static void snprintf_func(int ch, void *arg); 89 static int kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap); 90 91 int vsnprintf(char *str, size_t size, const char *format, va_list ap); 92 93 static char const hex2ascii_data[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 94 #define hex2ascii(hex) (hex2ascii_data[hex]) 95 96 /* 97 * Scaled down version of sprintf(3). 98 */ 99 int 100 sprintf(char *buf, const char *cfmt, ...) 101 { 102 int retval; 103 va_list ap; 104 105 va_start(ap, cfmt); 106 retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); 107 buf[retval] = '\0'; 108 va_end(ap); 109 return (retval); 110 } 111 112 /* 113 * Scaled down version of vsprintf(3). 114 */ 115 int 116 vsprintf(char *buf, const char *cfmt, va_list ap) 117 { 118 int retval; 119 120 retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); 121 buf[retval] = '\0'; 122 return (retval); 123 } 124 125 /* 126 * Scaled down version of snprintf(3). 127 */ 128 int 129 snprintf(char *str, size_t size, const char *format, ...) 130 { 131 int retval; 132 va_list ap; 133 134 va_start(ap, format); 135 retval = vsnprintf(str, size, format, ap); 136 va_end(ap); 137 return(retval); 138 } 139 140 /* 141 * Scaled down version of vsnprintf(3). 142 */ 143 int 144 vsnprintf(char *str, size_t size, const char *format, va_list ap) 145 { 146 struct snprintf_arg info; 147 int retval; 148 149 info.str = str; 150 info.remain = size; 151 retval = kvprintf(format, snprintf_func, &info, 10, ap); 152 if (info.remain >= 1) 153 *info.str++ = '\0'; 154 return (retval); 155 } 156 157 static void 158 snprintf_func(int ch, void *arg) 159 { 160 struct snprintf_arg *const info = arg; 161 162 if (info->remain >= 2) { 163 *info->str++ = ch; 164 info->remain--; 165 } 166 } 167 168 169 /* 170 * Kernel version which takes radix argument vsnprintf(3). 171 */ 172 int 173 vsnrprintf(char *str, size_t size, int radix, const char *format, va_list ap) 174 { 175 struct snprintf_arg info; 176 int retval; 177 178 info.str = str; 179 info.remain = size; 180 retval = kvprintf(format, snprintf_func, &info, radix, ap); 181 if (info.remain >= 1) 182 *info.str++ = '\0'; 183 return (retval); 184 } 185 186 187 /* 188 * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse 189 * order; return an optional length and a pointer to the last character 190 * written in the buffer (i.e., the first character of the string). 191 * The buffer pointed to by `nbuf' must have length >= MAXNBUF. 192 */ 193 static char * 194 ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper) 195 { 196 char *p, c; 197 198 p = nbuf; 199 *p = '\0'; 200 do { 201 c = hex2ascii(num % base); 202 *++p = upper ? toupper(c) : c; 203 } while (num /= base); 204 if (lenp) 205 *lenp = p - nbuf; 206 return (p); 207 } 208 209 /* 210 * Scaled down version of printf(3). 211 * 212 * Two additional formats: 213 * 214 * The format %b is supported to decode error registers. 215 * Its usage is: 216 * 217 * printf("reg=%b\n", regval, "<base><arg>*"); 218 * 219 * where <base> is the output base expressed as a control character, e.g. 220 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, 221 * the first of which gives the bit number to be inspected (origin 1), and 222 * the next characters (up to a control character, i.e. a character <= 32), 223 * give the name of the register. Thus: 224 * 225 * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 226 * 227 * would produce output: 228 * 229 * reg=3<BITTWO,BITONE> 230 * 231 * XXX: %D -- Hexdump, takes pointer and separator string: 232 * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX 233 * ("%*D", len, ptr, " " -> XX XX XX XX ... 234 */ 235 int 236 kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap) 237 { 238 #define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; } 239 char nbuf[MAXNBUF]; 240 char *d; 241 const char *p, *percent, *q; 242 u_char *up; 243 int ch, n; 244 uintmax_t num; 245 int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot; 246 int cflag, hflag, jflag, tflag, zflag; 247 int dwidth, upper; 248 char padc; 249 int stop = 0, retval = 0; 250 251 num = 0; 252 if (!func) 253 d = (char *) arg; 254 else 255 d = NULL; 256 257 if (fmt == NULL) 258 fmt = "(fmt null)\n"; 259 260 if (radix < 2 || radix > 36) 261 radix = 10; 262 263 for (;;) { 264 padc = ' '; 265 width = 0; 266 while ((ch = (u_char)*fmt++) != '%' || stop) { 267 if (ch == '\0') 268 return (retval); 269 PCHAR(ch); 270 } 271 percent = fmt - 1; 272 qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; 273 sign = 0; dot = 0; dwidth = 0; upper = 0; 274 cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0; 275 reswitch: switch (ch = (u_char)*fmt++) { 276 case '.': 277 dot = 1; 278 goto reswitch; 279 case '#': 280 sharpflag = 1; 281 goto reswitch; 282 case '+': 283 sign = 1; 284 goto reswitch; 285 case '-': 286 ladjust = 1; 287 goto reswitch; 288 case '%': 289 PCHAR(ch); 290 break; 291 case '*': 292 if (!dot) { 293 width = va_arg(ap, int); 294 if (width < 0) { 295 ladjust = !ladjust; 296 width = -width; 297 } 298 } else { 299 dwidth = va_arg(ap, int); 300 } 301 goto reswitch; 302 case '0': 303 if (!dot) { 304 padc = '0'; 305 goto reswitch; 306 } 307 case '1': case '2': case '3': case '4': 308 case '5': case '6': case '7': case '8': case '9': 309 for (n = 0;; ++fmt) { 310 n = n * 10 + ch - '0'; 311 ch = *fmt; 312 if (ch < '0' || ch > '9') 313 break; 314 } 315 if (dot) 316 dwidth = n; 317 else 318 width = n; 319 goto reswitch; 320 case 'b': 321 num = (u_int)va_arg(ap, int); 322 p = va_arg(ap, char *); 323 for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;) 324 PCHAR(*q--); 325 326 if (num == 0) 327 break; 328 329 for (tmp = 0; *p;) { 330 n = *p++; 331 if (num & (1 << (n - 1))) { 332 PCHAR(tmp ? ',' : '<'); 333 for (; (n = *p) > ' '; ++p) 334 PCHAR(n); 335 tmp = 1; 336 } else 337 for (; *p > ' '; ++p) 338 continue; 339 } 340 if (tmp) 341 PCHAR('>'); 342 break; 343 case 'c': 344 PCHAR(va_arg(ap, int)); 345 break; 346 case 'D': 347 up = va_arg(ap, u_char *); 348 p = va_arg(ap, char *); 349 if (!width) 350 width = 16; 351 while(width--) { 352 PCHAR(hex2ascii(*up >> 4)); 353 PCHAR(hex2ascii(*up & 0x0f)); 354 up++; 355 if (width) 356 for (q=p;*q;q++) 357 PCHAR(*q); 358 } 359 break; 360 case 'd': 361 case 'i': 362 base = 10; 363 sign = 1; 364 goto handle_sign; 365 case 'h': 366 if (hflag) { 367 hflag = 0; 368 cflag = 1; 369 } else 370 hflag = 1; 371 goto reswitch; 372 case 'j': 373 jflag = 1; 374 goto reswitch; 375 case 'l': 376 if (lflag) { 377 lflag = 0; 378 qflag = 1; 379 } else 380 lflag = 1; 381 goto reswitch; 382 case 'n': 383 if (jflag) 384 *(va_arg(ap, intmax_t *)) = retval; 385 else if (qflag) 386 *(va_arg(ap, quad_t *)) = retval; 387 else if (lflag) 388 *(va_arg(ap, long *)) = retval; 389 else if (zflag) 390 *(va_arg(ap, size_t *)) = retval; 391 else if (hflag) 392 *(va_arg(ap, short *)) = retval; 393 else if (cflag) 394 *(va_arg(ap, char *)) = retval; 395 else 396 *(va_arg(ap, int *)) = retval; 397 break; 398 case 'o': 399 base = 8; 400 goto handle_nosign; 401 case 'p': 402 base = 16; 403 sharpflag = (width == 0); 404 sign = 0; 405 num = (uintptr_t)va_arg(ap, void *); 406 goto number; 407 case 'q': 408 qflag = 1; 409 goto reswitch; 410 case 'r': 411 base = radix; 412 if (sign) 413 goto handle_sign; 414 goto handle_nosign; 415 case 's': 416 p = va_arg(ap, char *); 417 if (p == NULL) 418 p = "(null)"; 419 if (!dot) 420 n = strlen (p); 421 else 422 for (n = 0; n < dwidth && p[n]; n++) 423 continue; 424 425 width -= n; 426 427 if (!ladjust && width > 0) 428 while (width--) 429 PCHAR(padc); 430 while (n--) 431 PCHAR(*p++); 432 if (ladjust && width > 0) 433 while (width--) 434 PCHAR(padc); 435 break; 436 case 't': 437 tflag = 1; 438 goto reswitch; 439 case 'u': 440 base = 10; 441 goto handle_nosign; 442 case 'X': 443 upper = 1; 444 case 'x': 445 base = 16; 446 goto handle_nosign; 447 case 'y': 448 base = 16; 449 sign = 1; 450 goto handle_sign; 451 case 'z': 452 zflag = 1; 453 goto reswitch; 454 handle_nosign: 455 sign = 0; 456 if (jflag) 457 num = va_arg(ap, uintmax_t); 458 else if (qflag) 459 num = va_arg(ap, u_quad_t); 460 else if (tflag) 461 num = va_arg(ap, ptrdiff_t); 462 else if (lflag) 463 num = va_arg(ap, u_long); 464 else if (zflag) 465 num = va_arg(ap, size_t); 466 else if (hflag) 467 num = (u_short)va_arg(ap, int); 468 else if (cflag) 469 num = (u_char)va_arg(ap, int); 470 else 471 num = va_arg(ap, u_int); 472 goto number; 473 handle_sign: 474 if (jflag) 475 num = va_arg(ap, intmax_t); 476 else if (qflag) 477 num = va_arg(ap, quad_t); 478 else if (tflag) 479 num = va_arg(ap, ptrdiff_t); 480 else if (lflag) 481 num = va_arg(ap, long); 482 else if (zflag) 483 num = va_arg(ap, ssize_t); 484 else if (hflag) 485 num = (short)va_arg(ap, int); 486 else if (cflag) 487 num = (char)va_arg(ap, int); 488 else 489 num = va_arg(ap, int); 490 number: 491 if (sign && (intmax_t)num < 0) { 492 neg = 1; 493 num = -(intmax_t)num; 494 } 495 p = ksprintn(nbuf, num, base, &n, upper); 496 tmp = 0; 497 if (sharpflag && num != 0) { 498 if (base == 8) 499 tmp++; 500 else if (base == 16) 501 tmp += 2; 502 } 503 if (neg) 504 tmp++; 505 506 if (!ladjust && padc == '0') 507 dwidth = width - tmp; 508 width -= tmp + imax(dwidth, n); 509 dwidth -= n; 510 if (!ladjust) 511 while (width-- > 0) 512 PCHAR(' '); 513 if (neg) 514 PCHAR('-'); 515 if (sharpflag && num != 0) { 516 if (base == 8) { 517 PCHAR('0'); 518 } else if (base == 16) { 519 PCHAR('0'); 520 PCHAR('x'); 521 } 522 } 523 while (dwidth-- > 0) 524 PCHAR('0'); 525 526 while (*p) 527 PCHAR(*p--); 528 529 if (ladjust) 530 while (width-- > 0) 531 PCHAR(' '); 532 533 break; 534 default: 535 while (percent < fmt) 536 PCHAR(*percent++); 537 /* 538 * Since we ignore an formatting argument it is no 539 * longer safe to obey the remaining formatting 540 * arguments as the arguments will no longer match 541 * the format specs. 542 */ 543 stop = 1; 544 break; 545 } 546 } 547 #undef PCHAR 548 } 549