printf.c revision 38451
187628Sdwmalone/*- 287294Sdwmalone * Copyright (c) 1986, 1988, 1991, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * (c) UNIX System Laboratories, Inc. 51590Srgrimes * All or some portions of this file are derived from material licensed 61590Srgrimes * 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 * $Id: subr_prf.c,v 1.46 1998/05/28 09:30:20 phk Exp $ 40 */ 41 42/* 43 * Standaloneified version of the FreeBSD kernel printf family. 44 */ 45 46#include <sys/types.h> 47#include "stand.h" 48 49/* 50 * Note that stdarg.h and the ANSI style va_start macro is used for both 51 * ANSI and traditional C compilers. 52 */ 53#include <machine/stdarg.h> 54 55static char *ksprintn (u_long num, int base, int *len); 56static int kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap); 57 58int 59printf(const char *fmt, ...) 60{ 61 va_list ap; 62 int retval; 63 64 va_start(ap, fmt); 65 retval = kvprintf(fmt, putchar, NULL, 10, ap); 66 va_end(ap); 67 return retval; 68} 69 70void 71vprintf(const char *fmt, va_list ap) 72{ 73 74 kvprintf(fmt, putchar, NULL, 10, ap); 75} 76 77/* 78 * Scaled down version of sprintf(3). 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 93/* 94 * Put a number (base <= 16) in a buffer in reverse order; return an 95 * optional length and a pointer to the NULL terminated (preceded?) 96 * buffer. 97 */ 98static char * 99ksprintn(ul, base, lenp) 100 register u_long ul; 101 register int base, *lenp; 102{ /* A long in base 8, plus NULL. */ 103 static char buf[sizeof(long) * NBBY / 3 + 2]; 104 register char *p; 105 106 p = buf; 107 do { 108 *++p = hex2ascii(ul % base); 109 } while (ul /= base); 110 if (lenp) 111 *lenp = p - buf; 112 return (p); 113} 114 115/* 116 * Scaled down version of printf(3). 117 * 118 * Two additional formats: 119 * 120 * The format %b is supported to decode error registers. 121 * Its usage is: 122 * 123 * printf("reg=%b\n", regval, "<base><arg>*"); 124 * 125 * where <base> is the output base expressed as a control character, e.g. 126 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, 127 * the first of which gives the bit number to be inspected (origin 1), and 128 * the next characters (up to a control character, i.e. a character <= 32), 129 * give the name of the register. Thus: 130 * 131 * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 132 * 133 * would produce output: 134 * 135 * reg=3<BITTWO,BITONE> 136 * 137 * XXX: %D -- Hexdump, takes pointer and separator string: 138 * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX 139 * ("%*D", len, ptr, " " -> XX XX XX XX ... 140 */ 141static int 142kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap) 143{ 144#define PCHAR(c) {int cc=(c); if (func) (*func)(cc); else *d++ = cc; retval++; } 145 char *p, *q, *d; 146 u_char *up; 147 int ch, n; 148 u_long ul; 149 int base, lflag, tmp, width, ladjust, sharpflag, neg, sign, dot; 150 int dwidth; 151 char padc; 152 int retval = 0; 153 154 if (!func) 155 d = (char *) arg; 156 else 157 d = NULL; 158 159 if (fmt == NULL) 160 fmt = "(fmt null)\n"; 161 162 if (radix < 2 || radix > 36) 163 radix = 10; 164 165 for (;;) { 166 padc = ' '; 167 width = 0; 168 while ((ch = (u_char)*fmt++) != '%') { 169 if (ch == '\0') 170 return retval; 171 PCHAR(ch); 172 } 173 lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; 174 sign = 0; dot = 0; dwidth = 0; 175reswitch: switch (ch = (u_char)*fmt++) { 176 case '.': 177 dot = 1; 178 goto reswitch; 179 case '#': 180 sharpflag = 1; 181 goto reswitch; 182 case '+': 183 sign = 1; 184 goto reswitch; 185 case '-': 186 ladjust = 1; 187 goto reswitch; 188 case '%': 189 PCHAR(ch); 190 break; 191 case '*': 192 if (!dot) { 193 width = va_arg(ap, int); 194 if (width < 0) { 195 ladjust = !ladjust; 196 width = -width; 197 } 198 } else { 199 dwidth = va_arg(ap, int); 200 } 201 goto reswitch; 202 case '0': 203 if (!dot) { 204 padc = '0'; 205 goto reswitch; 206 } 207 case '1': case '2': case '3': case '4': 208 case '5': case '6': case '7': case '8': case '9': 209 for (n = 0;; ++fmt) { 210 n = n * 10 + ch - '0'; 211 ch = *fmt; 212 if (ch < '0' || ch > '9') 213 break; 214 } 215 if (dot) 216 dwidth = n; 217 else 218 width = n; 219 goto reswitch; 220 case 'b': 221 ul = va_arg(ap, int); 222 p = va_arg(ap, char *); 223 for (q = ksprintn(ul, *p++, NULL); *q;) 224 PCHAR(*q--); 225 226 if (!ul) 227 break; 228 229 for (tmp = 0; *p;) { 230 n = *p++; 231 if (ul & (1 << (n - 1))) { 232 PCHAR(tmp ? ',' : '<'); 233 for (; (n = *p) > ' '; ++p) 234 PCHAR(n); 235 tmp = 1; 236 } else 237 for (; *p > ' '; ++p) 238 continue; 239 } 240 if (tmp) 241 PCHAR('>'); 242 break; 243 case 'c': 244 PCHAR(va_arg(ap, int)); 245 break; 246 case 'D': 247 up = va_arg(ap, u_char *); 248 p = va_arg(ap, char *); 249 if (!width) 250 width = 16; 251 while(width--) { 252 PCHAR(hex2ascii(*up >> 4)); 253 PCHAR(hex2ascii(*up & 0x0f)); 254 up++; 255 if (width) 256 for (q=p;*q;q++) 257 PCHAR(*q); 258 } 259 break; 260 case 'd': 261 ul = lflag ? va_arg(ap, long) : va_arg(ap, int); 262 sign = 1; 263 base = 10; 264 goto number; 265 case 'l': 266 lflag = 1; 267 goto reswitch; 268 case 'n': 269 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 270 base = radix; 271 goto number; 272 case 'o': 273 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 274 base = 8; 275 goto number; 276 case 'p': 277 ul = (u_long)va_arg(ap, void *); 278 base = 16; 279 sharpflag = 1; 280 goto number; 281 case 's': 282 p = va_arg(ap, char *); 283 if (p == NULL) 284 p = "(null)"; 285 if (!dot) 286 n = strlen (p); 287 else 288 for (n = 0; n < dwidth && p[n]; n++) 289 continue; 290 291 width -= n; 292 293 if (!ladjust && width > 0) 294 while (width--) 295 PCHAR(padc); 296 while (n--) 297 PCHAR(*p++); 298 if (ladjust && width > 0) 299 while (width--) 300 PCHAR(padc); 301 break; 302 case 'u': 303 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 304 base = 10; 305 goto number; 306 case 'x': 307 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 308 base = 16; 309number: if (sign && (long)ul < 0L) { 310 neg = 1; 311 ul = -(long)ul; 312 } 313 p = ksprintn(ul, base, &tmp); 314 if (sharpflag && ul != 0) { 315 if (base == 8) 316 tmp++; 317 else if (base == 16) 318 tmp += 2; 319 } 320 if (neg) 321 tmp++; 322 323 if (!ladjust && width && (width -= tmp) > 0) 324 while (width--) 325 PCHAR(padc); 326 if (neg) 327 PCHAR('-'); 328 if (sharpflag && ul != 0) { 329 if (base == 8) { 330 PCHAR('0'); 331 } else if (base == 16) { 332 PCHAR('0'); 333 PCHAR('x'); 334 } 335 } 336 337 while (*p) 338 PCHAR(*p--); 339 340 if (ladjust && width && (width -= tmp) > 0) 341 while (width--) 342 PCHAR(padc); 343 344 break; 345 default: 346 PCHAR('%'); 347 if (lflag) 348 PCHAR('l'); 349 PCHAR(ch); 350 break; 351 } 352 } 353#undef PCHAR 354} 355 356