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