1 /* $NetBSD: subr_prf.c,v 1.27 2014/08/30 14:24:02 tsutsui Exp $ */ 2 3 /*- 4 * Copyright (c) 1993 5 * The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * @(#)printf.c 8.1 (Berkeley) 6/11/93 32 */ 33 34 /* 35 * Scaled down version of printf(3). 36 */ 37 38 #include <sys/cdefs.h> 39 #include <sys/types.h> 40 #include <sys/stdint.h> /* XXX: for intptr_t */ 41 42 #include "stand.h" 43 44 #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT 45 #define INTMAX_T longlong_t 46 #define UINTMAX_T u_longlong_t 47 #else 48 #define INTMAX_T long 49 #define UINTMAX_T u_long 50 #endif 51 52 #if 0 /* XXX: abuse intptr_t until the situation with ptrdiff_t is clear */ 53 #define PTRDIFF_T ptrdiff_t 54 #else 55 #define PTRDIFF_T intptr_t 56 #endif 57 58 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 59 static void kprintn(void (*)(int), UINTMAX_T, int, int, int); 60 #else 61 static void kprintn(void (*)(int), UINTMAX_T, int); 62 #endif 63 static void sputchar(int); 64 static void kdoprnt(void (*)(int), const char *, va_list); 65 66 static char *sbuf, *ebuf; 67 #if defined(__minix) 68 /* vsnprintf: add support for returning the amount of characters that would have been 69 * written if the buffer was large enough */ 70 static int scount; 71 #endif /* defined(__minix) */ 72 73 const char hexdigits[16] = "0123456789abcdef"; 74 75 #define LONG 0x01 76 #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT 77 #define LLONG 0x02 78 #endif 79 80 #if defined(__minix) 81 #define HEXCAP 0x100 82 #endif /* defined(__minix) */ 83 84 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 85 #define ALT 0x04 86 #define SPACE 0x08 87 #define LADJUST 0x10 88 #define SIGN 0x20 89 #define ZEROPAD 0x40 90 #define NEGATIVE 0x80 91 #define KPRINTN(base) kprintn(put, ul, base, lflag, width) 92 #define RADJUSTZEROPAD() \ 93 do { \ 94 if ((lflag & (ZEROPAD|LADJUST)) == ZEROPAD) { \ 95 while (width-- > 0) \ 96 put('0'); \ 97 } \ 98 } while (/*CONSTCOND*/0) 99 #define LADJUSTPAD() \ 100 do { \ 101 if (lflag & LADJUST) { \ 102 while (width-- > 0) \ 103 put(' '); \ 104 } \ 105 } while (/*CONSTCOND*/0) 106 #define RADJUSTPAD() \ 107 do { \ 108 if ((lflag & (ZEROPAD|LADJUST)) == 0) { \ 109 while (width-- > 0) \ 110 put(' '); \ 111 } \ 112 } while (/*CONSTCOND*/0) 113 #else /* LIBSA_PRINTF_WIDTH_SUPPORT */ 114 #define KPRINTN(base) kprintn(put, ul, base) 115 #define RADJUSTZEROPAD() /**/ 116 #define LADJUSTPAD() /**/ 117 #define RADJUSTPAD() /**/ 118 #endif /* LIBSA_PRINTF_WIDTH_SUPPORT */ 119 120 #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT 121 #define KPRINT(base) \ 122 do { \ 123 ul = (lflag & LLONG) \ 124 ? va_arg(ap, u_longlong_t) \ 125 : (lflag & LONG) \ 126 ? va_arg(ap, u_long) \ 127 : va_arg(ap, u_int); \ 128 KPRINTN(base); \ 129 } while (/*CONSTCOND*/0) 130 #else /* LIBSA_PRINTF_LONGLONG_SUPPORT */ 131 #define KPRINT(base) \ 132 do { \ 133 ul = (lflag & LONG) \ 134 ? va_arg(ap, u_long) : va_arg(ap, u_int); \ 135 KPRINTN(base); \ 136 } while (/*CONSTCOND*/0) 137 #endif /* LIBSA_PRINTF_LONGLONG_SUPPORT */ 138 139 static void 140 sputchar(int c) 141 { 142 #if defined(__minix) 143 scount++; /* increase scount regardless */ 144 if (!sbuf) return; /* hanlde NULL sbuf */ 145 #endif /* defined(__minix) */ 146 147 if (sbuf < ebuf) 148 *sbuf++ = c; 149 } 150 151 void 152 vprintf(const char *fmt, va_list ap) 153 { 154 155 kdoprnt(putchar, fmt, ap); 156 #if defined(__minix) && defined(LIBSA_PRINTF_WIDTH_SUPPORT) 157 /* BJG: our libminc kputc() relies on a 0 to flush the diag buffer. */ 158 putchar(0); 159 #endif /* defined(__minix) && defined(LIBSA_PRINTF_WIDTH_SUPPORT) */ 160 } 161 162 int 163 vsnprintf(char *buf, size_t size, const char *fmt, va_list ap) 164 { 165 166 sbuf = buf; 167 ebuf = buf + size - 1; 168 #if defined(__minix) 169 scount = 0; /* use scount to keep track of written items */ 170 #endif /* defined(__minix) */ 171 172 kdoprnt(sputchar, fmt, ap); 173 174 #if defined(__minix) 175 if (sbuf){ /* handle case where sbuf == NULL */ 176 *sbuf = '\0'; 177 } 178 #if defined(_MINIX_MAGIC) 179 sbuf = ebuf = NULL; /* leave no dangling pointers */ 180 #endif 181 return scount; 182 #else /* __minix is not defined */ 183 *sbuf = '\0'; 184 return sbuf - buf; 185 #endif /* defined(__minix) */ 186 } 187 188 static void 189 kdoprnt(void (*put)(int), const char *fmt, va_list ap) 190 { 191 char *p; 192 int ch; 193 UINTMAX_T ul; 194 int lflag; 195 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 196 int width; 197 char *q; 198 #if defined(__minix) 199 int max; 200 #endif /* defined(__minix) */ 201 #endif 202 203 for (;;) { 204 while ((ch = *fmt++) != '%') { 205 if (ch == '\0') 206 return; 207 put(ch); 208 } 209 lflag = 0; 210 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 211 width = 0; 212 #if defined(__minix) 213 max = -1; 214 #endif /* defined(__minix) */ 215 #endif 216 reswitch: 217 switch (ch = *fmt++) { 218 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 219 #if defined(__minix) 220 case '.': 221 if (*fmt == '*') { 222 max = va_arg(ap, int); 223 fmt++; 224 } else for (max = 0; *fmt >= '0' && *fmt <= '9'; fmt++) 225 max = max * 10 + *fmt - '0'; 226 goto reswitch; 227 #endif /* defined(__minix) */ 228 case '#': 229 lflag |= ALT; 230 goto reswitch; 231 case ' ': 232 lflag |= SPACE; 233 goto reswitch; 234 case '-': 235 lflag |= LADJUST; 236 goto reswitch; 237 case '+': 238 lflag |= SIGN; 239 goto reswitch; 240 case '0': 241 lflag |= ZEROPAD; 242 goto reswitch; 243 case '1': case '2': case '3': case '4': case '5': 244 case '6': case '7': case '8': case '9': 245 for (;;) { 246 width *= 10; 247 width += ch - '0'; 248 ch = *fmt; 249 if ((unsigned)ch - '0' > 9) 250 break; 251 ++fmt; 252 } 253 #endif 254 goto reswitch; 255 case 'l': 256 #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT 257 if (*fmt == 'l') { 258 ++fmt; 259 lflag |= LLONG; 260 } else 261 #endif 262 lflag |= LONG; 263 goto reswitch; 264 case 'j': 265 #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT 266 if (sizeof(intmax_t) == sizeof(long long)) 267 lflag |= LLONG; 268 else 269 #endif 270 if (sizeof(intmax_t) == sizeof(long)) 271 lflag |= LONG; 272 goto reswitch; 273 case 't': 274 if (sizeof(PTRDIFF_T) == sizeof(long)) 275 lflag |= LONG; 276 goto reswitch; 277 case 'z': 278 if (sizeof(ssize_t) == sizeof(long)) 279 lflag |= LONG; 280 goto reswitch; 281 case 'c': 282 ch = va_arg(ap, int); 283 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 284 --width; 285 #endif 286 RADJUSTPAD(); 287 put(ch & 0xFF); 288 LADJUSTPAD(); 289 break; 290 case 's': 291 p = va_arg(ap, char *); 292 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 293 for (q = p; *q != '\0'; ++q) 294 continue; 295 #if defined(__minix) 296 if (max >= 0 && q - p > max) 297 q = &p[max]; 298 #endif /* defined(__minix) */ 299 width -= q - p; 300 #endif 301 RADJUSTPAD(); 302 #if defined(LIBSA_PRINTF_WIDTH_SUPPORT) && defined(__minix) 303 while ((max < 0 || max-- > 0) && 304 (ch = (unsigned char)*p++)) 305 #else /* !defined(LIBSA_PRINTF_WIDTH_SUPPORT) || !defined(__minix) */ 306 while ((ch = (unsigned char)*p++)) 307 #endif /* !defined(LIBSA_PRINTF_WIDTH_SUPPORT) || !defined(__minix) */ 308 put(ch); 309 LADJUSTPAD(); 310 break; 311 case 'd': 312 ul = 313 #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT 314 (lflag & LLONG) ? va_arg(ap, longlong_t) : 315 #endif 316 (lflag & LONG) ? va_arg(ap, long) : va_arg(ap, int); 317 if ((INTMAX_T)ul < 0) { 318 ul = -(INTMAX_T)ul; 319 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 320 lflag |= NEGATIVE; 321 #else 322 put('-'); 323 #endif 324 } 325 KPRINTN(10); 326 break; 327 case 'o': 328 KPRINT(8); 329 break; 330 case 'u': 331 KPRINT(10); 332 break; 333 case 'p': 334 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 335 lflag |= (LONG|ALT); 336 #else 337 put('0'); 338 put('x'); 339 #endif 340 /* FALLTHROUGH */ 341 case 'x': 342 KPRINT(16); 343 break; 344 #if defined(__minix) 345 case 'X': 346 lflag |= HEXCAP; 347 KPRINT(16); 348 break; 349 #endif /* defined(__minix) */ 350 default: 351 if (ch == '\0') 352 return; 353 put(ch); 354 break; 355 } 356 } 357 } 358 359 static void 360 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 361 kprintn(void (*put)(int), UINTMAX_T ul, int base, int lflag, int width) 362 #else 363 kprintn(void (*put)(int), UINTMAX_T ul, int base) 364 #endif 365 { 366 /* hold a INTMAX_T in base 8 */ 367 char *p, buf[(sizeof(INTMAX_T) * NBBY / 3) + 1 + 2 /* ALT + SIGN */]; 368 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 369 char *q; 370 #endif 371 372 p = buf; 373 do { 374 *p++ = hexdigits[ul % base]; 375 #if defined(__minix) 376 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 377 /* LSC: Quick hack to support capital hex printout. */ 378 if ((lflag & HEXCAP) && (*(p-1) >= 'a') && (*(p-1) <= 'z')) { 379 *(p-1) -= 32; 380 } 381 #endif 382 #endif /* defined(__minix) */ 383 } while (ul /= base); 384 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 385 q = p; 386 if (lflag & ALT && *(p - 1) != '0') { 387 if (base == 8) { 388 *p++ = '0'; 389 } else if (base == 16) { 390 *p++ = 'x'; 391 *p++ = '0'; 392 } 393 } 394 if (lflag & NEGATIVE) 395 *p++ = '-'; 396 else if (lflag & SIGN) 397 *p++ = '+'; 398 else if (lflag & SPACE) 399 *p++ = ' '; 400 width -= p - buf; 401 if (lflag & ZEROPAD) { 402 while (p > q) 403 put(*--p); 404 } 405 #endif 406 RADJUSTPAD(); 407 RADJUSTZEROPAD(); 408 do { 409 put(*--p); 410 } while (p > buf); 411 LADJUSTPAD(); 412 } 413