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