1 /* $OpenBSD: printf.c,v 1.24 2006/09/18 21:11:50 mpf Exp $ */ 2 /* $NetBSD: printf.c,v 1.10 1996/11/30 04:19:21 gwr Exp $ */ 3 4 /*- 5 * Copyright (c) 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * @(#)printf.c 8.1 (Berkeley) 6/11/93 33 */ 34 35 /* 36 * Scaled down version of printf(3). 37 * 38 * One additional format: 39 * 40 * The format %b is supported to decode error registers. 41 * Its usage is: 42 * 43 * printf("reg=%b\n", regval, "<base><arg>*"); 44 * 45 * where <base> is the output base expressed as a control character, e.g. 46 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, 47 * the first of which gives the bit number to be inspected (origin 1), and 48 * the next characters (up to a control character, i.e. a character <= 32), 49 * give the name of the register. Thus: 50 * 51 * printf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 52 * 53 * would produce output: 54 * 55 * reg=3<BITTWO,BITONE> 56 */ 57 58 #include <sys/cdefs.h> 59 #include <sys/types.h> 60 #include <sys/stdarg.h> 61 62 #include "stand.h" 63 64 void kprintn(void (*)(int), u_long, int); 65 #ifdef LIBSA_LONGLONG_PRINTF 66 void kprintn64(void (*)(int), u_int64_t, int); 67 #endif 68 void kdoprnt(void (*)(int), const char *, va_list); 69 70 const char hexdig[] = "0123456789abcdef"; 71 72 void 73 printf(const char *fmt, ...) 74 { 75 va_list ap; 76 77 va_start(ap, fmt); 78 kdoprnt(putchar, fmt, ap); 79 va_end(ap); 80 } 81 82 void 83 vprintf(const char *fmt, va_list ap) 84 { 85 kdoprnt(putchar, fmt, ap); 86 } 87 88 void 89 kdoprnt(void (*put)(int), const char *fmt, va_list ap) 90 { 91 #ifdef LIBSA_LONGLONG_PRINTF 92 u_int64_t ull; 93 #endif 94 unsigned long ul; 95 int ch, lflag; 96 char *p; 97 98 for (;;) { 99 while ((ch = *fmt++) != '%') { 100 if (ch == '\0') 101 return; 102 put(ch); 103 } 104 lflag = 0; 105 reswitch: switch (ch = *fmt++) { 106 case 'l': 107 lflag++; 108 goto reswitch; 109 #ifndef STRIPPED 110 case 'b': 111 { 112 int set, n; 113 114 ul = va_arg(ap, int); 115 p = va_arg(ap, char *); 116 kprintn(put, ul, *p++); 117 118 if (!ul) 119 break; 120 121 for (set = 0; (n = *p++);) { 122 if (ul & (1 << (n - 1))) { 123 put(set ? ',' : '<'); 124 for (; (n = *p) > ' '; ++p) 125 put(n); 126 set = 1; 127 } else 128 for (; *p > ' '; ++p) 129 ; 130 } 131 if (set) 132 put('>'); 133 } 134 break; 135 #endif 136 case 'c': 137 ch = va_arg(ap, int); 138 put(ch & 0x7f); 139 break; 140 case 's': 141 p = va_arg(ap, char *); 142 while ((ch = *p++)) 143 put(ch); 144 break; 145 case 'd': 146 #ifdef LIBSA_LONGLONG_PRINTF 147 if (lflag > 1) { 148 ull = va_arg(ap, int64_t); 149 if ((int64_t)ull < 0) { 150 put('-'); 151 ull = -(int64_t)ull; 152 } 153 kprintn64(put, ull, 10); 154 break; 155 } 156 #endif 157 ul = lflag ? 158 va_arg(ap, long) : va_arg(ap, int); 159 if ((long)ul < 0) { 160 put('-'); 161 ul = -(long)ul; 162 } 163 kprintn(put, ul, 10); 164 break; 165 case 'o': 166 #ifdef LIBSA_LONGLONG_PRINTF 167 if (lflag > 1) { 168 ull = va_arg(ap, u_int64_t); 169 kprintn64(put, ull, 8); 170 break; 171 } 172 #endif 173 ul = lflag ? 174 va_arg(ap, u_long) : va_arg(ap, u_int); 175 kprintn(put, ul, 8); 176 break; 177 case 'u': 178 #ifdef LIBSA_LONGLONG_PRINTF 179 if (lflag > 1) { 180 ull = va_arg(ap, u_int64_t); 181 kprintn64(put, ull, 10); 182 break; 183 } 184 #endif 185 ul = lflag ? 186 va_arg(ap, u_long) : va_arg(ap, u_int); 187 kprintn(put, ul, 10); 188 break; 189 case 'p': 190 put('0'); 191 put('x'); 192 lflag += sizeof(void *)==sizeof(u_long)? 1 : 0; 193 case 'x': 194 #ifdef LIBSA_LONGLONG_PRINTF 195 if (lflag > 1) { 196 ull = va_arg(ap, u_int64_t); 197 kprintn64(put, ull, 16); 198 break; 199 } 200 #else 201 if (lflag > 1) { 202 /* hold an int64_t in base 16 */ 203 char *p, buf[(sizeof(u_int64_t) * NBBY / 4) + 1]; 204 u_int64_t ull; 205 206 ull = va_arg(ap, u_int64_t); 207 p = buf; 208 do { 209 *p++ = hexdig[ull & 15]; 210 } while (ull >>= 4); 211 do { 212 put(*--p); 213 } while (p > buf); 214 break; 215 } 216 #endif 217 ul = lflag ? 218 va_arg(ap, u_long) : va_arg(ap, u_int); 219 kprintn(put, ul, 16); 220 break; 221 default: 222 put('%'); 223 #ifdef LIBSA_LONGLONG_PRINTF 224 while (--lflag) 225 #else 226 if (lflag) 227 #endif 228 put('l'); 229 put(ch); 230 } 231 } 232 va_end(ap); 233 } 234 235 void 236 kprintn(void (*put)(int), unsigned long ul, int base) 237 { 238 /* hold a long in base 8 */ 239 char *p, buf[(sizeof(long) * NBBY / 3) + 1]; 240 241 p = buf; 242 do { 243 *p++ = hexdig[ul % base]; 244 } while (ul /= base); 245 do { 246 put(*--p); 247 } while (p > buf); 248 } 249 250 #ifdef LIBSA_LONGLONG_PRINTF 251 void 252 kprintn64(void (*put)(int), u_int64_t ull, int base) 253 { 254 /* hold an int64_t in base 8 */ 255 char *p, buf[(sizeof(u_int64_t) * NBBY / 3) + 1]; 256 257 p = buf; 258 do { 259 *p++ = hexdig[ull % base]; 260 } while (ull /= base); 261 do { 262 put(*--p); 263 } while (p > buf); 264 } 265 #endif 266 267 int donottwiddle = 0; 268 269 void 270 twiddle(void) 271 { 272 static int pos; 273 274 if (!donottwiddle) { 275 putchar("|/-\\"[pos++ & 3]); 276 putchar('\b'); 277 } 278 } 279