1 /* $OpenBSD: printf.c,v 1.28 2018/01/17 08:46:15 patrick 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/types.h> 59 #include <sys/stdarg.h> 60 61 #include "stand.h" 62 63 /* 64 * macros for converting digits to letters and vice versa 65 */ 66 #define to_digit(c) ((c) - '0') 67 #define is_digit(c) ((unsigned)to_digit(c) <= 9) 68 #define to_char(n) ((n) + '0') 69 70 void kprintn(void (*)(int), u_long, int, int, char); 71 #ifdef LIBSA_LONGLONG_PRINTF 72 void kprintn64(void (*)(int), u_int64_t, int, int, char); 73 #endif 74 void kdoprnt(void (*)(int), const char *, va_list); 75 76 const char hexdig[] = "0123456789abcdef"; 77 78 void 79 printf(const char *fmt, ...) 80 { 81 va_list ap; 82 83 va_start(ap, fmt); 84 kdoprnt(putchar, fmt, ap); 85 va_end(ap); 86 } 87 88 void 89 vprintf(const char *fmt, va_list ap) 90 { 91 kdoprnt(putchar, fmt, ap); 92 } 93 94 void 95 kdoprnt(void (*put)(int), const char *fmt, va_list ap) 96 { 97 #ifdef LIBSA_LONGLONG_PRINTF 98 u_int64_t ull; 99 #endif 100 unsigned long ul; 101 int ch, lflag, width, n; 102 char *p, padchar; 103 104 for (;;) { 105 while ((ch = *fmt++) != '%') { 106 if (ch == '\0') 107 return; 108 put(ch); 109 } 110 lflag = 0; 111 padchar = ' '; 112 width = 0; 113 rflag: ch = *fmt++; 114 reswitch: switch (ch) { 115 case '0': 116 /* 117 * ``Note that 0 is taken as a flag, not as the 118 * beginning of a field width.'' 119 * -- ANSI X3J11 120 */ 121 padchar = '0'; 122 goto rflag; 123 case '1': case '2': case '3': case '4': 124 case '5': case '6': case '7': case '8': case '9': 125 n = 0; 126 do { 127 n = 10 * n + to_digit(ch); 128 ch = *fmt++; 129 } while (is_digit(ch)); 130 width = n; 131 goto reswitch; 132 case 'l': 133 lflag++; 134 goto rflag; 135 #ifndef STRIPPED 136 case 'b': 137 { 138 int set, n; 139 140 ul = va_arg(ap, int); 141 p = va_arg(ap, char *); 142 kprintn(put, ul, *p++, width, padchar); 143 144 if (!ul) 145 break; 146 147 for (set = 0; (n = *p++);) { 148 if (ul & (1 << (n - 1))) { 149 put(set ? ',' : '<'); 150 for (; (n = *p) > ' '; ++p) 151 put(n); 152 set = 1; 153 } else 154 for (; *p > ' '; ++p) 155 ; 156 } 157 if (set) 158 put('>'); 159 } 160 break; 161 #endif 162 case 'c': 163 ch = va_arg(ap, int); 164 put(ch & 0x7f); 165 break; 166 case 's': 167 p = va_arg(ap, char *); 168 while ((ch = *p++)) 169 put(ch); 170 break; 171 case 'd': 172 #ifdef LIBSA_LONGLONG_PRINTF 173 if (lflag > 1) { 174 ull = va_arg(ap, int64_t); 175 if ((int64_t)ull < 0) { 176 put('-'); 177 ull = -(int64_t)ull; 178 } 179 kprintn64(put, ull, 10, width, padchar); 180 break; 181 } 182 #endif 183 ul = lflag ? 184 va_arg(ap, long) : va_arg(ap, int); 185 if ((long)ul < 0) { 186 put('-'); 187 ul = -(long)ul; 188 } 189 kprintn(put, ul, 10, width, padchar); 190 break; 191 case 'o': 192 #ifdef LIBSA_LONGLONG_PRINTF 193 if (lflag > 1) { 194 ull = va_arg(ap, u_int64_t); 195 kprintn64(put, ull, 8, width, padchar); 196 break; 197 } 198 #endif 199 ul = lflag ? 200 va_arg(ap, u_long) : va_arg(ap, u_int); 201 kprintn(put, ul, 8, width, padchar); 202 break; 203 case 'u': 204 #ifdef LIBSA_LONGLONG_PRINTF 205 if (lflag > 1) { 206 ull = va_arg(ap, u_int64_t); 207 kprintn64(put, ull, 10, width, padchar); 208 break; 209 } 210 #endif 211 ul = lflag ? 212 va_arg(ap, u_long) : va_arg(ap, u_int); 213 kprintn(put, ul, 10, width, padchar); 214 break; 215 case 'p': 216 put('0'); 217 put('x'); 218 lflag += sizeof(void *)==sizeof(u_long)? 1 : 0; 219 case 'x': 220 #ifdef LIBSA_LONGLONG_PRINTF 221 if (lflag > 1) { 222 ull = va_arg(ap, u_int64_t); 223 kprintn64(put, ull, 16, width, padchar); 224 break; 225 } 226 #else 227 if (lflag > 1) { 228 /* hold an int64_t in base 16 */ 229 char *p, buf[(sizeof(u_int64_t) * NBBY / 4) + 1]; 230 u_int64_t ull; 231 232 ull = va_arg(ap, u_int64_t); 233 p = buf; 234 do { 235 *p++ = hexdig[ull & 15]; 236 } while (ull >>= 4); 237 while ((p - buf) < width && 238 (p - buf) < sizeof(buf)) { 239 *p++ = padchar; 240 } 241 do { 242 put(*--p); 243 } while (p > buf); 244 break; 245 } 246 #endif 247 ul = lflag ? 248 va_arg(ap, u_long) : va_arg(ap, u_int); 249 kprintn(put, ul, 16, width, padchar); 250 break; 251 default: 252 put('%'); 253 #ifdef LIBSA_LONGLONG_PRINTF 254 while (--lflag) 255 #else 256 if (lflag) 257 #endif 258 put('l'); 259 put(ch); 260 } 261 } 262 } 263 264 void 265 kprintn(void (*put)(int), unsigned long ul, int base, int width, char padchar) 266 { 267 /* hold a long in base 8 */ 268 char *p, buf[(sizeof(long) * NBBY / 3) + 1]; 269 270 p = buf; 271 do { 272 *p++ = hexdig[ul % base]; 273 } while (ul /= base); 274 while ((p - buf) < width && (p - buf) < sizeof(buf)) { 275 *p++ = padchar; 276 } 277 do { 278 put(*--p); 279 } while (p > buf); 280 } 281 282 #ifdef LIBSA_LONGLONG_PRINTF 283 void 284 kprintn64(void (*put)(int), u_int64_t ull, int base, int width, char padchar) 285 { 286 /* hold an int64_t in base 8 */ 287 char *p, buf[(sizeof(u_int64_t) * NBBY / 3) + 1]; 288 289 p = buf; 290 do { 291 *p++ = hexdig[ull % base]; 292 } while (ull /= base); 293 while ((p - buf) < width && (p - buf) < sizeof(buf)) { 294 *p++ = padchar; 295 } 296 do { 297 put(*--p); 298 } while (p > buf); 299 } 300 #endif 301 302 int donottwiddle = 0; 303 304 void 305 twiddle(void) 306 { 307 static int pos; 308 309 if (!donottwiddle) { 310 putchar("|/-\\"[pos++ & 3]); 311 putchar('\b'); 312 } 313 } 314