1 /* $NetBSD: subr_prf.c,v 1.17 2010/01/19 15:26:45 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 #include <machine/stdarg.h> 42 43 #include "stand.h" 44 45 #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT 46 #define INTMAX_T longlong_t 47 #define UINTMAX_T u_longlong_t 48 #else 49 #define INTMAX_T long 50 #define UINTMAX_T u_long 51 #endif 52 53 #if 0 /* XXX: abuse intptr_t until the situation with ptrdiff_t is clear */ 54 #define PTRDIFF_T ptrdiff_t 55 #else 56 #define PTRDIFF_T intptr_t 57 #endif 58 59 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 60 static void kprintn(void (*)(int), UINTMAX_T, int, int, int); 61 #else 62 static void kprintn(void (*)(int), UINTMAX_T, int); 63 #endif 64 static void sputchar(int); 65 static void kdoprnt(void (*)(int), const char *, va_list); 66 67 static char *sbuf, *ebuf; 68 69 const char HEXDIGITS[] = "0123456789ABCDEF"; 70 const char hexdigits[] = "0123456789abcdef"; 71 72 #define LONG 0x01 73 #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT 74 #define LLONG 0x02 75 #endif 76 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 77 #define ALT 0x04 78 #define SPACE 0x08 79 #define LADJUST 0x10 80 #define SIGN 0x20 81 #define ZEROPAD 0x40 82 #define NEGATIVE 0x80 83 #define KPRINTN(base) kprintn(put, ul, base, lflag, width) 84 #define RZERO() \ 85 do { \ 86 if ((lflag & (ZEROPAD|LADJUST)) == ZEROPAD) { \ 87 while (width-- > 0) \ 88 put('0'); \ 89 } \ 90 } while (/*CONSTCOND*/0) 91 #define RPAD() \ 92 do { \ 93 if (lflag & LADJUST) { \ 94 while (width-- > 0) \ 95 put(' '); \ 96 } \ 97 } while (/*CONSTCOND*/0) 98 #define LPAD() \ 99 do { \ 100 if ((lflag & (ZEROPAD|LADJUST)) == 0) { \ 101 while (width-- > 0) \ 102 put(' '); \ 103 } \ 104 } while (/*CONSTCOND*/0) 105 #else /* LIBSA_PRINTF_WIDTH_SUPPORT */ 106 #define KPRINTN(base) kprintn(put, ul, base) 107 #define RZERO() /**/ 108 #define RPAD() /**/ 109 #define LPAD() /**/ 110 #endif /* LIBSA_PRINTF_WIDTH_SUPPORT */ 111 112 #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT 113 #define KPRINT(base) \ 114 do { \ 115 ul = (lflag & LLONG) \ 116 ? va_arg(ap, u_longlong_t) \ 117 : (lflag & LONG) \ 118 ? va_arg(ap, u_long) \ 119 : va_arg(ap, u_int); \ 120 KPRINTN(base); \ 121 } while (/*CONSTCOND*/0) 122 #else /* LIBSA_PRINTF_LONGLONG_SUPPORT */ 123 #define KPRINT(base) \ 124 do { \ 125 ul = (lflag & LONG) \ 126 ? va_arg(ap, u_long) : va_arg(ap, u_int); \ 127 KPRINTN(base); \ 128 } while (/*CONSTCOND*/0) 129 #endif /* LIBSA_PRINTF_LONGLONG_SUPPORT */ 130 131 static void 132 sputchar(int c) 133 { 134 135 if (sbuf < ebuf) 136 *sbuf++ = c; 137 } 138 139 void 140 vprintf(const char *fmt, va_list ap) 141 { 142 143 kdoprnt(putchar, fmt, ap); 144 } 145 146 int 147 vsnprintf(char *buf, size_t size, const char *fmt, va_list ap) 148 { 149 150 sbuf = buf; 151 ebuf = buf + size - 1; 152 kdoprnt(sputchar, fmt, ap); 153 *sbuf = '\0'; 154 return sbuf - buf; 155 } 156 157 static void 158 kdoprnt(void (*put)(int), const char *fmt, va_list ap) 159 { 160 char *p; 161 int ch; 162 UINTMAX_T ul; 163 int lflag; 164 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 165 int width; 166 char *q; 167 #endif 168 169 for (;;) { 170 while ((ch = *fmt++) != '%') { 171 if (ch == '\0') 172 return; 173 put(ch); 174 } 175 lflag = 0; 176 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 177 width = 0; 178 #endif 179 reswitch: 180 switch (ch = *fmt++) { 181 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 182 case '#': 183 lflag |= ALT; 184 goto reswitch; 185 case ' ': 186 lflag |= SPACE; 187 goto reswitch; 188 case '-': 189 lflag |= LADJUST; 190 goto reswitch; 191 case '+': 192 lflag |= SIGN; 193 goto reswitch; 194 case '0': 195 lflag |= ZEROPAD; 196 goto reswitch; 197 case '1': case '2': case '3': case '4': case '5': 198 case '6': case '7': case '8': case '9': 199 for (;;) { 200 width *= 10; 201 width += ch - '0'; 202 ch = *fmt; 203 if ((unsigned)ch - '0' > 9) 204 break; 205 ++fmt; 206 } 207 #endif 208 goto reswitch; 209 case 'l': 210 #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT 211 if (*fmt == 'l') { 212 ++fmt; 213 lflag |= LLONG; 214 } else 215 #endif 216 lflag |= LONG; 217 goto reswitch; 218 case 't': 219 if (sizeof(PTRDIFF_T) == sizeof(long)) 220 lflag |= LONG; 221 goto reswitch; 222 case 'z': 223 if (sizeof(ssize_t) == sizeof(long)) 224 lflag |= LONG; 225 goto reswitch; 226 case 'c': 227 ch = va_arg(ap, int); 228 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 229 --width; 230 #endif 231 RPAD(); 232 put(ch & 0xFF); 233 LPAD(); 234 break; 235 case 's': 236 p = va_arg(ap, char *); 237 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 238 for (q = p; *q; ++q); 239 width -= q - p; 240 #endif 241 RPAD(); 242 while ((ch = (unsigned char)*p++)) 243 put(ch); 244 LPAD(); 245 break; 246 case 'd': 247 ul = 248 #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT 249 (lflag & LLONG) ? va_arg(ap, longlong_t) : 250 #endif 251 (lflag & LONG) ? va_arg(ap, long) : va_arg(ap, int); 252 if ((INTMAX_T)ul < 0) { 253 ul = -(INTMAX_T)ul; 254 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 255 lflag |= NEGATIVE; 256 #else 257 put('-'); 258 #endif 259 } 260 KPRINTN(10); 261 break; 262 case 'o': 263 KPRINT(8); 264 break; 265 case 'u': 266 KPRINT(10); 267 break; 268 case 'p': 269 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 270 lflag |= (LONG|ALT); 271 #else 272 put('0'); 273 put('x'); 274 #endif 275 /* FALLTHROUGH */ 276 case 'x': 277 KPRINT(16); 278 break; 279 default: 280 if (ch == '\0') 281 return; 282 put(ch); 283 break; 284 } 285 } 286 } 287 288 static void 289 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 290 kprintn(void (*put)(int), UINTMAX_T ul, int base, int lflag, int width) 291 #else 292 kprintn(void (*put)(int), UINTMAX_T ul, int base) 293 #endif 294 { 295 /* hold a INTMAX_T in base 8 */ 296 char *p, buf[(sizeof(INTMAX_T) * NBBY / 3) + 1 + 2 /* ALT + SIGN */]; 297 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 298 char *q; 299 #endif 300 301 p = buf; 302 do { 303 *p++ = hexdigits[ul % base]; 304 } while (ul /= base); 305 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 306 q = p; 307 if (lflag & ALT && *(p - 1) != '0') { 308 if (base == 8) { 309 *p++ = '0'; 310 } else if (base == 16) { 311 *p++ = 'x'; 312 *p++ = '0'; 313 } 314 } 315 if (lflag & NEGATIVE) 316 *p++ = '-'; 317 else if (lflag & SIGN) 318 *p++ = '+'; 319 else if (lflag & SPACE) 320 *p++ = ' '; 321 width -= p - buf; 322 if ((lflag & LADJUST) == 0) { 323 while (p > q) 324 put(*--p); 325 } 326 #endif 327 RPAD(); 328 RZERO(); 329 do { 330 put(*--p); 331 } while (p > buf); 332 LPAD(); 333 } 334