1 /* $NetBSD: xprintf.c,v 1.21 2010/12/16 22:52:32 joerg 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 #ifndef lint 32 __RCSID("$NetBSD: xprintf.c,v 1.21 2010/12/16 22:52:32 joerg Exp $"); 33 #endif /* not lint */ 34 35 #include <string.h> 36 #include <stdlib.h> 37 #include <unistd.h> 38 #include <errno.h> 39 #include <stdarg.h> 40 41 #include "rtldenv.h" 42 43 #ifdef RTLD_LOADER 44 #define SZ_LONG 0x01 45 #define SZ_UNSIGNED 0x02 46 #define SZ_SIZE_T 0x04 47 48 /* 49 * Non-mallocing printf, for use by malloc and rtld itself. 50 * This avoids putting in most of stdio. 51 * 52 * deals withs formats %x, %p, %s, and %d. 53 */ 54 size_t 55 xvsnprintf(char *buf, size_t buflen, const char *fmt, va_list ap) 56 { 57 char *bp = buf; 58 char *const ep = buf + buflen - 4; 59 int size, prec; 60 61 while (*fmt != '\0' && bp < ep) { 62 switch (*fmt) { 63 case '\\':{ 64 if (fmt[1] != '\0') 65 *bp++ = *++fmt; 66 continue; 67 } 68 case '%':{ 69 size = 0; 70 prec = -1; 71 rflag: switch (fmt[1]) { 72 case '*': 73 prec = va_arg(ap, int); 74 /* FALLTHROUGH */ 75 case '.': 76 fmt++; 77 goto rflag; 78 case 'l': 79 size |= SZ_LONG; 80 fmt++; 81 goto rflag; 82 case 'z': 83 size |= SZ_SIZE_T; 84 fmt++; 85 goto rflag; 86 case 'u': 87 size |= SZ_UNSIGNED; 88 /* FALLTHROUGH */ 89 case 'd':{ 90 long sval; 91 unsigned long uval; 92 char digits[sizeof(int) * 3], *dp = digits; 93 #define SARG() \ 94 (size & SZ_LONG ? va_arg(ap, long) : \ 95 ((size & SZ_SIZE_T ? (long)va_arg(ap, size_t) : \ 96 va_arg(ap, int)))) 97 #define UARG() \ 98 (size & SZ_LONG ? va_arg(ap, unsigned long) : \ 99 ((size & SZ_SIZE_T ? va_arg(ap, size_t) : \ 100 va_arg(ap, unsigned int)))) 101 102 if (fmt[1] == 'd') { 103 if (size & SZ_UNSIGNED) 104 sval = UARG(); 105 else 106 sval = SARG(); 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 if (size & SZ_UNSIGNED) 132 uval = UARG(); 133 else 134 uval = SARG(); 135 } 136 do { 137 *dp++ = '0' + (uval % 10); 138 uval /= 10; 139 } while (uval != 0); 140 do { 141 *bp++ = *--dp; 142 } while (dp != digits && bp < ep); 143 fmt += 2; 144 break; 145 } 146 case 'x': 147 case 'p':{ 148 unsigned long val = va_arg(ap, unsigned long); 149 unsigned long mask = ~(~0UL >> 4); 150 int bits = sizeof(val) * 8 - 4; 151 const char hexdigits[] = "0123456789abcdef"; 152 if (fmt[1] == 'p') { 153 *bp++ = '0'; 154 *bp++ = 'x'; 155 } 156 /* handle the border case */ 157 if (val == 0) { 158 *bp++ = '0'; 159 fmt += 2; 160 break; 161 } 162 /* suppress 0s */ 163 while ((val & mask) == 0) 164 bits -= 4, mask >>= 4; 165 166 /* emit the hex digits */ 167 while (bits >= 0 && bp < ep) { 168 *bp++ = hexdigits[(val & mask) >> bits]; 169 bits -= 4, mask >>= 4; 170 } 171 fmt += 2; 172 break; 173 } 174 case 's':{ 175 const char *str = va_arg(ap, const char *); 176 int len; 177 178 if (str == NULL) 179 str = "(null)"; 180 181 if (prec < 0) 182 len = strlen(str); 183 else 184 len = prec; 185 if (ep - bp < len) 186 len = ep - bp; 187 memcpy(bp, str, len); 188 bp += len; 189 fmt += 2; 190 break; 191 } 192 case 'c':{ 193 int c = va_arg(ap, int); 194 *bp++ = (char)c; 195 fmt += 2; 196 break; 197 } 198 default: 199 *bp++ = *fmt; 200 break; 201 } 202 break; 203 } 204 default: 205 *bp++ = *fmt++; 206 break; 207 } 208 } 209 210 *bp = '\0'; 211 return bp - buf; 212 } 213 214 void 215 xvprintf(const char *fmt, va_list ap) 216 { 217 char buf[256]; 218 219 (void) write(2, buf, xvsnprintf(buf, sizeof(buf), fmt, ap)); 220 } 221 222 void 223 xprintf(const char *fmt, ...) 224 { 225 va_list ap; 226 227 va_start(ap, fmt); 228 229 xvprintf(fmt, ap); 230 231 va_end(ap); 232 } 233 234 void 235 xsnprintf(char *buf, size_t buflen, const char *fmt, ...) 236 { 237 va_list ap; 238 239 va_start(ap, fmt); 240 241 xvsnprintf(buf, buflen, fmt, ap); 242 243 va_end(ap); 244 } 245 246 #include "errlist_concat.h" 247 248 const char * 249 xstrerror(int error) 250 { 251 252 if (error >= concat_nerr || error < 0) { 253 static char buf[128]; 254 xsnprintf(buf, sizeof(buf), "Unknown error: %d", error); 255 return buf; 256 } 257 return concat_errlist + concat_offset[error]; 258 } 259 260 void 261 xerrx(int eval, const char *fmt, ...) 262 { 263 va_list ap; 264 265 va_start(ap, fmt); 266 xvprintf(fmt, ap); 267 va_end(ap); 268 (void) write(2, "\n", 1); 269 270 exit(eval); 271 } 272 273 void 274 xerr(int eval, 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 exit(eval); 285 } 286 287 void 288 xwarn(const char *fmt, ...) 289 { 290 int saved_errno = errno; 291 va_list ap; 292 293 va_start(ap, fmt); 294 xvprintf(fmt, ap); 295 va_end(ap); 296 297 xprintf(": %s\n", xstrerror(saved_errno)); 298 errno = saved_errno; 299 } 300 301 void 302 xwarnx(const char *fmt, ...) 303 { 304 va_list ap; 305 306 va_start(ap, fmt); 307 xvprintf(fmt, ap); 308 va_end(ap); 309 (void) write(2, "\n", 1); 310 } 311 312 #ifdef DEBUG 313 void 314 xassert(const char *file, int line, const char *failedexpr) 315 { 316 317 xprintf("assertion \"%s\" failed: file \"%s\", line %d\n", 318 failedexpr, file, line); 319 abort(); 320 /* NOTREACHED */ 321 } 322 #endif 323 #endif 324