1 /* $NetBSD: xprintf.c,v 1.18 2005/04/24 21:11:58 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.18 2005/04/24 21:11:58 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 47 /* 48 * Non-mallocing printf, for use by malloc and rtld itself. 49 * This avoids putting in most of stdio. 50 * 51 * deals withs formats %x, %p, %s, and %d. 52 */ 53 size_t 54 xvsnprintf(char *buf, size_t buflen, const char *fmt, va_list ap) 55 { 56 char *bp = buf; 57 char *const ep = buf + buflen - 4; 58 int size, prec; 59 60 while (*fmt != '\0' && bp < ep) { 61 switch (*fmt) { 62 case '\\':{ 63 if (fmt[1] != '\0') 64 *bp++ = *++fmt; 65 continue; 66 } 67 case '%':{ 68 size = 0; 69 prec = -1; 70 rflag: switch (fmt[1]) { 71 case '*': 72 prec = va_arg(ap, int); 73 /* FALLTHROUGH */ 74 case '.': 75 fmt++; 76 goto rflag; 77 case 'l': 78 size |= SZ_LONG; 79 fmt++; 80 goto rflag; 81 case 'u': 82 size |= SZ_UNSIGNED; 83 /* FALLTHROUGH */ 84 case 'd':{ 85 long sval; 86 unsigned long uval; 87 char digits[sizeof(int) * 3], *dp = digits; 88 #define SARG() \ 89 (size & SZ_LONG ? va_arg(ap, long) : \ 90 va_arg(ap, int)) 91 #define UARG() \ 92 (size & SZ_LONG ? va_arg(ap, unsigned long) : \ 93 va_arg(ap, unsigned int)) 94 #define ARG() (size & SZ_UNSIGNED ? UARG() : SARG()) 95 96 if (fmt[1] == 'd') { 97 sval = ARG(); 98 if (sval < 0) { 99 if ((sval << 1) == 0) { 100 /* 101 * We can't flip the 102 * sign of this since 103 * it can't be 104 * represented as a 105 * positive number in 106 * two complement, 107 * handle the first 108 * digit. After that, 109 * it can be flipped 110 * since it is now not 111 * 2^(n-1). 112 */ 113 *dp++ = '0'-(sval % 10); 114 sval /= 10; 115 } 116 *bp++ = '-'; 117 uval = -sval; 118 } else { 119 uval = sval; 120 } 121 } else { 122 uval = ARG(); 123 } 124 do { 125 *dp++ = '0' + (uval % 10); 126 uval /= 10; 127 } while (uval != 0); 128 do { 129 *bp++ = *--dp; 130 } while (dp != digits && bp < ep); 131 fmt += 2; 132 break; 133 } 134 case 'x': 135 case 'p':{ 136 unsigned long val = va_arg(ap, unsigned long); 137 unsigned long mask = ~(~0UL >> 4); 138 int bits = sizeof(val) * 8 - 4; 139 const char hexdigits[] = "0123456789abcdef"; 140 if (fmt[1] == 'p') { 141 *bp++ = '0'; 142 *bp++ = 'x'; 143 } 144 /* handle the border case */ 145 if (val == 0) { 146 *bp++ = '0'; 147 fmt += 2; 148 break; 149 } 150 /* suppress 0s */ 151 while ((val & mask) == 0) 152 bits -= 4, mask >>= 4; 153 154 /* emit the hex digits */ 155 while (bits >= 0 && bp < ep) { 156 *bp++ = hexdigits[(val & mask) >> bits]; 157 bits -= 4, mask >>= 4; 158 } 159 fmt += 2; 160 break; 161 } 162 case 's':{ 163 const char *str = va_arg(ap, const char *); 164 int len; 165 166 if (str == NULL) 167 str = "(null)"; 168 169 if (prec < 0) 170 len = strlen(str); 171 else 172 len = prec; 173 if (ep - bp < len) 174 len = ep - bp; 175 memcpy(bp, str, len); 176 bp += len; 177 fmt += 2; 178 break; 179 } 180 case 'c':{ 181 int c = va_arg(ap, int); 182 *bp++ = (char)c; 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(const char *fmt, va_list ap) 204 { 205 char buf[256]; 206 207 (void) write(2, buf, xvsnprintf(buf, sizeof(buf), fmt, ap)); 208 } 209 210 void 211 xprintf(const char *fmt, ...) 212 { 213 va_list ap; 214 215 va_start(ap, fmt); 216 217 xvprintf(fmt, ap); 218 219 va_end(ap); 220 } 221 222 void 223 xsnprintf(char *buf, size_t buflen, const char *fmt, ...) 224 { 225 va_list ap; 226 227 va_start(ap, fmt); 228 229 xvsnprintf(buf, buflen, fmt, ap); 230 231 va_end(ap); 232 } 233 234 const char * 235 xstrerror(int error) 236 { 237 238 if (error >= sys_nerr || error < 0) { 239 static char buf[128]; 240 xsnprintf(buf, sizeof(buf), "Unknown error: %d", error); 241 return buf; 242 } 243 return sys_errlist[error]; 244 } 245 246 void 247 xerrx(int eval, const char *fmt, ...) 248 { 249 va_list ap; 250 251 va_start(ap, fmt); 252 xvprintf(fmt, ap); 253 va_end(ap); 254 (void) write(2, "\n", 1); 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 va_end(ap); 295 (void) write(2, "\n", 1); 296 } 297 298 #ifdef DEBUG 299 void 300 xassert(const char *file, int line, const char *failedexpr) 301 { 302 303 xprintf("assertion \"%s\" failed: file \"%s\", line %d\n", 304 failedexpr, file, line); 305 abort(); 306 /* NOTREACHED */ 307 } 308 #endif 309 #endif 310