1 /* $NetBSD: xprintf.c,v 1.7 2000/07/03 03:32:57 matt 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 "rtldenv.h" 32 #include <string.h> 33 #include <stdlib.h> 34 #include <unistd.h> 35 #include <errno.h> 36 #ifdef __STDC__ 37 #include <stdarg.h> 38 #else 39 #include <varargs.h> 40 #endif 41 42 #ifdef RTLD_LOADER 43 #define SZ_SHORT 0x01 44 #define SZ_INT 0x02 45 #define SZ_LONG 0x04 46 #define SZ_QUAD 0x08 47 #define SZ_UNSIGNED 0x10 48 #define SZ_MASK 0x0f 49 50 /* 51 * Non-mallocing printf, for use by malloc and rtld itself. 52 * This avoids putting in most of stdio. 53 * 54 * deals withs formats %x, %p, %s, and %d. 55 */ 56 size_t 57 xvsnprintf(buf, buflen, fmt, ap) 58 char *buf; 59 size_t buflen; 60 const char *fmt; 61 va_list ap; 62 { 63 char *bp = buf; 64 char *const ep = buf + buflen - 4; 65 int size; 66 67 while (*fmt != NULL && bp < ep) { 68 switch (*fmt) { 69 case '\\':{ 70 if (fmt[1] != '\0') 71 *bp++ = *++fmt; 72 continue; 73 } 74 case '%':{ 75 size = SZ_INT; 76 rflag: switch (fmt[1]) { 77 case 'h': 78 size = (size&SZ_MASK)|SZ_SHORT; 79 fmt++; 80 goto rflag; 81 case 'l': 82 size = (size&SZ_MASK)|SZ_LONG; 83 fmt++; 84 if (fmt[1] == 'l') { 85 case 'q': 86 size = (size&SZ_MASK)|SZ_QUAD; 87 fmt++; 88 } 89 goto rflag; 90 case 'u': 91 size |= SZ_UNSIGNED; 92 /* FALLTHROUGH */ 93 case 'd':{ 94 long long sval; 95 unsigned long long uval; 96 char digits[sizeof(int) * 3], *dp = digits; 97 #define SARG() \ 98 (size & SZ_SHORT ? (short) va_arg(ap, int) : \ 99 size & SZ_LONG ? va_arg(ap, long) : \ 100 size & SZ_QUAD ? va_arg(ap, long long) : \ 101 va_arg(ap, int)) 102 #define UARG() \ 103 (size & SZ_SHORT ? (unsigned short) va_arg(ap, unsigned int) : \ 104 size & SZ_LONG ? va_arg(ap, unsigned long) : \ 105 size & SZ_QUAD ? va_arg(ap, unsigned long long) : \ 106 va_arg(ap, unsigned int)) 107 #define ARG() (size & SZ_UNSIGNED ? UARG() : SARG()) 108 109 if (fmt[1] == 'd') { 110 sval = ARG(); 111 if (sval < 0) { 112 if ((sval << 1) == 0) { 113 /* 114 * We can't flip the 115 * sign of this since 116 * it can't be 117 * represented as a 118 * positive number in 119 * two complement, 120 * handle the first 121 * digit. After that, 122 * it can be flipped 123 * since it is now not 124 * 2^(n-1). 125 */ 126 *dp++ = '0'-(sval % 10); 127 sval /= 10; 128 } 129 *bp++ = '-'; 130 uval = -sval; 131 } else { 132 uval = sval; 133 } 134 } else { 135 uval = ARG(); 136 } 137 do { 138 *dp++ = '0' + (uval % 10); 139 uval /= 10; 140 } while (uval != 0); 141 do { 142 *bp++ = *--dp; 143 } while (dp != digits && bp < ep); 144 fmt += 2; 145 break; 146 } 147 case 'x': 148 case 'p':{ 149 unsigned long val = va_arg(ap, unsigned long); 150 unsigned long mask = ~(~0UL >> 4); 151 int bits = sizeof(val) * 8 - 4; 152 const char hexdigits[] = "0123456789abcdef"; 153 if (fmt[1] == 'p') { 154 *bp++ = '0'; 155 *bp++ = 'x'; 156 } 157 /* handle the border case */ 158 if (val == 0) { 159 *bp++ = '0'; 160 fmt += 2; 161 break; 162 } 163 /* suppress 0s */ 164 while ((val & mask) == 0) 165 bits -= 4, mask >>= 4; 166 167 /* emit the hex digits */ 168 while (bits >= 0 && bp < ep) { 169 *bp++ = hexdigits[(val & mask) >> bits]; 170 bits -= 4, mask >>= 4; 171 } 172 fmt += 2; 173 break; 174 } 175 case 's':{ 176 const char *str = va_arg(ap, const char *); 177 int len; 178 179 if (str == NULL) 180 str = "(null)"; 181 182 len = strlen(str); 183 if (ep - bp < len) 184 len = ep - bp; 185 memcpy(bp, str, len); 186 bp += len; 187 fmt += 2; 188 break; 189 } 190 default: 191 *bp++ = *fmt; 192 break; 193 } 194 break; 195 } 196 default: 197 *bp++ = *fmt++; 198 break; 199 } 200 } 201 202 *bp = '\0'; 203 return bp - buf; 204 } 205 206 void 207 xvprintf(fmt, ap) 208 const char *fmt; 209 va_list ap; 210 { 211 char buf[256]; 212 (void) write(2, buf, xvsnprintf(buf, sizeof(buf), fmt, ap)); 213 } 214 215 void 216 #ifdef __STDC__ 217 xprintf(const char *fmt, ...) 218 #else 219 xprintf(va_alist) 220 va_dcl 221 #endif 222 { 223 va_list ap; 224 225 #ifdef __STDC__ 226 va_start(ap, fmt); 227 #else 228 const char *fmt; 229 230 va_start(ap); 231 fmt = va_arg(ap, const char *); 232 #endif 233 234 xvprintf(fmt, ap); 235 236 va_end(ap); 237 } 238 239 void 240 #ifdef __STDC__ 241 xsnprintf(char *buf, size_t buflen, const char *fmt, ...) 242 #else 243 xsnprintf(va_alist) 244 va_dcl 245 #endif 246 { 247 va_list ap; 248 #ifdef __STDC__ 249 va_start(ap, fmt); 250 #else 251 char *buf; 252 size_t buflen; 253 const char *fmt; 254 255 va_start(ap); 256 buf = va_arg(ap, char *); 257 buflen = va_arg(ap, size_t); 258 fmt = va_arg(ap, const char *); 259 #endif 260 xvsnprintf(buf, buflen, fmt, ap); 261 262 va_end(ap); 263 } 264 265 const char * 266 xstrerror(error) 267 int error; 268 { 269 if (error >= sys_nerr || error < 0) { 270 static char buf[128]; 271 xsnprintf(buf, sizeof(buf), "Unknown error: %d", error); 272 return buf; 273 } 274 return sys_errlist[error]; 275 } 276 277 void 278 #ifdef __STDC__ 279 xerrx(int eval, const char *fmt, ...) 280 #else 281 xerrx(va_alist) 282 va_dcl 283 #endif 284 { 285 va_list ap; 286 #ifdef __STDC__ 287 va_start(ap, fmt); 288 #else 289 int eval; 290 const char *fmt; 291 292 va_start(ap); 293 eval = va_arg(ap, int); 294 fmt = va_arg(ap, const char *); 295 #endif 296 297 xvprintf(fmt, ap); 298 va_end(ap); 299 300 exit(eval); 301 } 302 303 void 304 #ifdef __STDC__ 305 xerr(int eval, const char *fmt, ...) 306 #else 307 xerr(va_alist) 308 va_dcl 309 #endif 310 { 311 int saved_errno = errno; 312 va_list ap; 313 #ifdef __STDC__ 314 va_start(ap, fmt); 315 #else 316 int eval; 317 const char *fmt; 318 319 va_start(ap); 320 eval = va_arg(ap, int); 321 fmt = va_arg(ap, const char *); 322 #endif 323 xvprintf(fmt, ap); 324 va_end(ap); 325 326 xprintf(": %s\n", xstrerror(saved_errno)); 327 exit(eval); 328 } 329 330 void 331 #ifdef __STDC__ 332 xwarn(const char *fmt, ...) 333 #else 334 xwarn(va_alist) 335 va_dcl 336 #endif 337 { 338 int saved_errno = errno; 339 va_list ap; 340 #ifdef __STDC__ 341 va_start(ap, fmt); 342 #else 343 const char *fmt; 344 345 va_start(ap); 346 fmt = va_arg(ap, const char *); 347 #endif 348 xvprintf(fmt, ap); 349 va_end(ap); 350 351 xprintf(": %s\n", xstrerror(saved_errno)); 352 errno = saved_errno; 353 } 354 355 void 356 #ifdef __STDC__ 357 xwarnx(const char *fmt, ...) 358 #else 359 xwarnx(va_alist) 360 va_dcl 361 #endif 362 { 363 va_list ap; 364 #ifdef __STDC__ 365 va_start(ap, fmt); 366 #else 367 const char *fmt; 368 369 va_start(ap); 370 fmt = va_arg(ap, const char *); 371 #endif 372 xvprintf(fmt, ap); 373 (void) write(2, "\n", 1); 374 va_end(ap); 375 } 376 377 void 378 xassert(file, line, failedexpr) 379 const char *file; 380 int line; 381 const char *failedexpr; 382 { 383 xprintf("assertion \"%s\" failed: file \"%s\", line %d\n", 384 failedexpr, file, line); 385 abort(); 386 /* NOTREACHED */ 387 } 388 #endif 389