1 1.31 mlelstv /* $NetBSD: subr_prf.c,v 1.31 2024/08/31 07:12:57 mlelstv Exp $ */ 2 1.1 pk 3 1.1 pk /*- 4 1.1 pk * Copyright (c) 1993 5 1.1 pk * The Regents of the University of California. All rights reserved. 6 1.1 pk * 7 1.1 pk * Redistribution and use in source and binary forms, with or without 8 1.1 pk * modification, are permitted provided that the following conditions 9 1.1 pk * are met: 10 1.1 pk * 1. Redistributions of source code must retain the above copyright 11 1.1 pk * notice, this list of conditions and the following disclaimer. 12 1.1 pk * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 pk * notice, this list of conditions and the following disclaimer in the 14 1.1 pk * documentation and/or other materials provided with the distribution. 15 1.10 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 pk * may be used to endorse or promote products derived from this software 17 1.1 pk * without specific prior written permission. 18 1.1 pk * 19 1.1 pk * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 pk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 pk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 pk * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 pk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 pk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 pk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 pk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 pk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 pk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 pk * SUCH DAMAGE. 30 1.1 pk * 31 1.1 pk * @(#)printf.c 8.1 (Berkeley) 6/11/93 32 1.1 pk */ 33 1.1 pk 34 1.1 pk /* 35 1.1 pk * Scaled down version of printf(3). 36 1.1 pk */ 37 1.1 pk 38 1.1 pk #include <sys/cdefs.h> 39 1.1 pk #include <sys/types.h> 40 1.14 uwe #include <sys/stdint.h> /* XXX: for intptr_t */ 41 1.1 pk 42 1.1 pk #include "stand.h" 43 1.1 pk 44 1.17 tsutsui #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT 45 1.17 tsutsui #define INTMAX_T longlong_t 46 1.17 tsutsui #define UINTMAX_T u_longlong_t 47 1.17 tsutsui #else 48 1.17 tsutsui #define INTMAX_T long 49 1.17 tsutsui #define UINTMAX_T u_long 50 1.17 tsutsui #endif 51 1.17 tsutsui 52 1.17 tsutsui #if 0 /* XXX: abuse intptr_t until the situation with ptrdiff_t is clear */ 53 1.17 tsutsui #define PTRDIFF_T ptrdiff_t 54 1.17 tsutsui #else 55 1.17 tsutsui #define PTRDIFF_T intptr_t 56 1.17 tsutsui #endif 57 1.17 tsutsui 58 1.17 tsutsui #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 59 1.17 tsutsui static void kprintn(void (*)(int), UINTMAX_T, int, int, int); 60 1.17 tsutsui #else 61 1.17 tsutsui static void kprintn(void (*)(int), UINTMAX_T, int); 62 1.17 tsutsui #endif 63 1.6 bjh21 static void sputchar(int); 64 1.6 bjh21 static void kdoprnt(void (*)(int), const char *, va_list); 65 1.1 pk 66 1.1 pk static char *sbuf, *ebuf; 67 1.1 pk 68 1.19 joerg const char hexdigits[16] = "0123456789abcdef"; 69 1.11 christos 70 1.17 tsutsui #define LONG 0x01 71 1.17 tsutsui #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT 72 1.17 tsutsui #define LLONG 0x02 73 1.17 tsutsui #endif 74 1.17 tsutsui #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 75 1.17 tsutsui #define ALT 0x04 76 1.17 tsutsui #define SPACE 0x08 77 1.17 tsutsui #define LADJUST 0x10 78 1.17 tsutsui #define SIGN 0x20 79 1.17 tsutsui #define ZEROPAD 0x40 80 1.17 tsutsui #define NEGATIVE 0x80 81 1.17 tsutsui #define KPRINTN(base) kprintn(put, ul, base, lflag, width) 82 1.27 tsutsui #define RADJUSTZEROPAD() \ 83 1.27 tsutsui do { \ 84 1.27 tsutsui if ((lflag & (ZEROPAD|LADJUST)) == ZEROPAD) { \ 85 1.27 tsutsui while (width-- > 0) \ 86 1.27 tsutsui put('0'); \ 87 1.27 tsutsui } \ 88 1.27 tsutsui } while (/*CONSTCOND*/0) 89 1.27 tsutsui #define LADJUSTPAD() \ 90 1.17 tsutsui do { \ 91 1.17 tsutsui if (lflag & LADJUST) { \ 92 1.17 tsutsui while (width-- > 0) \ 93 1.27 tsutsui put(' '); \ 94 1.17 tsutsui } \ 95 1.17 tsutsui } while (/*CONSTCOND*/0) 96 1.27 tsutsui #define RADJUSTPAD() \ 97 1.17 tsutsui do { \ 98 1.17 tsutsui if ((lflag & (ZEROPAD|LADJUST)) == 0) { \ 99 1.17 tsutsui while (width-- > 0) \ 100 1.27 tsutsui put(' '); \ 101 1.17 tsutsui } \ 102 1.17 tsutsui } while (/*CONSTCOND*/0) 103 1.17 tsutsui #else /* LIBSA_PRINTF_WIDTH_SUPPORT */ 104 1.17 tsutsui #define KPRINTN(base) kprintn(put, ul, base) 105 1.27 tsutsui #define RADJUSTZEROPAD() /**/ 106 1.25 tsutsui #define LADJUSTPAD() /**/ 107 1.25 tsutsui #define RADJUSTPAD() /**/ 108 1.17 tsutsui #endif /* LIBSA_PRINTF_WIDTH_SUPPORT */ 109 1.17 tsutsui 110 1.17 tsutsui #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT 111 1.17 tsutsui #define KPRINT(base) \ 112 1.17 tsutsui do { \ 113 1.17 tsutsui ul = (lflag & LLONG) \ 114 1.17 tsutsui ? va_arg(ap, u_longlong_t) \ 115 1.17 tsutsui : (lflag & LONG) \ 116 1.17 tsutsui ? va_arg(ap, u_long) \ 117 1.17 tsutsui : va_arg(ap, u_int); \ 118 1.17 tsutsui KPRINTN(base); \ 119 1.17 tsutsui } while (/*CONSTCOND*/0) 120 1.17 tsutsui #else /* LIBSA_PRINTF_LONGLONG_SUPPORT */ 121 1.17 tsutsui #define KPRINT(base) \ 122 1.17 tsutsui do { \ 123 1.17 tsutsui ul = (lflag & LONG) \ 124 1.17 tsutsui ? va_arg(ap, u_long) : va_arg(ap, u_int); \ 125 1.17 tsutsui KPRINTN(base); \ 126 1.17 tsutsui } while (/*CONSTCOND*/0) 127 1.17 tsutsui #endif /* LIBSA_PRINTF_LONGLONG_SUPPORT */ 128 1.17 tsutsui 129 1.1 pk static void 130 1.29 thorpej null_sputchar(int c) 131 1.29 thorpej { 132 1.29 thorpej sbuf++; 133 1.29 thorpej } 134 1.29 thorpej 135 1.29 thorpej static void 136 1.6 bjh21 sputchar(int c) 137 1.1 pk { 138 1.6 bjh21 139 1.1 pk if (sbuf < ebuf) 140 1.1 pk *sbuf++ = c; 141 1.1 pk } 142 1.1 pk 143 1.1 pk void 144 1.1 pk vprintf(const char *fmt, va_list ap) 145 1.1 pk { 146 1.1 pk 147 1.1 pk kdoprnt(putchar, fmt, ap); 148 1.1 pk } 149 1.1 pk 150 1.1 pk int 151 1.1 pk vsnprintf(char *buf, size_t size, const char *fmt, va_list ap) 152 1.1 pk { 153 1.1 pk 154 1.1 pk sbuf = buf; 155 1.1 pk ebuf = buf + size - 1; 156 1.29 thorpej kdoprnt(buf == NULL ? null_sputchar : sputchar, fmt, ap); 157 1.29 thorpej if (buf != NULL) 158 1.29 thorpej *sbuf = '\0'; 159 1.16 isaki return sbuf - buf; 160 1.1 pk } 161 1.1 pk 162 1.5 thorpej static void 163 1.6 bjh21 kdoprnt(void (*put)(int), const char *fmt, va_list ap) 164 1.1 pk { 165 1.3 augustss char *p; 166 1.9 tron int ch; 167 1.17 tsutsui UINTMAX_T ul; 168 1.9 tron int lflag; 169 1.17 tsutsui #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 170 1.17 tsutsui int width; 171 1.17 tsutsui char *q; 172 1.17 tsutsui #endif 173 1.1 pk 174 1.1 pk for (;;) { 175 1.1 pk while ((ch = *fmt++) != '%') { 176 1.1 pk if (ch == '\0') 177 1.1 pk return; 178 1.1 pk put(ch); 179 1.1 pk } 180 1.1 pk lflag = 0; 181 1.17 tsutsui #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 182 1.17 tsutsui width = 0; 183 1.17 tsutsui #endif 184 1.16 isaki reswitch: 185 1.16 isaki switch (ch = *fmt++) { 186 1.17 tsutsui #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 187 1.17 tsutsui case '#': 188 1.17 tsutsui lflag |= ALT; 189 1.17 tsutsui goto reswitch; 190 1.17 tsutsui case ' ': 191 1.17 tsutsui lflag |= SPACE; 192 1.17 tsutsui goto reswitch; 193 1.17 tsutsui case '-': 194 1.17 tsutsui lflag |= LADJUST; 195 1.17 tsutsui goto reswitch; 196 1.17 tsutsui case '+': 197 1.17 tsutsui lflag |= SIGN; 198 1.17 tsutsui goto reswitch; 199 1.17 tsutsui case '0': 200 1.31 mlelstv if (width == 0) { 201 1.31 mlelstv lflag |= ZEROPAD; 202 1.31 mlelstv goto reswitch; 203 1.31 mlelstv } 204 1.31 mlelstv /* FALLTHROUGH */ 205 1.17 tsutsui case '1': case '2': case '3': case '4': case '5': 206 1.17 tsutsui case '6': case '7': case '8': case '9': 207 1.17 tsutsui for (;;) { 208 1.17 tsutsui width *= 10; 209 1.17 tsutsui width += ch - '0'; 210 1.17 tsutsui ch = *fmt; 211 1.17 tsutsui if ((unsigned)ch - '0' > 9) 212 1.17 tsutsui break; 213 1.17 tsutsui ++fmt; 214 1.17 tsutsui } 215 1.30 rin goto reswitch; 216 1.17 tsutsui #endif 217 1.1 pk case 'l': 218 1.17 tsutsui #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT 219 1.17 tsutsui if (*fmt == 'l') { 220 1.17 tsutsui ++fmt; 221 1.17 tsutsui lflag |= LLONG; 222 1.17 tsutsui } else 223 1.17 tsutsui #endif 224 1.17 tsutsui lflag |= LONG; 225 1.1 pk goto reswitch; 226 1.22 jakllsch case 'j': 227 1.23 jakllsch #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT 228 1.23 jakllsch if (sizeof(intmax_t) == sizeof(long long)) 229 1.23 jakllsch lflag |= LLONG; 230 1.23 jakllsch else 231 1.23 jakllsch #endif 232 1.22 jakllsch if (sizeof(intmax_t) == sizeof(long)) 233 1.22 jakllsch lflag |= LONG; 234 1.22 jakllsch goto reswitch; 235 1.14 uwe case 't': 236 1.17 tsutsui if (sizeof(PTRDIFF_T) == sizeof(long)) 237 1.17 tsutsui lflag |= LONG; 238 1.14 uwe goto reswitch; 239 1.14 uwe case 'z': 240 1.17 tsutsui if (sizeof(ssize_t) == sizeof(long)) 241 1.17 tsutsui lflag |= LONG; 242 1.14 uwe goto reswitch; 243 1.1 pk case 'c': 244 1.1 pk ch = va_arg(ap, int); 245 1.17 tsutsui #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 246 1.17 tsutsui --width; 247 1.17 tsutsui #endif 248 1.27 tsutsui RADJUSTPAD(); 249 1.24 hkenken put(ch & 0xFF); 250 1.27 tsutsui LADJUSTPAD(); 251 1.1 pk break; 252 1.1 pk case 's': 253 1.1 pk p = va_arg(ap, char *); 254 1.17 tsutsui #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 255 1.20 tsutsui for (q = p; *q != '\0'; ++q) 256 1.20 tsutsui continue; 257 1.17 tsutsui width -= q - p; 258 1.17 tsutsui #endif 259 1.27 tsutsui RADJUSTPAD(); 260 1.17 tsutsui while ((ch = (unsigned char)*p++)) 261 1.1 pk put(ch); 262 1.27 tsutsui LADJUSTPAD(); 263 1.1 pk break; 264 1.1 pk case 'd': 265 1.17 tsutsui ul = 266 1.17 tsutsui #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT 267 1.17 tsutsui (lflag & LLONG) ? va_arg(ap, longlong_t) : 268 1.17 tsutsui #endif 269 1.17 tsutsui (lflag & LONG) ? va_arg(ap, long) : va_arg(ap, int); 270 1.17 tsutsui if ((INTMAX_T)ul < 0) { 271 1.17 tsutsui ul = -(INTMAX_T)ul; 272 1.17 tsutsui #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 273 1.17 tsutsui lflag |= NEGATIVE; 274 1.17 tsutsui #else 275 1.1 pk put('-'); 276 1.17 tsutsui #endif 277 1.1 pk } 278 1.17 tsutsui KPRINTN(10); 279 1.1 pk break; 280 1.1 pk case 'o': 281 1.17 tsutsui KPRINT(8); 282 1.1 pk break; 283 1.1 pk case 'u': 284 1.17 tsutsui KPRINT(10); 285 1.1 pk break; 286 1.1 pk case 'p': 287 1.17 tsutsui #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 288 1.17 tsutsui lflag |= (LONG|ALT); 289 1.17 tsutsui #else 290 1.1 pk put('0'); 291 1.1 pk put('x'); 292 1.17 tsutsui #endif 293 1.15 uwe /* FALLTHROUGH */ 294 1.1 pk case 'x': 295 1.17 tsutsui KPRINT(16); 296 1.1 pk break; 297 1.1 pk default: 298 1.7 bjh21 if (ch == '\0') 299 1.7 bjh21 return; 300 1.1 pk put(ch); 301 1.16 isaki break; 302 1.1 pk } 303 1.1 pk } 304 1.1 pk } 305 1.1 pk 306 1.1 pk static void 307 1.17 tsutsui #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 308 1.17 tsutsui kprintn(void (*put)(int), UINTMAX_T ul, int base, int lflag, int width) 309 1.17 tsutsui #else 310 1.17 tsutsui kprintn(void (*put)(int), UINTMAX_T ul, int base) 311 1.17 tsutsui #endif 312 1.1 pk { 313 1.17 tsutsui /* hold a INTMAX_T in base 8 */ 314 1.17 tsutsui char *p, buf[(sizeof(INTMAX_T) * NBBY / 3) + 1 + 2 /* ALT + SIGN */]; 315 1.17 tsutsui #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 316 1.17 tsutsui char *q; 317 1.17 tsutsui #endif 318 1.1 pk 319 1.1 pk p = buf; 320 1.1 pk do { 321 1.11 christos *p++ = hexdigits[ul % base]; 322 1.1 pk } while (ul /= base); 323 1.17 tsutsui #ifdef LIBSA_PRINTF_WIDTH_SUPPORT 324 1.17 tsutsui q = p; 325 1.17 tsutsui if (lflag & ALT && *(p - 1) != '0') { 326 1.17 tsutsui if (base == 8) { 327 1.17 tsutsui *p++ = '0'; 328 1.17 tsutsui } else if (base == 16) { 329 1.17 tsutsui *p++ = 'x'; 330 1.17 tsutsui *p++ = '0'; 331 1.17 tsutsui } 332 1.17 tsutsui } 333 1.17 tsutsui if (lflag & NEGATIVE) 334 1.17 tsutsui *p++ = '-'; 335 1.17 tsutsui else if (lflag & SIGN) 336 1.17 tsutsui *p++ = '+'; 337 1.17 tsutsui else if (lflag & SPACE) 338 1.17 tsutsui *p++ = ' '; 339 1.17 tsutsui width -= p - buf; 340 1.24 hkenken if (lflag & ZEROPAD) { 341 1.17 tsutsui while (p > q) 342 1.17 tsutsui put(*--p); 343 1.17 tsutsui } 344 1.17 tsutsui #endif 345 1.27 tsutsui RADJUSTPAD(); 346 1.27 tsutsui RADJUSTZEROPAD(); 347 1.1 pk do { 348 1.1 pk put(*--p); 349 1.1 pk } while (p > buf); 350 1.27 tsutsui LADJUSTPAD(); 351 1.1 pk } 352