1 /* $NetBSD: xprintf.c,v 1.16 2004/02/15 02:59:04 enami Exp $ */ 2 3 /* 4 * Copyright 1996 Matt Thomas <matt@3am-software.com> 5 * 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. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 #include <string.h> 32 #include <stdlib.h> 33 #include <unistd.h> 34 #include <errno.h> 35 #include <stdarg.h> 36 37 #include "rtldenv.h" 38 39 #ifdef RTLD_LOADER 40 #define SZ_LONG 0x01 41 #define SZ_UNSIGNED 0x02 42 43 /* 44 * Non-mallocing printf, for use by malloc and rtld itself. 45 * This avoids putting in most of stdio. 46 * 47 * deals withs formats %x, %p, %s, and %d. 48 */ 49 size_t 50 xvsnprintf(char *buf, size_t buflen, const char *fmt, va_list ap) 51 { 52 char *bp = buf; 53 char *const ep = buf + buflen - 4; 54 int size, prec; 55 56 while (*fmt != '\0' && bp < ep) { 57 switch (*fmt) { 58 case '\\':{ 59 if (fmt[1] != '\0') 60 *bp++ = *++fmt; 61 continue; 62 } 63 case '%':{ 64 size = 0; 65 prec = -1; 66 rflag: switch (fmt[1]) { 67 case '*': 68 prec = va_arg(ap, int); 69 /* FALLTHROUGH */ 70 case '.': 71 fmt++; 72 goto rflag; 73 case 'l': 74 size |= SZ_LONG; 75 fmt++; 76 goto rflag; 77 case 'u': 78 size |= SZ_UNSIGNED; 79 /* FALLTHROUGH */ 80 case 'd':{ 81 long sval; 82 unsigned long uval; 83 char digits[sizeof(int) * 3], *dp = digits; 84 #define SARG() \ 85 (size & SZ_LONG ? va_arg(ap, long) : \ 86 va_arg(ap, int)) 87 #define UARG() \ 88 (size & SZ_LONG ? va_arg(ap, unsigned long) : \ 89 va_arg(ap, unsigned int)) 90 #define ARG() (size & SZ_UNSIGNED ? UARG() : SARG()) 91 92 if (fmt[1] == 'd') { 93 sval = ARG(); 94 if (sval < 0) { 95 if ((sval << 1) == 0) { 96 /* 97 * We can't flip the 98 * sign of this since 99 * it can't be 100 * represented as a 101 * positive number in 102 * two complement, 103 * handle the first 104 * digit. After that, 105 * it can be flipped 106 * since it is now not 107 * 2^(n-1). 108 */ 109 *dp++ = '0'-(sval % 10); 110 sval /= 10; 111 } 112 *bp++ = '-'; 113 uval = -sval; 114 } else { 115 uval = sval; 116 } 117 } else { 118 uval = ARG(); 119 } 120 do { 121 *dp++ = '0' + (uval % 10); 122 uval /= 10; 123 } while (uval != 0); 124 do { 125 *bp++ = *--dp; 126 } while (dp != digits && bp < ep); 127 fmt += 2; 128 break; 129 } 130 case 'x': 131 case 'p':{ 132 unsigned long val = va_arg(ap, unsigned long); 133 unsigned long mask = ~(~0UL >> 4); 134 int bits = sizeof(val) * 8 - 4; 135 const char hexdigits[] = "0123456789abcdef"; 136 if (fmt[1] == 'p') { 137 *bp++ = '0'; 138 *bp++ = 'x'; 139 } 140 /* handle the border case */ 141 if (val == 0) { 142 *bp++ = '0'; 143 fmt += 2; 144 break; 145 } 146 /* suppress 0s */ 147 while ((val & mask) == 0) 148 bits -= 4, mask >>= 4; 149 150 /* emit the hex digits */ 151 while (bits >= 0 && bp < ep) { 152 *bp++ = hexdigits[(val & mask) >> bits]; 153 bits -= 4, mask >>= 4; 154 } 155 fmt += 2; 156 break; 157 } 158 case 's':{ 159 const char *str = va_arg(ap, const char *); 160 int len; 161 162 if (str == NULL) 163 str = "(null)"; 164 165 if (prec < 0) 166 len = strlen(str); 167 else 168 len = prec; 169 if (ep - bp < len) 170 len = ep - bp; 171 memcpy(bp, str, len); 172 bp += len; 173 fmt += 2; 174 break; 175 } 176 default: 177 *bp++ = *fmt; 178 break; 179 } 180 break; 181 } 182 default: 183 *bp++ = *fmt++; 184 break; 185 } 186 } 187 188 *bp = '\0'; 189 return bp - buf; 190 } 191 192 void 193 xvprintf(const char *fmt, va_list ap) 194 { 195 char buf[256]; 196 197 (void) write(2, buf, xvsnprintf(buf, sizeof(buf), fmt, ap)); 198 } 199 200 void 201 xprintf(const char *fmt, ...) 202 { 203 va_list ap; 204 205 va_start(ap, fmt); 206 207 xvprintf(fmt, ap); 208 209 va_end(ap); 210 } 211 212 void 213 xsnprintf(char *buf, size_t buflen, const char *fmt, ...) 214 { 215 va_list ap; 216 217 va_start(ap, fmt); 218 219 xvsnprintf(buf, buflen, fmt, ap); 220 221 va_end(ap); 222 } 223 224 const char * 225 xstrerror(int error) 226 { 227 228 if (error >= sys_nerr || error < 0) { 229 static char buf[128]; 230 xsnprintf(buf, sizeof(buf), "Unknown error: %d", error); 231 return buf; 232 } 233 return sys_errlist[error]; 234 } 235 236 void 237 xerrx(int eval, const char *fmt, ...) 238 { 239 va_list ap; 240 241 va_start(ap, fmt); 242 xvprintf(fmt, ap); 243 va_end(ap); 244 (void) write(2, "\n", 1); 245 246 exit(eval); 247 } 248 249 void 250 xerr(int eval, const char *fmt, ...) 251 { 252 int saved_errno = errno; 253 va_list ap; 254 255 va_start(ap, fmt); 256 xvprintf(fmt, ap); 257 va_end(ap); 258 259 xprintf(": %s\n", xstrerror(saved_errno)); 260 exit(eval); 261 } 262 263 void 264 xwarn(const char *fmt, ...) 265 { 266 int saved_errno = errno; 267 va_list ap; 268 269 va_start(ap, fmt); 270 xvprintf(fmt, ap); 271 va_end(ap); 272 273 xprintf(": %s\n", xstrerror(saved_errno)); 274 errno = saved_errno; 275 } 276 277 void 278 xwarnx(const char *fmt, ...) 279 { 280 va_list ap; 281 282 va_start(ap, fmt); 283 xvprintf(fmt, ap); 284 va_end(ap); 285 (void) write(2, "\n", 1); 286 } 287 288 #ifdef DEBUG 289 void 290 xassert(const char *file, int line, const char *failedexpr) 291 { 292 293 xprintf("assertion \"%s\" failed: file \"%s\", line %d\n", 294 failedexpr, file, line); 295 abort(); 296 /* NOTREACHED */ 297 } 298 #endif 299 #endif 300