1 /* $NetBSD: subr_prf.c,v 1.21 2011/07/17 20:54:52 joerg 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 68 const char hexdigits[16] = "0123456789abcdef"; 69 70 #define LONG 0x01 71 #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT 72 #define LLONG 0x02 73 #endif 74 75 #if defined(__minix) 76 #define HEXCAP 0x100 77 #endif /* defined(__minix) */ 78 79 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 80 #define ALT 0x04 81 #define SPACE 0x08 82 #define LADJUST 0x10 83 #define SIGN 0x20 84 #define ZEROPAD 0x40 85 #define NEGATIVE 0x80 86 #define KPRINTN(base) kprintn(put, ul, base, lflag, width) 87 #define RZERO() \ 88 do { \ 89 if ((lflag & (ZEROPAD|LADJUST)) == ZEROPAD) { \ 90 while (width-- > 0) \ 91 put('0'); \ 92 } \ 93 } while (/*CONSTCOND*/0) 94 #define RPAD() \ 95 do { \ 96 if (lflag & LADJUST) { \ 97 while (width-- > 0) \ 98 put(' '); \ 99 } \ 100 } while (/*CONSTCOND*/0) 101 #define LPAD() \ 102 do { \ 103 if ((lflag & (ZEROPAD|LADJUST)) == 0) { \ 104 while (width-- > 0) \ 105 put(' '); \ 106 } \ 107 } while (/*CONSTCOND*/0) 108 #else /* LIBSA_PRINTF_WIDTH_SUPPORT */ 109 #define KPRINTN(base) kprintn(put, ul, base) 110 #define RZERO() /**/ 111 #define RPAD() /**/ 112 #define LPAD() /**/ 113 #endif /* LIBSA_PRINTF_WIDTH_SUPPORT */ 114 115 #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT 116 #define KPRINT(base) \ 117 do { \ 118 ul = (lflag & LLONG) \ 119 ? va_arg(ap, u_longlong_t) \ 120 : (lflag & LONG) \ 121 ? va_arg(ap, u_long) \ 122 : va_arg(ap, u_int); \ 123 KPRINTN(base); \ 124 } while (/*CONSTCOND*/0) 125 #else /* LIBSA_PRINTF_LONGLONG_SUPPORT */ 126 #define KPRINT(base) \ 127 do { \ 128 ul = (lflag & LONG) \ 129 ? va_arg(ap, u_long) : va_arg(ap, u_int); \ 130 KPRINTN(base); \ 131 } while (/*CONSTCOND*/0) 132 #endif /* LIBSA_PRINTF_LONGLONG_SUPPORT */ 133 134 static void 135 sputchar(int c) 136 { 137 138 if (sbuf < ebuf) 139 *sbuf++ = c; 140 } 141 142 void 143 vprintf(const char *fmt, va_list ap) 144 { 145 146 kdoprnt(putchar, fmt, ap); 147 #if defined(__minix) && defined(LIBSA_PRINTF_WIDTH_SUPPORT) 148 /* BJG: our libminc kputc() relies on a 0 to flush the diag buffer. */ 149 putchar(0); 150 #endif /* defined(__minix) && defined(LIBSA_PRINTF_WIDTH_SUPPORT) */ 151 } 152 153 int 154 vsnprintf(char *buf, size_t size, const char *fmt, va_list ap) 155 { 156 157 sbuf = buf; 158 ebuf = buf + size - 1; 159 kdoprnt(sputchar, fmt, ap); 160 *sbuf = '\0'; 161 return sbuf - buf; 162 } 163 164 static void 165 kdoprnt(void (*put)(int), const char *fmt, va_list ap) 166 { 167 char *p; 168 int ch; 169 UINTMAX_T ul; 170 int lflag; 171 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 172 int width; 173 char *q; 174 #endif 175 176 for (;;) { 177 while ((ch = *fmt++) != '%') { 178 if (ch == '\0') 179 return; 180 put(ch); 181 } 182 lflag = 0; 183 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 184 width = 0; 185 #endif 186 reswitch: 187 switch (ch = *fmt++) { 188 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 189 #if defined(__minix) 190 /* LSC: FIXME: this is a simple hack which ignores the thing for now. */ 191 case '.': 192 /* eat up digits */ 193 while( ((('1' >= *fmt) && ( *fmt <= '9')) 194 || (*fmt == '*')) ) 195 fmt++; 196 fmt++; 197 goto reswitch; 198 #endif /* defined(__minix) */ 199 case '#': 200 lflag |= ALT; 201 goto reswitch; 202 case ' ': 203 lflag |= SPACE; 204 goto reswitch; 205 case '-': 206 lflag |= LADJUST; 207 goto reswitch; 208 case '+': 209 lflag |= SIGN; 210 goto reswitch; 211 case '0': 212 lflag |= ZEROPAD; 213 goto reswitch; 214 case '1': case '2': case '3': case '4': case '5': 215 case '6': case '7': case '8': case '9': 216 for (;;) { 217 width *= 10; 218 width += ch - '0'; 219 ch = *fmt; 220 if ((unsigned)ch - '0' > 9) 221 break; 222 ++fmt; 223 } 224 #endif 225 goto reswitch; 226 case 'l': 227 #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT 228 if (*fmt == 'l') { 229 ++fmt; 230 lflag |= LLONG; 231 } else 232 #endif 233 lflag |= LONG; 234 goto reswitch; 235 case 't': 236 if (sizeof(PTRDIFF_T) == sizeof(long)) 237 lflag |= LONG; 238 goto reswitch; 239 case 'z': 240 if (sizeof(ssize_t) == sizeof(long)) 241 lflag |= LONG; 242 goto reswitch; 243 case 'c': 244 ch = va_arg(ap, int); 245 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 246 --width; 247 #endif 248 RPAD(); 249 put(ch & 0xFF); 250 LPAD(); 251 break; 252 case 's': 253 p = va_arg(ap, char *); 254 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 255 for (q = p; *q != '\0'; ++q) 256 continue; 257 width -= q - p; 258 #endif 259 RPAD(); 260 while ((ch = (unsigned char)*p++)) 261 put(ch); 262 LPAD(); 263 break; 264 case 'd': 265 ul = 266 #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT 267 (lflag & LLONG) ? va_arg(ap, longlong_t) : 268 #endif 269 (lflag & LONG) ? va_arg(ap, long) : va_arg(ap, int); 270 if ((INTMAX_T)ul < 0) { 271 ul = -(INTMAX_T)ul; 272 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 273 lflag |= NEGATIVE; 274 #else 275 put('-'); 276 #endif 277 } 278 KPRINTN(10); 279 break; 280 case 'o': 281 KPRINT(8); 282 break; 283 case 'u': 284 KPRINT(10); 285 break; 286 case 'p': 287 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 288 lflag |= (LONG|ALT); 289 #else 290 put('0'); 291 put('x'); 292 #endif 293 /* FALLTHROUGH */ 294 case 'x': 295 KPRINT(16); 296 break; 297 #if defined(__minix) 298 case 'X': 299 lflag |= HEXCAP; 300 KPRINT(16); 301 break; 302 #endif /* defined(__minix) */ 303 default: 304 if (ch == '\0') 305 return; 306 put(ch); 307 break; 308 } 309 } 310 } 311 312 static void 313 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 314 kprintn(void (*put)(int), UINTMAX_T ul, int base, int lflag, int width) 315 #else 316 kprintn(void (*put)(int), UINTMAX_T ul, int base) 317 #endif 318 { 319 /* hold a INTMAX_T in base 8 */ 320 char *p, buf[(sizeof(INTMAX_T) * NBBY / 3) + 1 + 2 /* ALT + SIGN */]; 321 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 322 char *q; 323 #endif 324 325 p = buf; 326 do { 327 *p++ = hexdigits[ul % base]; 328 #if defined(__minix) 329 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 330 /* LSC: Quick hack to support capital hex printout. */ 331 if ((lflag & HEXCAP) && (*(p-1) >= 'a') && (*(p-1) <= 'z')) { 332 *(p-1) -= 32; 333 } 334 #endif 335 #endif /* defined(__minix) */ 336 } while (ul /= base); 337 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 338 q = p; 339 if (lflag & ALT && *(p - 1) != '0') { 340 if (base == 8) { 341 *p++ = '0'; 342 } else if (base == 16) { 343 *p++ = 'x'; 344 *p++ = '0'; 345 } 346 } 347 if (lflag & NEGATIVE) 348 *p++ = '-'; 349 else if (lflag & SIGN) 350 *p++ = '+'; 351 else if (lflag & SPACE) 352 *p++ = ' '; 353 width -= p - buf; 354 if ((lflag & LADJUST) == 0) { 355 while (p > q) 356 put(*--p); 357 } 358 #endif 359 RPAD(); 360 RZERO(); 361 do { 362 put(*--p); 363 } while (p > buf); 364 LPAD(); 365 } 366