printf.c (13678B)
1 //===-- printf.c - kit freestanding printf routines ---------------------===// 2 // 3 // Based on the mpaland/printf MIT-licensed formatter, imported for kit's 4 // freestanding runtime and reduced to the top-level <stdio.h> declarations. 5 // Floating-point formats are intentionally omitted until kit's backends can 6 // compile the original mpaland conversion path portably. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include <stdarg.h> 11 #include <stddef.h> 12 #include <stdint.h> 13 14 typedef void (*KitPrintfCallback)(char ch, void* arg); 15 16 typedef struct { 17 char* buf; 18 size_t cap; 19 size_t len; 20 KitPrintfCallback fct; 21 void* arg; 22 } KitPrintfOut; 23 24 static void kit_out_ch(KitPrintfOut* out, char ch) { 25 if (out->fct) { 26 out->fct(ch, out->arg); 27 } else if (out->cap && out->len + 1U < out->cap) { 28 out->buf[out->len] = ch; 29 } 30 out->len++; 31 } 32 33 static void kit_out_repeat(KitPrintfOut* out, char ch, unsigned count) { 34 while (count-- > 0) kit_out_ch(out, ch); 35 } 36 37 static unsigned kit_strlen_prec(const char* s, int has_prec, unsigned prec) { 38 unsigned n = 0; 39 if (!s) s = "(null)"; 40 while (s[n] != '\0' && (!has_prec || n < prec)) n++; 41 return n; 42 } 43 44 static void kit_out_string(KitPrintfOut* out, const char* s, int left, 45 unsigned width, int has_prec, unsigned prec) { 46 unsigned len = kit_strlen_prec(s, has_prec, prec); 47 if (!s) s = "(null)"; 48 if (!left && width > len) kit_out_repeat(out, ' ', width - len); 49 for (unsigned i = 0; i < len; i++) kit_out_ch(out, s[i]); 50 if (left && width > len) kit_out_repeat(out, ' ', width - len); 51 } 52 53 static void kit_out_uint(KitPrintfOut* out, unsigned long long value, 54 unsigned base, int upper, int neg, int left, int zero, 55 unsigned width) { 56 char tmp[64]; 57 unsigned len = 0; 58 unsigned digits_len; 59 const char* digits = upper ? "0123456789ABCDEF" : "0123456789abcdef"; 60 unsigned prefix = neg ? 1U : 0U; 61 char pad = (zero && !left) ? '0' : ' '; 62 63 do { 64 tmp[len++] = digits[value % base]; 65 value /= base; 66 } while (value != 0); 67 digits_len = len; 68 69 if (!left && pad == ' ' && width > len + prefix) { 70 kit_out_repeat(out, ' ', width - len - prefix); 71 } 72 if (neg) kit_out_ch(out, '-'); 73 if (!left && pad == '0' && width > len + prefix) { 74 kit_out_repeat(out, '0', width - len - prefix); 75 } 76 while (len > 0) kit_out_ch(out, tmp[--len]); 77 if (left && width > digits_len + prefix) { 78 kit_out_repeat(out, ' ', width - digits_len - prefix); 79 } 80 } 81 82 static void kit_out_padded_string(KitPrintfOut* out, const char* s, 83 unsigned len, int neg, int plus, int space, 84 int left, int zero, unsigned width) { 85 unsigned prefix = (neg || plus || space) ? 1U : 0U; 86 char sign = neg ? '-' : (plus ? '+' : ' '); 87 char pad = (zero && !left) ? '0' : ' '; 88 89 if (!left && pad == ' ' && width > len + prefix) { 90 kit_out_repeat(out, ' ', width - len - prefix); 91 } 92 if (prefix) kit_out_ch(out, sign); 93 if (!left && pad == '0' && width > len + prefix) { 94 kit_out_repeat(out, '0', width - len - prefix); 95 } 96 for (unsigned i = 0; i < len; i++) kit_out_ch(out, s[i]); 97 if (left && width > len + prefix) { 98 kit_out_repeat(out, ' ', width - len - prefix); 99 } 100 } 101 102 static int kit_double_negative(double v) { 103 union { 104 double d; 105 uint64_t u; 106 } bits; 107 bits.d = v; 108 return (int)(bits.u >> 63); 109 } 110 111 static double kit_double_abs(double v) { return v < 0.0 ? -v : v; } 112 113 static double kit_pow10_u(unsigned n) { 114 double value = 1.0; 115 while (n-- > 0) value *= 10.0; 116 return value; 117 } 118 119 static void kit_format_fixed_abs(KitPrintfOut* out, double value, unsigned prec, 120 int alt) { 121 double rounded; 122 double pow10 = 1.0; 123 int emitted = 0; 124 125 if (prec > 18U) prec = 18U; 126 rounded = value + 0.5 / kit_pow10_u(prec); 127 128 if (rounded >= 1.0) { 129 for (;;) { 130 double next = pow10 * 10.0; 131 if (!(next > pow10) || next > rounded) break; 132 pow10 = next; 133 } 134 } 135 136 while (pow10 >= 1.0) { 137 int digit = (int)(rounded / pow10); 138 if (digit < 0) digit = 0; 139 if (digit > 9) digit = 9; 140 kit_out_ch(out, (char)('0' + digit)); 141 rounded -= (double)digit * pow10; 142 pow10 /= 10.0; 143 emitted = 1; 144 } 145 if (!emitted) kit_out_ch(out, '0'); 146 147 if (prec != 0 || alt) kit_out_ch(out, '.'); 148 for (unsigned i = 0; i < prec; i++) { 149 int digit; 150 rounded *= 10.0; 151 digit = (int)rounded; 152 if (digit < 0) digit = 0; 153 if (digit > 9) digit = 9; 154 kit_out_ch(out, (char)('0' + digit)); 155 rounded -= (double)digit; 156 } 157 } 158 159 static int kit_decimal_exp(double value) { 160 int exp = 0; 161 if (value == 0.0) return 0; 162 while (value >= 10.0) { 163 value /= 10.0; 164 exp++; 165 } 166 while (value < 1.0) { 167 value *= 10.0; 168 exp--; 169 } 170 return exp; 171 } 172 173 static double kit_normalize_decimal(double value, int* exp) { 174 *exp = 0; 175 if (value == 0.0) return 0.0; 176 while (value >= 10.0) { 177 value /= 10.0; 178 (*exp)++; 179 } 180 while (value < 1.0) { 181 value *= 10.0; 182 (*exp)--; 183 } 184 return value; 185 } 186 187 static void kit_format_exp_abs(KitPrintfOut* out, double value, unsigned prec, 188 int upper, int alt) { 189 int exp; 190 unsigned e; 191 char digits[12]; 192 unsigned len = 0; 193 double norm; 194 195 if (prec > 18U) prec = 18U; 196 norm = kit_normalize_decimal(value, &exp); 197 if (norm + 0.5 / kit_pow10_u(prec) >= 10.0) { 198 norm /= 10.0; 199 exp++; 200 } 201 202 kit_format_fixed_abs(out, norm, prec, alt); 203 kit_out_ch(out, upper ? 'E' : 'e'); 204 if (exp < 0) { 205 kit_out_ch(out, '-'); 206 e = (unsigned)-exp; 207 } else { 208 kit_out_ch(out, '+'); 209 e = (unsigned)exp; 210 } 211 212 do { 213 digits[len++] = (char)('0' + (e % 10U)); 214 e /= 10U; 215 } while (e != 0U); 216 while (len < 2U) digits[len++] = '0'; 217 while (len > 0) kit_out_ch(out, digits[--len]); 218 } 219 220 static void kit_trim_float(char* s, unsigned* len, int alt) { 221 unsigned end = *len; 222 unsigned exp_start = end; 223 unsigned trim_end; 224 unsigned dot_pos = end; 225 unsigned i; 226 227 if (alt) return; 228 for (i = 0; i < end; i++) { 229 if (s[i] == 'e' || s[i] == 'E') { 230 exp_start = i; 231 break; 232 } 233 } 234 trim_end = exp_start; 235 for (i = 0; i < exp_start; i++) { 236 if (s[i] == '.') { 237 dot_pos = i; 238 break; 239 } 240 } 241 if (dot_pos == end) return; 242 243 while (trim_end > dot_pos + 1U && s[trim_end - 1U] == '0') trim_end--; 244 if (trim_end > dot_pos && s[trim_end - 1U] == '.') trim_end--; 245 246 if (exp_start < end) { 247 unsigned src = exp_start; 248 while (src < end) s[trim_end++] = s[src++]; 249 } 250 *len = trim_end; 251 s[*len] = '\0'; 252 } 253 254 static void kit_format_float(KitPrintfOut* out, double value, char spec, 255 int left, int zero, int plus, int space, int alt, 256 unsigned width, int has_prec, unsigned prec) { 257 char tmp[384]; 258 KitPrintfOut tmp_out; 259 unsigned len; 260 int neg = kit_double_negative(value); 261 double mag = kit_double_abs(value); 262 263 if (!has_prec) prec = 6U; 264 tmp_out.buf = tmp; 265 tmp_out.cap = sizeof(tmp); 266 tmp_out.len = 0U; 267 tmp_out.fct = NULL; 268 tmp_out.arg = NULL; 269 270 if (value != value) { 271 kit_out_string(&tmp_out, (spec >= 'A' && spec <= 'Z') ? "NAN" : "nan", 0, 0, 272 0, 0); 273 neg = 0; 274 } else if (mag > 1.7976931348623157e308) { 275 kit_out_string(&tmp_out, (spec >= 'A' && spec <= 'Z') ? "INF" : "inf", 0, 0, 276 0, 0); 277 } else if (spec == 'e' || spec == 'E') { 278 kit_format_exp_abs(&tmp_out, mag, prec, spec == 'E', alt); 279 } else if (spec == 'g' || spec == 'G') { 280 int exp = kit_decimal_exp(mag); 281 if (prec == 0U) prec = 1U; 282 if (exp < -4 || exp >= (int)prec) { 283 kit_format_exp_abs(&tmp_out, mag, prec - 1U, spec == 'G', alt); 284 } else { 285 unsigned fprec = 286 exp >= 0 ? prec - (unsigned)exp - 1U : prec + (unsigned)(-exp) - 1U; 287 kit_format_fixed_abs(&tmp_out, mag, fprec, alt); 288 } 289 } else { 290 kit_format_fixed_abs(&tmp_out, mag, prec, alt); 291 } 292 293 len = tmp_out.len < sizeof(tmp) ? (unsigned)tmp_out.len 294 : (unsigned)sizeof(tmp) - 1U; 295 tmp[len] = '\0'; 296 if (spec == 'g' || spec == 'G') kit_trim_float(tmp, &len, alt); 297 if (value != value) neg = 0; 298 kit_out_padded_string(out, tmp, len, neg, plus && !neg, space && !neg, left, 299 zero, width); 300 } 301 302 static int kit_is_digit(char ch) { return ch >= '0' && ch <= '9'; } 303 304 static unsigned kit_parse_uint(const char** p) { 305 unsigned value = 0; 306 while (kit_is_digit(**p)) { 307 value = value * 10U + (unsigned)(*(*p)++ - '0'); 308 } 309 return value; 310 } 311 312 static int kit_vprintf_impl(KitPrintfOut* out, const char* fmt, va_list ap) { 313 while (*fmt) { 314 int left = 0; 315 int zero = 0; 316 int plus = 0; 317 int space = 0; 318 int alt = 0; 319 int long_mod = 0; 320 int long_long_mod = 0; 321 int has_prec = 0; 322 unsigned width = 0; 323 unsigned prec = 0; 324 325 if (*fmt != '%') { 326 kit_out_ch(out, *fmt++); 327 continue; 328 } 329 fmt++; 330 if (*fmt == '%') { 331 kit_out_ch(out, *fmt++); 332 continue; 333 } 334 335 for (;;) { 336 if (*fmt == '-') { 337 left = 1; 338 fmt++; 339 } else if (*fmt == '0') { 340 zero = 1; 341 fmt++; 342 } else if (*fmt == '+') { 343 plus = 1; 344 fmt++; 345 } else if (*fmt == ' ') { 346 space = 1; 347 fmt++; 348 } else if (*fmt == '#') { 349 alt = 1; 350 fmt++; 351 } else { 352 break; 353 } 354 } 355 if (*fmt == '*') { 356 /* Width from an int arg; a negative value means left-justify (C11 357 * 7.21.6.1p5: taken as a '-' flag plus a positive width). */ 358 int w = va_arg(ap, int); 359 fmt++; 360 if (w < 0) { 361 left = 1; 362 width = (unsigned)(-w); 363 } else { 364 width = (unsigned)w; 365 } 366 } else if (kit_is_digit(*fmt)) { 367 width = kit_parse_uint(&fmt); 368 } 369 if (*fmt == '.') { 370 fmt++; 371 has_prec = 1; 372 if (*fmt == '*') { 373 /* Precision from an int arg; a negative value is taken as if the 374 * precision were omitted (C11 7.21.6.1p5). */ 375 int p = va_arg(ap, int); 376 fmt++; 377 if (p < 0) { 378 has_prec = 0; 379 } else { 380 prec = (unsigned)p; 381 } 382 } else { 383 prec = kit_parse_uint(&fmt); 384 } 385 } 386 if (*fmt == 'l') { 387 fmt++; 388 if (*fmt == 'l') { 389 fmt++; 390 long_long_mod = 1; 391 } else { 392 long_mod = 1; 393 } 394 } else if (*fmt == 'h') { 395 fmt++; 396 if (*fmt == 'h') fmt++; 397 } 398 399 switch (*fmt) { 400 case 'd': 401 case 'i': { 402 long long v; 403 unsigned long long mag; 404 if (long_long_mod) { 405 v = va_arg(ap, long long); 406 } else if (long_mod) { 407 v = va_arg(ap, long); 408 } else { 409 v = va_arg(ap, int); 410 } 411 mag = v < 0 ? 0ULL - (unsigned long long)v : (unsigned long long)v; 412 kit_out_uint(out, mag, 10U, 0, v < 0, left, zero, width); 413 break; 414 } 415 case 'u': 416 case 'x': 417 case 'X': 418 case 'o': { 419 unsigned long long v; 420 unsigned base = *fmt == 'o' ? 8U : ((*fmt == 'u') ? 10U : 16U); 421 if (long_long_mod) { 422 v = va_arg(ap, unsigned long long); 423 } else if (long_mod) { 424 v = va_arg(ap, unsigned long); 425 } else { 426 v = va_arg(ap, unsigned int); 427 } 428 kit_out_uint(out, v, base, *fmt == 'X', 0, left, zero, width); 429 break; 430 } 431 case 'p': { 432 uintptr_t v = (uintptr_t)va_arg(ap, void*); 433 kit_out_string(out, "0x", 0, 0, 0, 0); 434 kit_out_uint(out, (unsigned long long)v, 16U, 0, 0, 0, 0, 0); 435 break; 436 } 437 case 'c': 438 kit_out_ch(out, (char)va_arg(ap, int)); 439 break; 440 case 's': 441 kit_out_string(out, va_arg(ap, const char*), left, width, has_prec, 442 prec); 443 break; 444 case 'f': 445 case 'F': 446 case 'e': 447 case 'E': 448 case 'g': 449 case 'G': 450 kit_format_float(out, va_arg(ap, double), *fmt, left, zero, plus, space, 451 alt, width, has_prec, prec); 452 break; 453 default: 454 if (*fmt) kit_out_ch(out, *fmt); 455 break; 456 } 457 if (*fmt) fmt++; 458 } 459 460 return (int)out->len; 461 } 462 463 static int kit_vsnprintf_impl(char* s, size_t n, const char* fmt, va_list ap) { 464 KitPrintfOut out; 465 int rc; 466 out.buf = s; 467 out.cap = s ? n : 0U; 468 out.len = 0U; 469 out.fct = NULL; 470 out.arg = NULL; 471 472 rc = kit_vprintf_impl(&out, fmt, ap); 473 if (out.cap) { 474 size_t pos = out.len < out.cap ? out.len : out.cap - 1U; 475 out.buf[pos] = '\0'; 476 } 477 return rc; 478 } 479 480 __attribute__((weak)) int vsnprintf(char* s, size_t n, const char* fmt, 481 va_list ap) { 482 va_list copy; 483 int rc; 484 va_copy(copy, ap); 485 rc = kit_vsnprintf_impl(s, n, fmt, copy); 486 va_end(copy); 487 return rc; 488 } 489 490 __attribute__((weak)) int snprintf(char* s, size_t n, const char* fmt, ...) { 491 va_list ap; 492 int rc; 493 va_start(ap, fmt); 494 rc = vsnprintf(s, n, fmt, ap); 495 va_end(ap); 496 return rc; 497 } 498 499 __attribute__((weak)) int vsprintf(char* s, const char* fmt, va_list ap) { 500 return vsnprintf(s, (size_t)-1, fmt, ap); 501 } 502 503 __attribute__((weak)) int sprintf(char* s, const char* fmt, ...) { 504 va_list ap; 505 int rc; 506 va_start(ap, fmt); 507 rc = vsprintf(s, fmt, ap); 508 va_end(ap); 509 return rc; 510 } 511 512 __attribute__((weak)) int fctprintf(void (*out_fct)(char ch, void* arg), 513 void* arg, const char* fmt, ...) { 514 KitPrintfOut out; 515 va_list ap; 516 int rc; 517 out.buf = NULL; 518 out.cap = 0U; 519 out.len = 0U; 520 out.fct = out_fct; 521 out.arg = arg; 522 va_start(ap, fmt); 523 rc = kit_vprintf_impl(&out, fmt, ap); 524 va_end(ap); 525 return rc; 526 }