1 /* $NetBSD: xprintf.c,v 1.19 2007/11/24 18:32:26 christos 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.19 2007/11/24 18:32:26 christos 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 ? 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 #define ARG() (size & SZ_UNSIGNED ? UARG() : SARG()) 102 103 if (fmt[1] == 'd') { 104 sval = ARG(); 105 if (sval < 0) { 106 if ((sval << 1) == 0) { 107 /* 108 * We can't flip the 109 * sign of this since 110 * it can't be 111 * represented as a 112 * positive number in 113 * two complement, 114 * handle the first 115 * digit. After that, 116 * it can be flipped 117 * since it is now not 118 * 2^(n-1). 119 */ 120 *dp++ = '0'-(sval % 10); 121 sval /= 10; 122 } 123 *bp++ = '-'; 124 uval = -sval; 125 } else { 126 uval = sval; 127 } 128 } else { 129 uval = ARG(); 130 } 131 do { 132 *dp++ = '0' + (uval % 10); 133 uval /= 10; 134 } while (uval != 0); 135 do { 136 *bp++ = *--dp; 137 } while (dp != digits && bp < ep); 138 fmt += 2; 139 break; 140 } 141 case 'x': 142 case 'p':{ 143 unsigned long val = va_arg(ap, unsigned long); 144 unsigned long mask = ~(~0UL >> 4); 145 int bits = sizeof(val) * 8 - 4; 146 const char hexdigits[] = "0123456789abcdef"; 147 if (fmt[1] == 'p') { 148 *bp++ = '0'; 149 *bp++ = 'x'; 150 } 151 /* handle the border case */ 152 if (val == 0) { 153 *bp++ = '0'; 154 fmt += 2; 155 break; 156 } 157 /* suppress 0s */ 158 while ((val & mask) == 0) 159 bits -= 4, mask >>= 4; 160 161 /* emit the hex digits */ 162 while (bits >= 0 && bp < ep) { 163 *bp++ = hexdigits[(val & mask) >> bits]; 164 bits -= 4, mask >>= 4; 165 } 166 fmt += 2; 167 break; 168 } 169 case 's':{ 170 const char *str = va_arg(ap, const char *); 171 int len; 172 173 if (str == NULL) 174 str = "(null)"; 175 176 if (prec < 0) 177 len = strlen(str); 178 else 179 len = prec; 180 if (ep - bp < len) 181 len = ep - bp; 182 memcpy(bp, str, len); 183 bp += len; 184 fmt += 2; 185 break; 186 } 187 case 'c':{ 188 int c = va_arg(ap, int); 189 *bp++ = (char)c; 190 fmt += 2; 191 break; 192 } 193 default: 194 *bp++ = *fmt; 195 break; 196 } 197 break; 198 } 199 default: 200 *bp++ = *fmt++; 201 break; 202 } 203 } 204 205 *bp = '\0'; 206 return bp - buf; 207 } 208 209 void 210 xvprintf(const char *fmt, va_list ap) 211 { 212 char buf[256]; 213 214 (void) write(2, buf, xvsnprintf(buf, sizeof(buf), fmt, ap)); 215 } 216 217 void 218 xprintf(const char *fmt, ...) 219 { 220 va_list ap; 221 222 va_start(ap, fmt); 223 224 xvprintf(fmt, ap); 225 226 va_end(ap); 227 } 228 229 void 230 xsnprintf(char *buf, size_t buflen, const char *fmt, ...) 231 { 232 va_list ap; 233 234 va_start(ap, fmt); 235 236 xvsnprintf(buf, buflen, fmt, ap); 237 238 va_end(ap); 239 } 240 241 const char * 242 xstrerror(int error) 243 { 244 245 if (error >= sys_nerr || error < 0) { 246 static char buf[128]; 247 xsnprintf(buf, sizeof(buf), "Unknown error: %d", error); 248 return buf; 249 } 250 return sys_errlist[error]; 251 } 252 253 void 254 xerrx(int eval, const char *fmt, ...) 255 { 256 va_list ap; 257 258 va_start(ap, fmt); 259 xvprintf(fmt, ap); 260 va_end(ap); 261 (void) write(2, "\n", 1); 262 263 exit(eval); 264 } 265 266 void 267 xerr(int eval, const char *fmt, ...) 268 { 269 int saved_errno = errno; 270 va_list ap; 271 272 va_start(ap, fmt); 273 xvprintf(fmt, ap); 274 va_end(ap); 275 276 xprintf(": %s\n", xstrerror(saved_errno)); 277 exit(eval); 278 } 279 280 void 281 xwarn(const char *fmt, ...) 282 { 283 int saved_errno = errno; 284 va_list ap; 285 286 va_start(ap, fmt); 287 xvprintf(fmt, ap); 288 va_end(ap); 289 290 xprintf(": %s\n", xstrerror(saved_errno)); 291 errno = saved_errno; 292 } 293 294 void 295 xwarnx(const char *fmt, ...) 296 { 297 va_list ap; 298 299 va_start(ap, fmt); 300 xvprintf(fmt, ap); 301 va_end(ap); 302 (void) write(2, "\n", 1); 303 } 304 305 #ifdef DEBUG 306 void 307 xassert(const char *file, int line, const char *failedexpr) 308 { 309 310 xprintf("assertion \"%s\" failed: file \"%s\", line %d\n", 311 failedexpr, file, line); 312 abort(); 313 /* NOTREACHED */ 314 } 315 #endif 316 #endif 317