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