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