printf.c revision 84221
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 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94 39 */ 40 41#include <sys/cdefs.h> 42__FBSDID("$FreeBSD: head/lib/libstand/printf.c 84221 2001-09-30 22:28:01Z dillon $"); 43 44/* 45 * Standaloneified version of the FreeBSD kernel printf family. 46 */ 47 48#include <sys/types.h> 49#include <string.h> 50#include "stand.h" 51 52/* 53 * Note that stdarg.h and the ANSI style va_start macro is used for both 54 * ANSI and traditional C compilers. 55 */ 56#include <machine/stdarg.h> 57 58static char *ksprintn (u_long num, int base, int *len); 59static int kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap); 60 61int 62printf(const char *fmt, ...) 63{ 64 va_list ap; 65 int retval; 66 67 va_start(ap, fmt); 68 retval = kvprintf(fmt, putchar, NULL, 10, ap); 69 va_end(ap); 70 return retval; 71} 72 73void 74vprintf(const char *fmt, va_list ap) 75{ 76 77 kvprintf(fmt, putchar, NULL, 10, ap); 78} 79 80int 81sprintf(char *buf, const char *cfmt, ...) 82{ 83 int retval; 84 va_list ap; 85 86 va_start(ap, cfmt); 87 retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); 88 buf[retval] = '\0'; 89 va_end(ap); 90 return retval; 91} 92 93void 94vsprintf(char *buf, const char *cfmt, va_list ap) 95{ 96 int retval; 97 98 retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); 99 buf[retval] = '\0'; 100} 101 102/* 103 * Put a number (base <= 16) in a buffer in reverse order; return an 104 * optional length and a pointer to the NULL terminated (preceded?) 105 * buffer. 106 */ 107static char * 108ksprintn(ul, base, lenp) 109 register u_long ul; 110 register int base, *lenp; 111{ /* A long in base 8, plus NULL. */ 112 static char buf[sizeof(long) * NBBY / 3 + 2]; 113 register char *p; 114 115 p = buf; 116 do { 117 *++p = hex2ascii(ul % base); 118 } while (ul /= base); 119 if (lenp) 120 *lenp = p - buf; 121 return (p); 122} 123 124/* 125 * Scaled down version of printf(3). 126 * 127 * Two additional formats: 128 * 129 * The format %b is supported to decode error registers. 130 * Its usage is: 131 * 132 * printf("reg=%b\n", regval, "<base><arg>*"); 133 * 134 * where <base> is the output base expressed as a control character, e.g. 135 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, 136 * the first of which gives the bit number to be inspected (origin 1), and 137 * the next characters (up to a control character, i.e. a character <= 32), 138 * give the name of the register. Thus: 139 * 140 * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 141 * 142 * would produce output: 143 * 144 * reg=3<BITTWO,BITONE> 145 * 146 * XXX: %D -- Hexdump, takes pointer and separator string: 147 * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX 148 * ("%*D", len, ptr, " " -> XX XX XX XX ... 149 */ 150static int 151kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap) 152{ 153#define PCHAR(c) {int cc=(c); if (func) (*func)(cc); else *d++ = cc; retval++; } 154 char *p, *q, *d; 155 u_char *up; 156 int ch, n; 157 u_long ul; 158 int base, lflag, tmp, width, ladjust, sharpflag, neg, sign, dot; 159 int dwidth; 160 char padc; 161 int retval = 0; 162 163 if (!func) 164 d = (char *) arg; 165 else 166 d = NULL; 167 168 if (fmt == NULL) 169 fmt = "(fmt null)\n"; 170 171 if (radix < 2 || radix > 36) 172 radix = 10; 173 174 for (;;) { 175 padc = ' '; 176 width = 0; 177 while ((ch = (u_char)*fmt++) != '%') { 178 if (ch == '\0') 179 return retval; 180 PCHAR(ch); 181 } 182 lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; 183 sign = 0; dot = 0; dwidth = 0; 184reswitch: switch (ch = (u_char)*fmt++) { 185 case '.': 186 dot = 1; 187 goto reswitch; 188 case '#': 189 sharpflag = 1; 190 goto reswitch; 191 case '+': 192 sign = 1; 193 goto reswitch; 194 case '-': 195 ladjust = 1; 196 goto reswitch; 197 case '%': 198 PCHAR(ch); 199 break; 200 case '*': 201 if (!dot) { 202 width = va_arg(ap, int); 203 if (width < 0) { 204 ladjust = !ladjust; 205 width = -width; 206 } 207 } else { 208 dwidth = va_arg(ap, int); 209 } 210 goto reswitch; 211 case '0': 212 if (!dot) { 213 padc = '0'; 214 goto reswitch; 215 } 216 case '1': case '2': case '3': case '4': 217 case '5': case '6': case '7': case '8': case '9': 218 for (n = 0;; ++fmt) { 219 n = n * 10 + ch - '0'; 220 ch = *fmt; 221 if (ch < '0' || ch > '9') 222 break; 223 } 224 if (dot) 225 dwidth = n; 226 else 227 width = n; 228 goto reswitch; 229 case 'b': 230 ul = va_arg(ap, int); 231 p = va_arg(ap, char *); 232 for (q = ksprintn(ul, *p++, NULL); *q;) 233 PCHAR(*q--); 234 235 if (!ul) 236 break; 237 238 for (tmp = 0; *p;) { 239 n = *p++; 240 if (ul & (1 << (n - 1))) { 241 PCHAR(tmp ? ',' : '<'); 242 for (; (n = *p) > ' '; ++p) 243 PCHAR(n); 244 tmp = 1; 245 } else 246 for (; *p > ' '; ++p) 247 continue; 248 } 249 if (tmp) 250 PCHAR('>'); 251 break; 252 case 'c': 253 PCHAR(va_arg(ap, int)); 254 break; 255 case 'D': 256 up = va_arg(ap, u_char *); 257 p = va_arg(ap, char *); 258 if (!width) 259 width = 16; 260 while(width--) { 261 PCHAR(hex2ascii(*up >> 4)); 262 PCHAR(hex2ascii(*up & 0x0f)); 263 up++; 264 if (width) 265 for (q=p;*q;q++) 266 PCHAR(*q); 267 } 268 break; 269 case 'd': 270 ul = lflag ? va_arg(ap, long) : va_arg(ap, int); 271 sign = 1; 272 base = 10; 273 goto number; 274 case 'l': 275 lflag = 1; 276 goto reswitch; 277 case 'n': 278 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 279 base = radix; 280 goto number; 281 case 'o': 282 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 283 base = 8; 284 goto number; 285 case 'p': 286 ul = (u_long)va_arg(ap, void *); 287 base = 16; 288 sharpflag = 1; 289 goto number; 290 case 's': 291 p = va_arg(ap, char *); 292 if (p == NULL) 293 p = "(null)"; 294 if (!dot) 295 n = strlen (p); 296 else 297 for (n = 0; n < dwidth && p[n]; n++) 298 continue; 299 300 width -= n; 301 302 if (!ladjust && width > 0) 303 while (width--) 304 PCHAR(padc); 305 while (n--) 306 PCHAR(*p++); 307 if (ladjust && width > 0) 308 while (width--) 309 PCHAR(padc); 310 break; 311 case 'u': 312 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 313 base = 10; 314 goto number; 315 case 'x': 316 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 317 base = 16; 318number: if (sign && (long)ul < 0L) { 319 neg = 1; 320 ul = -(long)ul; 321 } 322 p = ksprintn(ul, base, &tmp); 323 if (sharpflag && ul != 0) { 324 if (base == 8) 325 tmp++; 326 else if (base == 16) 327 tmp += 2; 328 } 329 if (neg) 330 tmp++; 331 332 if (!ladjust && width && (width -= tmp) > 0) 333 while (width--) 334 PCHAR(padc); 335 if (neg) 336 PCHAR('-'); 337 if (sharpflag && ul != 0) { 338 if (base == 8) { 339 PCHAR('0'); 340 } else if (base == 16) { 341 PCHAR('0'); 342 PCHAR('x'); 343 } 344 } 345 346 while (*p) 347 PCHAR(*p--); 348 349 if (ladjust && width && (width -= tmp) > 0) 350 while (width--) 351 PCHAR(padc); 352 353 break; 354 default: 355 PCHAR('%'); 356 if (lflag) 357 PCHAR('l'); 358 PCHAR(ch); 359 break; 360 } 361 } 362#undef PCHAR 363} 364 365