1 /* $OpenBSD: printf.c,v 1.29 2019/05/11 16:56:47 deraadt 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 case 'b': 136 { 137 int set, n; 138 139 ul = va_arg(ap, int); 140 p = va_arg(ap, char *); 141 kprintn(put, ul, *p++, width, padchar); 142 143 if (!ul) 144 break; 145 146 for (set = 0; (n = *p++);) { 147 if (ul & (1 << (n - 1))) { 148 put(set ? ',' : '<'); 149 for (; (n = *p) > ' '; ++p) 150 put(n); 151 set = 1; 152 } else 153 for (; *p > ' '; ++p) 154 ; 155 } 156 if (set) 157 put('>'); 158 } 159 break; 160 case 'c': 161 ch = va_arg(ap, int); 162 put(ch & 0x7f); 163 break; 164 case 's': 165 p = va_arg(ap, char *); 166 while ((ch = *p++)) 167 put(ch); 168 break; 169 case 'd': 170 #ifdef LIBSA_LONGLONG_PRINTF 171 if (lflag > 1) { 172 ull = va_arg(ap, int64_t); 173 if ((int64_t)ull < 0) { 174 put('-'); 175 ull = -(int64_t)ull; 176 } 177 kprintn64(put, ull, 10, width, padchar); 178 break; 179 } 180 #endif 181 ul = lflag ? 182 va_arg(ap, long) : va_arg(ap, int); 183 if ((long)ul < 0) { 184 put('-'); 185 ul = -(long)ul; 186 } 187 kprintn(put, ul, 10, width, padchar); 188 break; 189 case 'o': 190 #ifdef LIBSA_LONGLONG_PRINTF 191 if (lflag > 1) { 192 ull = va_arg(ap, u_int64_t); 193 kprintn64(put, ull, 8, width, padchar); 194 break; 195 } 196 #endif 197 ul = lflag ? 198 va_arg(ap, u_long) : va_arg(ap, u_int); 199 kprintn(put, ul, 8, width, padchar); 200 break; 201 case 'u': 202 #ifdef LIBSA_LONGLONG_PRINTF 203 if (lflag > 1) { 204 ull = va_arg(ap, u_int64_t); 205 kprintn64(put, ull, 10, width, padchar); 206 break; 207 } 208 #endif 209 ul = lflag ? 210 va_arg(ap, u_long) : va_arg(ap, u_int); 211 kprintn(put, ul, 10, width, padchar); 212 break; 213 case 'p': 214 put('0'); 215 put('x'); 216 lflag += sizeof(void *)==sizeof(u_long)? 1 : 0; 217 case 'x': 218 #ifdef LIBSA_LONGLONG_PRINTF 219 if (lflag > 1) { 220 ull = va_arg(ap, u_int64_t); 221 kprintn64(put, ull, 16, width, padchar); 222 break; 223 } 224 #else 225 if (lflag > 1) { 226 /* hold an int64_t in base 16 */ 227 char *p, buf[(sizeof(u_int64_t) * NBBY / 4) + 1]; 228 u_int64_t ull; 229 230 ull = va_arg(ap, u_int64_t); 231 p = buf; 232 do { 233 *p++ = hexdig[ull & 15]; 234 } while (ull >>= 4); 235 while ((p - buf) < width && 236 (p - buf) < sizeof(buf)) { 237 *p++ = padchar; 238 } 239 do { 240 put(*--p); 241 } while (p > buf); 242 break; 243 } 244 #endif 245 ul = lflag ? 246 va_arg(ap, u_long) : va_arg(ap, u_int); 247 kprintn(put, ul, 16, width, padchar); 248 break; 249 default: 250 put('%'); 251 #ifdef LIBSA_LONGLONG_PRINTF 252 while (--lflag) 253 #else 254 if (lflag) 255 #endif 256 put('l'); 257 put(ch); 258 } 259 } 260 } 261 262 void 263 kprintn(void (*put)(int), unsigned long ul, int base, int width, char padchar) 264 { 265 /* hold a long in base 8 */ 266 char *p, buf[(sizeof(long) * NBBY / 3) + 1]; 267 268 p = buf; 269 do { 270 *p++ = hexdig[ul % base]; 271 } while (ul /= base); 272 while ((p - buf) < width && (p - buf) < sizeof(buf)) { 273 *p++ = padchar; 274 } 275 do { 276 put(*--p); 277 } while (p > buf); 278 } 279 280 #ifdef LIBSA_LONGLONG_PRINTF 281 void 282 kprintn64(void (*put)(int), u_int64_t ull, int base, int width, char padchar) 283 { 284 /* hold an int64_t in base 8 */ 285 char *p, buf[(sizeof(u_int64_t) * NBBY / 3) + 1]; 286 287 p = buf; 288 do { 289 *p++ = hexdig[ull % base]; 290 } while (ull /= base); 291 while ((p - buf) < width && (p - buf) < sizeof(buf)) { 292 *p++ = padchar; 293 } 294 do { 295 put(*--p); 296 } while (p > buf); 297 } 298 #endif 299 300 int donottwiddle = 0; 301 302 void 303 twiddle(void) 304 { 305 static int pos; 306 307 if (!donottwiddle) { 308 putchar("|/-\\"[pos++ & 3]); 309 putchar('\b'); 310 } 311 } 312