Changeset c7c6afd in mainline for common/printf/printf_core.c
- Timestamp:
- 2025-04-13T23:27:44Z (4 weeks ago)
- Children:
- b6061f8c
- Parents:
- 240b2e4 (diff), f5e1692 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - git-author:
- Wayne Thornton <wmthornton-dev@…> (2025-04-13 23:27:44)
- git-committer:
- GitHub <noreply@…> (2025-04-13 23:27:44)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
common/printf/printf_core.c
r240b2e4 rc7c6afd 3 3 * Copyright (c) 2006 Josef Cejka 4 4 * Copyright (c) 2009 Martin Decky 5 * Copyright (c) 2025 Jiří Zárevúcky 5 6 * All rights reserved. 6 7 * … … 37 38 */ 38 39 39 #include <stdio.h> 40 #include <_bits/uchar.h> 41 #include <_bits/wint_t.h> 42 #include <assert.h> 43 #include <ctype.h> 44 #include <errno.h> 45 #include <limits.h> 46 #include <macros.h> 47 #include <printf_core.h> 40 48 #include <stddef.h> 49 #include <stdint.h> 41 50 #include <stdlib.h> 42 #include <printf_core.h>43 #include <ctype.h>44 51 #include <str.h> 45 #include <assert.h>46 #include <macros.h>47 #include <uchar.h>48 52 49 53 /* Disable float support in kernel, because we usually disable floating operations there. */ … … 88 92 89 93 /** 90 * Buffer big enough for 64-bit number printed in base 2, sign, prefix and 0 91 * to terminate string... (last one is only for better testing end of buffer by 92 * zero-filling subroutine) 93 */ 94 #define PRINT_NUMBER_BUFFER_SIZE (64 + 5) 94 * Buffer big enough for 64-bit number printed in base 2. 95 */ 96 #define PRINT_NUMBER_BUFFER_SIZE 64 95 97 96 98 /** Get signed or unsigned integer argument */ … … 122 124 PrintfQualifierLongLong, 123 125 PrintfQualifierPointer, 124 PrintfQualifierSize,125 PrintfQualifierMax126 126 } qualifier_t; 127 127 128 static const char *nullstr = "(NULL)"; 129 static const char *digits_small = "0123456789abcdef"; 130 static const char *digits_big = "0123456789ABCDEF"; 131 static const char invalch = U_SPECIAL; 132 133 /** Print one or more characters without adding newline. 134 * 135 * @param buf Buffer holding characters with size of 136 * at least size bytes. NULL is not allowed! 137 * @param size Size of the buffer in bytes. 138 * @param ps Output method and its data. 139 * 140 * @return Number of characters printed. 141 * 142 */ 143 static int printf_putnchars(const char *buf, size_t size, 144 printf_spec_t *ps) 145 { 146 return ps->str_write((void *) buf, size, ps->data); 147 } 148 149 /** Print one or more wide characters without adding newline. 150 * 151 * @param buf Buffer holding wide characters with size of 152 * at least size bytes. NULL is not allowed! 153 * @param size Size of the buffer in bytes. 154 * @param ps Output method and its data. 155 * 156 * @return Number of wide characters printed. 157 * 158 */ 159 static int printf_wputnchars(const char32_t *buf, size_t size, 160 printf_spec_t *ps) 161 { 162 return ps->wstr_write((void *) buf, size, ps->data); 163 } 164 165 /** Print string without adding a newline. 166 * 167 * @param str String to print. 168 * @param ps Write function specification and support data. 169 * 170 * @return Number of characters printed. 171 * 172 */ 173 static int printf_putstr(const char *str, printf_spec_t *ps) 174 { 175 if (str == NULL) 176 return printf_putnchars(nullstr, str_size(nullstr), ps); 177 178 return ps->str_write((void *) str, str_size(str), ps->data); 179 } 180 181 /** Print one ASCII character. 182 * 183 * @param c ASCII character to be printed. 184 * @param ps Output method. 185 * 186 * @return Number of characters printed. 187 * 188 */ 189 static int printf_putchar(const char ch, printf_spec_t *ps) 190 { 191 if (!ascii_check(ch)) 192 return ps->str_write((void *) &invalch, 1, ps->data); 193 194 return ps->str_write(&ch, 1, ps->data); 195 } 196 197 /** Print one wide character. 198 * 199 * @param c Wide character to be printed. 200 * @param ps Output method. 201 * 202 * @return Number of characters printed. 203 * 204 */ 205 static int printf_putuchar(const char32_t ch, printf_spec_t *ps) 206 { 207 if (!chr_check(ch)) 208 return ps->str_write((void *) &invalch, 1, ps->data); 209 210 return ps->wstr_write(&ch, sizeof(char32_t), ps->data); 128 static const char _digits_small[] = "0123456789abcdef"; 129 static const char _digits_big[] = "0123456789ABCDEF"; 130 131 static const char _nullstr[] = "(NULL)"; 132 static const char _replacement[] = u8"�"; 133 static const char _spaces[] = " "; 134 static const char _zeros[] = "000000000000000000000000000000000000000000000000"; 135 136 static void _set_errno(errno_t rc) 137 { 138 #ifdef errno 139 errno = rc; 140 #endif 141 } 142 143 static size_t _utf8_bytes(char32_t c) 144 { 145 if (c < 0x80) 146 return 1; 147 148 if (c < 0x800) 149 return 2; 150 151 if (c < 0xD800) 152 return 3; 153 154 /* Surrogate code points, invalid in UTF-32. */ 155 if (c < 0xE000) 156 return sizeof(_replacement) - 1; 157 158 if (c < 0x10000) 159 return 3; 160 161 if (c < 0x110000) 162 return 4; 163 164 /* Invalid character. */ 165 return sizeof(_replacement) - 1; 166 } 167 168 /** Counts characters and utf8 bytes in a wide string up to a byte limit. 169 * @param max_bytes Byte length limit for string's utf8 conversion. 170 * @param[out] len The number of wide characters 171 * @return Number of utf8 bytes that the first *len characters in the string 172 * will convert to. Will always be less than max_bytes. 173 */ 174 static size_t _utf8_wstr_bytes_len(char32_t *s, size_t max_bytes, size_t *len) 175 { 176 size_t bytes = 0; 177 size_t i; 178 179 for (i = 0; bytes < max_bytes && s[i]; i++) { 180 size_t next = _utf8_bytes(s[i]); 181 if (max_bytes - bytes < next) 182 break; 183 184 bytes += next; 185 } 186 187 *len = i; 188 return bytes; 189 } 190 191 #define TRY(expr) ({ errno_t rc = (expr); if (rc != EOK) return rc; }) 192 193 static inline void _saturating_add(size_t *a, size_t b) 194 { 195 size_t s = *a + b; 196 /* Only works because size_t is unsigned. */ 197 *a = (s < b) ? SIZE_MAX : s; 198 } 199 200 static errno_t _write_bytes(const char *buf, size_t n, printf_spec_t *ps, 201 size_t *written_bytes) 202 { 203 errno_t rc = ps->write(buf, n, ps->data); 204 if (rc != EOK) 205 return rc; 206 207 _saturating_add(written_bytes, n); 208 return EOK; 209 } 210 211 /** Write one UTF-32 character. */ 212 static errno_t _write_uchar(char32_t ch, printf_spec_t *ps, 213 size_t *written_bytes) 214 { 215 char utf8[4]; 216 size_t offset = 0; 217 218 if (chr_encode(ch, utf8, &offset, sizeof(utf8)) == EOK) 219 return _write_bytes(utf8, offset, ps, written_bytes); 220 221 /* Invalid character. */ 222 return _write_bytes(_replacement, sizeof(_replacement) - 1, ps, written_bytes); 223 } 224 225 /** Write n UTF-32 characters. */ 226 static errno_t _write_chars(const char32_t *buf, size_t n, printf_spec_t *ps, 227 size_t *written_bytes) 228 { 229 for (size_t i = 0; i < n; i++) 230 TRY(_write_uchar(buf[i], ps, written_bytes)); 231 232 return EOK; 233 } 234 235 static errno_t _write_char(char c, printf_spec_t *ps, size_t *written_bytes) 236 { 237 return _write_bytes(&c, 1, ps, written_bytes); 238 } 239 240 static errno_t _write_spaces(size_t n, printf_spec_t *ps, size_t *written_bytes) 241 { 242 size_t max_spaces = sizeof(_spaces) - 1; 243 244 while (n > max_spaces) { 245 TRY(_write_bytes(_spaces, max_spaces, ps, written_bytes)); 246 n -= max_spaces; 247 } 248 249 return _write_bytes(_spaces, n, ps, written_bytes); 250 } 251 252 static errno_t _write_zeros(size_t n, printf_spec_t *ps, size_t *written_bytes) 253 { 254 size_t max_zeros = sizeof(_zeros) - 1; 255 256 while (n > max_zeros) { 257 TRY(_write_bytes(_zeros, max_zeros, ps, written_bytes)); 258 n -= max_zeros; 259 } 260 261 return _write_bytes(_zeros, n, ps, written_bytes); 211 262 } 212 263 … … 216 267 * @param width Width modifier. 217 268 * @param flags Flags that change the way the character is printed. 218 * 219 * @return Number of characters printed, negative value on failure. 220 * 221 */ 222 static int print_char(const char ch, int width, uint32_t flags, printf_spec_t *ps) 223 { 224 size_t counter = 0; 225 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) { 226 while (--width > 0) { 227 /* 228 * One space is consumed by the character itself, hence 229 * the predecrement. 230 */ 231 if (printf_putchar(' ', ps) > 0) 232 counter++; 233 } 234 } 235 236 if (printf_putchar(ch, ps) > 0) 237 counter++; 238 239 while (--width > 0) { 240 /* 241 * One space is consumed by the character itself, hence 242 * the predecrement. 243 */ 244 if (printf_putchar(' ', ps) > 0) 245 counter++; 246 } 247 248 return (int) (counter); 269 */ 270 static errno_t _format_char(const char c, size_t width, uint32_t flags, 271 printf_spec_t *ps, size_t *written_bytes) 272 { 273 size_t bytes = 1; 274 275 if (width <= bytes) 276 return _write_char(c, ps, written_bytes); 277 278 if (flags & __PRINTF_FLAG_LEFTALIGNED) { 279 TRY(_write_char(c, ps, written_bytes)); 280 TRY(_write_spaces(width - bytes, ps, written_bytes)); 281 } else { 282 TRY(_write_spaces(width - bytes, ps, written_bytes)); 283 TRY(_write_char(c, ps, written_bytes)); 284 } 285 286 return EOK; 249 287 } 250 288 … … 254 292 * @param width Width modifier. 255 293 * @param flags Flags that change the way the character is printed. 256 * 257 * @return Number of characters printed, negative value on failure. 258 * 259 */ 260 static int print_wchar(const char32_t ch, int width, uint32_t flags, printf_spec_t *ps) 261 { 262 size_t counter = 0; 263 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) { 264 while (--width > 0) { 265 /* 266 * One space is consumed by the character itself, hence 267 * the predecrement. 268 */ 269 if (printf_putchar(' ', ps) > 0) 270 counter++; 271 } 272 } 273 274 if (printf_putuchar(ch, ps) > 0) 275 counter++; 276 277 while (--width > 0) { 278 /* 279 * One space is consumed by the character itself, hence 280 * the predecrement. 281 */ 282 if (printf_putchar(' ', ps) > 0) 283 counter++; 284 } 285 286 return (int) (counter); 294 */ 295 static errno_t _format_uchar(const char32_t ch, size_t width, uint32_t flags, 296 printf_spec_t *ps, size_t *written_bytes) 297 { 298 /* 299 * All widths in printf() are specified in bytes. It might seem nonsensical 300 * with unicode text, but that's the way the function is defined. The width 301 * is barely useful if you want column alignment in terminal, but keep in 302 * mind that counting code points is only marginally better for that. 303 * Characters can span more than one unicode code point, even in languages 304 * based on latin alphabet, and a single unicode code point can occupy two 305 * spaces in east asian scripts. 306 * 307 * What the width can actually be useful for is padding, when you need the 308 * output to fill an exact number of bytes in a file. That use would break 309 * if we did our own thing here. 310 */ 311 312 size_t bytes = _utf8_bytes(ch); 313 314 if (width <= bytes) 315 return _write_uchar(ch, ps, written_bytes); 316 317 if (flags & __PRINTF_FLAG_LEFTALIGNED) { 318 TRY(_write_uchar(ch, ps, written_bytes)); 319 TRY(_write_spaces(width - bytes, ps, written_bytes)); 320 } else { 321 TRY(_write_spaces(width - bytes, ps, written_bytes)); 322 TRY(_write_uchar(ch, ps, written_bytes)); 323 } 324 325 return EOK; 287 326 } 288 327 … … 293 332 * @param precision Precision modifier. 294 333 * @param flags Flags that modify the way the string is printed. 295 * 296 * @return Number of characters printed, negative value on failure. 297 */ 298 static int print_str(char *str, int width, unsigned int precision, 299 uint32_t flags, printf_spec_t *ps) 334 */ 335 static errno_t _format_cstr(const char *str, size_t width, int precision, 336 uint32_t flags, printf_spec_t *ps, size_t *written_bytes) 300 337 { 301 338 if (str == NULL) 302 return printf_putstr(nullstr, ps); 303 304 size_t strw = str_length(str); 305 306 /* Precision unspecified - print everything. */ 307 if ((precision == 0) || (precision > strw)) 308 precision = strw; 309 310 /* Left padding */ 311 size_t counter = 0; 312 width -= precision; 313 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) { 314 while (width-- > 0) { 315 if (printf_putchar(' ', ps) == 1) 316 counter++; 317 } 318 } 319 320 /* Part of @a str fitting into the alloted space. */ 321 int retval; 322 size_t size = str_lsize(str, precision); 323 if ((retval = printf_putnchars(str, size, ps)) < 0) 324 return -counter; 325 326 counter += retval; 327 328 /* Right padding */ 329 while (width-- > 0) { 330 if (printf_putchar(' ', ps) == 1) 331 counter++; 332 } 333 334 return ((int) counter); 335 339 str = _nullstr; 340 341 /* Negative precision == unspecified. */ 342 size_t max_bytes = (precision < 0) ? SIZE_MAX : (size_t) precision; 343 size_t bytes = str_nsize(str, max_bytes); 344 345 if (width <= bytes) 346 return _write_bytes(str, bytes, ps, written_bytes); 347 348 if (flags & __PRINTF_FLAG_LEFTALIGNED) { 349 TRY(_write_bytes(str, bytes, ps, written_bytes)); 350 TRY(_write_spaces(width - bytes, ps, written_bytes)); 351 } else { 352 TRY(_write_spaces(width - bytes, ps, written_bytes)); 353 TRY(_write_bytes(str, bytes, ps, written_bytes)); 354 } 355 356 return EOK; 336 357 } 337 358 … … 342 363 * @param precision Precision modifier. 343 364 * @param flags Flags that modify the way the string is printed. 344 * 345 * @return Number of wide characters printed, negative value on failure. 346 */ 347 static int print_wstr(char32_t *str, int width, unsigned int precision, 348 uint32_t flags, printf_spec_t *ps) 349 { 350 if (str == NULL) 351 return printf_putstr(nullstr, ps); 352 353 size_t strw = wstr_length(str); 354 355 /* Precision not specified - print everything. */ 356 if ((precision == 0) || (precision > strw)) 357 precision = strw; 358 359 /* Left padding */ 360 size_t counter = 0; 361 width -= precision; 362 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) { 363 while (width-- > 0) { 364 if (printf_putchar(' ', ps) == 1) 365 counter++; 366 } 367 } 368 369 /* Part of @a wstr fitting into the alloted space. */ 370 int retval; 371 size_t size = wstr_lsize(str, precision); 372 if ((retval = printf_wputnchars(str, size, ps)) < 0) 373 return -counter; 374 375 counter += retval; 376 377 /* Right padding */ 378 while (width-- > 0) { 379 if (printf_putchar(' ', ps) == 1) 380 counter++; 381 } 382 383 return ((int) counter); 365 */ 366 static errno_t _format_wstr(char32_t *str, size_t width, int precision, 367 uint32_t flags, printf_spec_t *ps, size_t *written_bytes) 368 { 369 if (!str) 370 return _format_cstr(_nullstr, width, precision, flags, ps, written_bytes); 371 372 /* Width and precision are always byte-based. See _format_uchar() */ 373 /* Negative precision == unspecified. */ 374 size_t max_bytes = (precision < 0) ? SIZE_MAX : (size_t) precision; 375 376 size_t len; 377 size_t bytes = _utf8_wstr_bytes_len(str, max_bytes, &len); 378 379 if (width <= bytes) 380 return _write_chars(str, len, ps, written_bytes); 381 382 if (flags & __PRINTF_FLAG_LEFTALIGNED) { 383 TRY(_write_chars(str, len, ps, written_bytes)); 384 TRY(_write_spaces(width - bytes, ps, written_bytes)); 385 } else { 386 TRY(_write_spaces(width - bytes, ps, written_bytes)); 387 TRY(_write_chars(str, len, ps, written_bytes)); 388 } 389 390 return EOK; 391 } 392 393 static char _sign(uint32_t flags) 394 { 395 if (!(flags & __PRINTF_FLAG_SIGNED)) 396 return 0; 397 398 if (flags & __PRINTF_FLAG_NEGATIVE) 399 return '-'; 400 401 if (flags & __PRINTF_FLAG_SHOWPLUS) 402 return '+'; 403 404 if (flags & __PRINTF_FLAG_SPACESIGN) 405 return ' '; 406 407 return 0; 384 408 } 385 409 … … 393 417 * @param base Base to print the number in (must be between 2 and 16). 394 418 * @param flags Flags that modify the way the number is printed. 395 * 396 * @return Number of characters printed. 397 * 398 */ 399 static int print_number(uint64_t num, int width, int precision, int base, 400 uint32_t flags, printf_spec_t *ps) 401 { 402 /* Precision not specified. */ 403 if (precision < 0) { 404 precision = 0; 405 } 406 407 const char *digits; 408 if (flags & __PRINTF_FLAG_BIGCHARS) 409 digits = digits_big; 410 else 411 digits = digits_small; 412 413 char data[PRINT_NUMBER_BUFFER_SIZE]; 414 char *ptr = &data[PRINT_NUMBER_BUFFER_SIZE - 1]; 415 416 /* Size of number with all prefixes and signs */ 417 int size = 0; 418 419 /* Put zero at end of string */ 420 *ptr-- = 0; 421 422 if (num == 0) { 423 *ptr-- = '0'; 424 size++; 425 } else { 426 do { 427 *ptr-- = digits[num % base]; 428 size++; 429 } while (num /= base); 430 } 431 432 /* Size of plain number */ 433 int number_size = size; 434 435 /* 436 * Collect the sum of all prefixes/signs/etc. to calculate padding and 437 * leading zeroes. 438 */ 439 if (flags & __PRINTF_FLAG_PREFIX) { 440 switch (base) { 441 case 2: 442 /* Binary formating is not standard, but usefull */ 443 size += 2; 444 break; 445 case 8: 446 size++; 447 break; 448 case 16: 449 size += 2; 450 break; 451 } 452 } 453 454 char sgn = 0; 455 if (flags & __PRINTF_FLAG_SIGNED) { 456 if (flags & __PRINTF_FLAG_NEGATIVE) { 457 sgn = '-'; 458 size++; 459 } else if (flags & __PRINTF_FLAG_SHOWPLUS) { 460 sgn = '+'; 461 size++; 462 } else if (flags & __PRINTF_FLAG_SPACESIGN) { 463 sgn = ' '; 464 size++; 465 } 466 } 467 468 if (flags & __PRINTF_FLAG_LEFTALIGNED) 469 flags &= ~__PRINTF_FLAG_ZEROPADDED; 470 471 /* 472 * If the number is left-aligned or precision is specified then 473 * padding with zeros is ignored. 474 */ 475 if (flags & __PRINTF_FLAG_ZEROPADDED) { 476 if ((precision == 0) && (width > size)) 477 precision = width - size + number_size; 478 } 479 480 /* Print leading spaces */ 481 if (number_size > precision) { 482 /* Print the whole number, not only a part */ 483 precision = number_size; 484 } 485 486 width -= precision + size - number_size; 487 size_t counter = 0; 488 489 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) { 490 while (width-- > 0) { 491 if (printf_putchar(' ', ps) == 1) 492 counter++; 493 } 494 } 495 496 /* Print sign */ 497 if (sgn) { 498 if (printf_putchar(sgn, ps) == 1) 499 counter++; 500 } 501 502 /* Print prefix */ 503 if (flags & __PRINTF_FLAG_PREFIX) { 504 switch (base) { 505 case 2: 506 /* Binary formating is not standard, but useful */ 507 if (printf_putchar('0', ps) == 1) 508 counter++; 509 if (flags & __PRINTF_FLAG_BIGCHARS) { 510 if (printf_putchar('B', ps) == 1) 511 counter++; 512 } else { 513 if (printf_putchar('b', ps) == 1) 514 counter++; 515 } 516 break; 517 case 8: 518 if (printf_putchar('o', ps) == 1) 519 counter++; 520 break; 521 case 16: 522 if (printf_putchar('0', ps) == 1) 523 counter++; 524 if (flags & __PRINTF_FLAG_BIGCHARS) { 525 if (printf_putchar('X', ps) == 1) 526 counter++; 527 } else { 528 if (printf_putchar('x', ps) == 1) 529 counter++; 530 } 531 break; 532 } 533 } 534 535 /* Print leading zeroes */ 536 precision -= number_size; 537 while (precision-- > 0) { 538 if (printf_putchar('0', ps) == 1) 539 counter++; 540 } 541 542 /* Print the number itself */ 543 int retval; 544 if ((retval = printf_putstr(++ptr, ps)) > 0) 545 counter += retval; 546 547 /* Print trailing spaces */ 548 549 while (width-- > 0) { 550 if (printf_putchar(' ', ps) == 1) 551 counter++; 552 } 553 554 return ((int) counter); 419 */ 420 static errno_t _format_number(uint64_t num, size_t width, int precision, int base, 421 uint32_t flags, printf_spec_t *ps, size_t *written_bytes) 422 { 423 assert(base >= 2 && base <= 16); 424 425 /* Default precision for numeric output is 1. */ 426 size_t min_digits = (precision < 0) ? 1 : precision; 427 428 bool bigchars = flags & __PRINTF_FLAG_BIGCHARS; 429 bool prefix = flags & __PRINTF_FLAG_PREFIX; 430 bool left_aligned = flags & __PRINTF_FLAG_LEFTALIGNED; 431 bool zero_padded = flags & __PRINTF_FLAG_ZEROPADDED; 432 433 const char *digits = bigchars ? _digits_big : _digits_small; 434 435 char buffer[PRINT_NUMBER_BUFFER_SIZE]; 436 char *end = &buffer[PRINT_NUMBER_BUFFER_SIZE]; 437 438 /* Write number to the buffer. */ 439 int offset = 0; 440 while (num > 0) { 441 end[--offset] = digits[num % base]; 442 num /= base; 443 } 444 445 char *number = &end[offset]; 446 size_t number_len = end - number; 447 char sign = _sign(flags); 448 449 if (left_aligned) { 450 /* Space padded right-aligned. */ 451 size_t real_size = max(number_len, min_digits); 452 453 if (sign) { 454 TRY(_write_char(sign, ps, written_bytes)); 455 real_size++; 456 } 457 458 if (prefix && base == 2 && number_len > 0) { 459 TRY(_write_bytes(bigchars ? "0B" : "0b", 2, ps, written_bytes)); 460 real_size += 2; 461 } 462 463 if (prefix && base == 16 && number_len > 0) { 464 TRY(_write_bytes(bigchars ? "0X" : "0x", 2, ps, written_bytes)); 465 real_size += 2; 466 } 467 468 if (min_digits > number_len) { 469 TRY(_write_zeros(min_digits - number_len, ps, written_bytes)); 470 } else if (prefix && base == 8) { 471 TRY(_write_zeros(1, ps, written_bytes)); 472 real_size++; 473 } 474 475 TRY(_write_bytes(number, number_len, ps, written_bytes)); 476 477 if (width > real_size) 478 TRY(_write_spaces(width - real_size, ps, written_bytes)); 479 480 return EOK; 481 } 482 483 /* Zero padded number (ignored when left aligned or if precision is specified). */ 484 if (precision < 0 && zero_padded) { 485 size_t real_size = number_len; 486 487 if (sign) { 488 TRY(_write_char(sign, ps, written_bytes)); 489 real_size++; 490 } 491 492 if (prefix && base == 2 && number_len > 0) { 493 TRY(_write_bytes(bigchars ? "0B" : "0b", 2, ps, written_bytes)); 494 real_size += 2; 495 } 496 497 if (prefix && base == 16 && number_len > 0) { 498 TRY(_write_bytes(bigchars ? "0X" : "0x", 2, ps, written_bytes)); 499 real_size += 2; 500 } 501 502 if (width > real_size) 503 TRY(_write_zeros(width - real_size, ps, written_bytes)); 504 else if (number_len == 0 || (prefix && base == 8)) 505 TRY(_write_char('0', ps, written_bytes)); 506 507 return _write_bytes(number, number_len, ps, written_bytes); 508 } 509 510 /* Space padded right-aligned. */ 511 size_t real_size = max(number_len, min_digits); 512 if (sign) 513 real_size++; 514 515 if (prefix && (base == 2 || base == 16) && number_len > 0) 516 real_size += 2; 517 518 if (prefix && base == 8 && number_len >= min_digits) 519 real_size += 1; 520 521 if (width > real_size) 522 TRY(_write_spaces(width - real_size, ps, written_bytes)); 523 524 if (sign) 525 TRY(_write_char(sign, ps, written_bytes)); 526 527 if (prefix && base == 2 && number_len > 0) 528 TRY(_write_bytes(bigchars ? "0B" : "0b", 2, ps, written_bytes)); 529 530 if (prefix && base == 16 && number_len > 0) 531 TRY(_write_bytes(bigchars ? "0X" : "0x", 2, ps, written_bytes)); 532 533 if (min_digits > number_len) 534 TRY(_write_zeros(min_digits - number_len, ps, written_bytes)); 535 else if (prefix && base == 8) 536 TRY(_write_char('0', ps, written_bytes)); 537 538 return _write_bytes(number, number_len, ps, written_bytes); 555 539 } 556 540 … … 570 554 571 555 /** Returns the sign character or 0 if no sign should be printed. */ 572 static intget_sign_char(bool negative, uint32_t flags)556 static char _get_sign_char(bool negative, uint32_t flags) 573 557 { 574 558 if (negative) { … … 583 567 } 584 568 585 /** Prints count times character ch. */586 static int print_padding(char ch, int count, printf_spec_t *ps)587 {588 for (int i = 0; i < count; ++i) {589 if (ps->str_write(&ch, 1, ps->data) < 0) {590 return -1;591 }592 }593 594 return count;595 }596 597 569 /** Prints a special double (ie NaN, infinity) padded to width characters. */ 598 static int print_special(ieee_double_t val, int width, uint32_t flags,599 printf_spec_t *ps )570 static errno_t _format_special(ieee_double_t val, int width, uint32_t flags, 571 printf_spec_t *ps, size_t *written_bytes) 600 572 { 601 573 assert(val.is_special); 602 574 603 char sign = get_sign_char(val.is_negative, flags);575 char sign = _get_sign_char(val.is_negative, flags); 604 576 605 577 const int str_len = 3; … … 614 586 int padding_len = max(0, width - ((sign ? 1 : 0) + str_len)); 615 587 616 int counter = 0;617 int ret;618 619 588 /* Leading padding. */ 620 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) { 621 if ((ret = print_padding(' ', padding_len, ps)) < 0) 622 return -1; 623 624 counter += ret; 625 } 626 627 if (sign) { 628 if ((ret = ps->str_write(&sign, 1, ps->data)) < 0) 629 return -1; 630 631 counter += ret; 632 } 633 634 if ((ret = ps->str_write(str, str_len, ps->data)) < 0) 635 return -1; 636 637 counter += ret; 589 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) 590 TRY(_write_spaces(padding_len, ps, written_bytes)); 591 592 if (sign) 593 TRY(_write_char(sign, ps, written_bytes)); 594 595 TRY(_write_bytes(str, str_len, ps, written_bytes)); 638 596 639 597 /* Trailing padding. */ 640 if (flags & __PRINTF_FLAG_LEFTALIGNED) { 641 if ((ret = print_padding(' ', padding_len, ps)) < 0) 642 return -1; 643 644 counter += ret; 645 } 646 647 return counter; 598 if (flags & __PRINTF_FLAG_LEFTALIGNED) 599 TRY(_write_spaces(padding_len, ps, written_bytes)); 600 601 return EOK; 648 602 } 649 603 650 604 /** Trims trailing zeros but leaves a single "0" intact. */ 651 static void fp_trim_trailing_zeros(char *buf, int *len, int *dec_exp)605 static void _fp_trim_trailing_zeros(char *buf, int *len, int *dec_exp) 652 606 { 653 607 /* Cut the zero off by adjusting the exponent. */ … … 659 613 660 614 /** Textually round up the last digit thereby eliminating it. */ 661 static void fp_round_up(char *buf, int *len, int *dec_exp)615 static void _fp_round_up(char *buf, int *len, int *dec_exp) 662 616 { 663 617 assert(1 <= *len); … … 703 657 * to the %f specifier. 704 658 */ 705 static int print_double_str_fixed(double_str_t *val_str, int precision, int width,706 uint32_t flags, printf_spec_t *ps )659 static errno_t _format_double_str_fixed(double_str_t *val_str, int precision, int width, 660 uint32_t flags, printf_spec_t *ps, size_t *written_bytes) 707 661 { 708 662 int len = val_str->len; … … 717 671 int int_len = max(1, len + dec_exp); 718 672 719 char sign = get_sign_char(val_str->neg, flags);673 char sign = _get_sign_char(val_str->neg, flags); 720 674 721 675 /* Fractional portion lengths. */ … … 726 680 char *buf_frac = buf + len - signif_frac_figs; 727 681 728 if (flags & __PRINTF_FLAG_NOFRACZEROS) {682 if (flags & __PRINTF_FLAG_NOFRACZEROS) 729 683 trailing_frac_zeros = 0; 730 }731 684 732 685 int frac_len = leading_frac_zeros + signif_frac_figs + trailing_frac_zeros; … … 738 691 739 692 int padding_len = max(0, width - num_len); 740 int ret = 0;741 int counter = 0;742 693 743 694 /* Leading padding and sign. */ 744 695 745 if (!(flags & (__PRINTF_FLAG_LEFTALIGNED | __PRINTF_FLAG_ZEROPADDED))) { 746 if ((ret = print_padding(' ', padding_len, ps)) < 0) 747 return -1; 748 749 counter += ret; 750 } 751 752 if (sign) { 753 if ((ret = ps->str_write(&sign, 1, ps->data)) < 0) 754 return -1; 755 756 counter += ret; 757 } 758 759 if (flags & __PRINTF_FLAG_ZEROPADDED) { 760 if ((ret = print_padding('0', padding_len, ps)) < 0) 761 return -1; 762 763 counter += ret; 764 } 696 if (!(flags & (__PRINTF_FLAG_LEFTALIGNED | __PRINTF_FLAG_ZEROPADDED))) 697 TRY(_write_spaces(padding_len, ps, written_bytes)); 698 699 if (sign) 700 TRY(_write_char(sign, ps, written_bytes)); 701 702 if (flags & __PRINTF_FLAG_ZEROPADDED) 703 TRY(_write_zeros(padding_len, ps, written_bytes)); 765 704 766 705 /* Print the intergral part of the buffer. */ … … 769 708 770 709 if (0 < buf_int_len) { 771 if ((ret = ps->str_write(buf, buf_int_len, ps->data)) < 0) 772 return -1; 773 774 counter += ret; 710 TRY(_write_bytes(buf, buf_int_len, ps, written_bytes)); 775 711 776 712 /* Print trailing zeros of the integral part of the number. */ 777 if ((ret = print_padding('0', int_len - buf_int_len, ps)) < 0) 778 return -1; 713 TRY(_write_zeros(int_len - buf_int_len, ps, written_bytes)); 779 714 } else { 780 715 /* Single leading integer 0. */ 781 char ch = '0'; 782 if ((ret = ps->str_write(&ch, 1, ps->data)) < 0) 783 return -1; 784 } 785 786 counter += ret; 716 TRY(_write_char('0', ps, written_bytes)); 717 } 787 718 788 719 /* Print the decimal point and the fractional part. */ 789 720 if (has_decimal_pt) { 790 char ch = '.'; 791 792 if ((ret = ps->str_write(&ch, 1, ps->data)) < 0) 793 return -1; 794 795 counter += ret; 721 TRY(_write_char('.', ps, written_bytes)); 796 722 797 723 /* Print leading zeros of the fractional part of the number. */ 798 if ((ret = print_padding('0', leading_frac_zeros, ps)) < 0) 799 return -1; 800 801 counter += ret; 724 TRY(_write_zeros(leading_frac_zeros, ps, written_bytes)); 802 725 803 726 /* Print significant digits of the fractional part of the number. */ 804 if (0 < signif_frac_figs) { 805 if ((ret = ps->str_write(buf_frac, signif_frac_figs, ps->data)) < 0) 806 return -1; 807 808 counter += ret; 809 } 727 if (0 < signif_frac_figs) 728 TRY(_write_bytes(buf_frac, signif_frac_figs, ps, written_bytes)); 810 729 811 730 /* Print trailing zeros of the fractional part of the number. */ 812 if ((ret = print_padding('0', trailing_frac_zeros, ps)) < 0) 813 return -1; 814 815 counter += ret; 731 TRY(_write_zeros(trailing_frac_zeros, ps, written_bytes)); 816 732 } 817 733 818 734 /* Trailing padding. */ 819 if (flags & __PRINTF_FLAG_LEFTALIGNED) { 820 if ((ret = print_padding(' ', padding_len, ps)) < 0) 821 return -1; 822 823 counter += ret; 824 } 825 826 return counter; 735 if (flags & __PRINTF_FLAG_LEFTALIGNED) 736 TRY(_write_spaces(padding_len, ps, written_bytes)); 737 738 return EOK; 827 739 } 828 740 … … 837 749 * @param flags Printf flags. 838 750 * @param ps Printing functions. 839 * 840 * @return The number of characters printed; negative on failure. 841 */ 842 static int print_double_fixed(double g, int precision, int width, uint32_t flags, 843 printf_spec_t *ps) 751 */ 752 static errno_t _format_double_fixed(double g, int precision, int width, 753 uint32_t flags, printf_spec_t *ps, size_t *written_bytes) 844 754 { 845 755 if (flags & __PRINTF_FLAG_LEFTALIGNED) { … … 854 764 855 765 if (val.is_special) { 856 return print_special(val, width, flags, ps);766 return _format_special(val, width, flags, ps, written_bytes); 857 767 } 858 768 … … 877 787 * digit is definitely inaccurate so also round to get rid of it. 878 788 */ 879 fp_round_up(buf, &val_str.len, &val_str.dec_exp);789 _fp_round_up(buf, &val_str.len, &val_str.dec_exp); 880 790 881 791 /* Rounding could have introduced trailing zeros. */ 882 792 if (flags & __PRINTF_FLAG_NOFRACZEROS) { 883 fp_trim_trailing_zeros(buf, &val_str.len, &val_str.dec_exp);793 _fp_trim_trailing_zeros(buf, &val_str.len, &val_str.dec_exp); 884 794 } 885 795 } else { … … 891 801 } 892 802 893 return print_double_str_fixed(&val_str, precision, width, flags, ps);803 return _format_double_str_fixed(&val_str, precision, width, flags, ps, written_bytes); 894 804 } 895 805 896 806 /** Prints the decimal exponent part of a %e specifier formatted number. */ 897 static int print_exponent(int exp_val, uint32_t flags, printf_spec_t *ps) 898 { 899 int counter = 0; 900 int ret; 901 807 static errno_t _format_exponent(int exp_val, uint32_t flags, printf_spec_t *ps, 808 size_t *written_bytes) 809 { 902 810 char exp_ch = (flags & __PRINTF_FLAG_BIGCHARS) ? 'E' : 'e'; 903 904 if ((ret = ps->str_write(&exp_ch, 1, ps->data)) < 0) 905 return -1; 906 907 counter += ret; 811 TRY(_write_char(exp_ch, ps, written_bytes)); 908 812 909 813 char exp_sign = (exp_val < 0) ? '-' : '+'; 910 911 if ((ret = ps->str_write(&exp_sign, 1, ps->data)) < 0) 912 return -1; 913 914 counter += ret; 814 TRY(_write_char(exp_sign, ps, written_bytes)); 915 815 916 816 /* Print the exponent. */ … … 926 826 const char *exp_str_start = &exp_str[3] - exp_len; 927 827 928 if ((ret = ps->str_write(exp_str_start, exp_len, ps->data)) < 0) 929 return -1; 930 931 counter += ret; 932 933 return counter; 828 return _write_bytes(exp_str_start, exp_len, ps, written_bytes); 934 829 } 935 830 … … 937 832 * to the %e specifier. 938 833 */ 939 static int print_double_str_scient(double_str_t *val_str, int precision,940 int width, uint32_t flags, printf_spec_t *ps )834 static errno_t _format_double_str_scient(double_str_t *val_str, int precision, 835 int width, uint32_t flags, printf_spec_t *ps, size_t *written_bytes) 941 836 { 942 837 int len = val_str->len; … … 946 841 assert(0 < len); 947 842 948 char sign = get_sign_char(val_str->neg, flags);843 char sign = _get_sign_char(val_str->neg, flags); 949 844 bool has_decimal_pt = (0 < precision) || (flags & __PRINTF_FLAG_DECIMALPT); 950 845 int dec_pt_len = has_decimal_pt ? 1 : 0; … … 968 863 969 864 int padding_len = max(0, width - num_len); 970 int ret = 0; 971 int counter = 0; 972 973 if (!(flags & (__PRINTF_FLAG_LEFTALIGNED | __PRINTF_FLAG_ZEROPADDED))) { 974 if ((ret = print_padding(' ', padding_len, ps)) < 0) 975 return -1; 976 977 counter += ret; 978 } 979 980 if (sign) { 981 if ((ret = ps->str_write(&sign, 1, ps->data)) < 0) 982 return -1; 983 984 counter += ret; 985 } 986 987 if (flags & __PRINTF_FLAG_ZEROPADDED) { 988 if ((ret = print_padding('0', padding_len, ps)) < 0) 989 return -1; 990 991 counter += ret; 992 } 865 866 if (!(flags & (__PRINTF_FLAG_LEFTALIGNED | __PRINTF_FLAG_ZEROPADDED))) 867 TRY(_write_spaces(padding_len, ps, written_bytes)); 868 869 if (sign) 870 TRY(_write_char(sign, ps, written_bytes)); 871 872 if (flags & __PRINTF_FLAG_ZEROPADDED) 873 TRY(_write_zeros(padding_len, ps, written_bytes)); 993 874 994 875 /* Single leading integer. */ 995 if ((ret = ps->str_write(buf, 1, ps->data)) < 0) 996 return -1; 997 998 counter += ret; 876 TRY(_write_char(buf[0], ps, written_bytes)); 999 877 1000 878 /* Print the decimal point and the fractional part. */ 1001 879 if (has_decimal_pt) { 1002 char ch = '.'; 1003 1004 if ((ret = ps->str_write(&ch, 1, ps->data)) < 0) 1005 return -1; 1006 1007 counter += ret; 880 TRY(_write_char('.', ps, written_bytes)); 1008 881 1009 882 /* Print significant digits of the fractional part of the number. */ 1010 if (0 < signif_frac_figs) { 1011 if ((ret = ps->str_write(buf + 1, signif_frac_figs, ps->data)) < 0) 1012 return -1; 1013 1014 counter += ret; 1015 } 883 if (0 < signif_frac_figs) 884 TRY(_write_bytes(buf + 1, signif_frac_figs, ps, written_bytes)); 1016 885 1017 886 /* Print trailing zeros of the fractional part of the number. */ 1018 if ((ret = print_padding('0', trailing_frac_zeros, ps)) < 0) 1019 return -1; 1020 1021 counter += ret; 887 TRY(_write_zeros(trailing_frac_zeros, ps, written_bytes)); 1022 888 } 1023 889 1024 890 /* Print the exponent. */ 1025 if ((ret = print_exponent(exp_val, flags, ps)) < 0) 1026 return -1; 1027 1028 counter += ret; 1029 1030 if (flags & __PRINTF_FLAG_LEFTALIGNED) { 1031 if ((ret = print_padding(' ', padding_len, ps)) < 0) 1032 return -1; 1033 1034 counter += ret; 1035 } 1036 1037 return counter; 891 TRY(_format_exponent(exp_val, flags, ps, written_bytes)); 892 893 if (flags & __PRINTF_FLAG_LEFTALIGNED) 894 TRY(_write_spaces(padding_len, ps, written_bytes)); 895 896 return EOK; 1038 897 } 1039 898 … … 1057 916 * @param flags Printf flags. 1058 917 * @param ps Printing functions. 1059 * 1060 * @return The number of characters printed; negative on failure. 1061 */ 1062 static int print_double_scientific(double g, int precision, int width, 1063 uint32_t flags, printf_spec_t *ps) 1064 { 1065 if (flags & __PRINTF_FLAG_LEFTALIGNED) { 918 */ 919 static errno_t _format_double_scientific(double g, int precision, int width, 920 uint32_t flags, printf_spec_t *ps, size_t *written_bytes) 921 { 922 if (flags & __PRINTF_FLAG_LEFTALIGNED) 1066 923 flags &= ~__PRINTF_FLAG_ZEROPADDED; 1067 }1068 924 1069 925 ieee_double_t val = extract_ieee_double(g); 1070 926 1071 if (val.is_special) { 1072 return print_special(val, width, flags, ps); 1073 } 927 if (val.is_special) 928 return _format_special(val, width, flags, ps, written_bytes); 1074 929 1075 930 char buf[MAX_DOUBLE_STR_BUF_SIZE]; … … 1094 949 * digit is definitely inaccurate so also round to get rid of it. 1095 950 */ 1096 fp_round_up(buf, &val_str.len, &val_str.dec_exp);951 _fp_round_up(buf, &val_str.len, &val_str.dec_exp); 1097 952 1098 953 /* Rounding could have introduced trailing zeros. */ 1099 954 if (flags & __PRINTF_FLAG_NOFRACZEROS) { 1100 fp_trim_trailing_zeros(buf, &val_str.len, &val_str.dec_exp);955 _fp_trim_trailing_zeros(buf, &val_str.len, &val_str.dec_exp); 1101 956 } 1102 957 } else { … … 1108 963 } 1109 964 1110 return print_double_str_scient(&val_str, precision, width, flags, ps);965 return _format_double_str_scient(&val_str, precision, width, flags, ps, written_bytes); 1111 966 } 1112 967 … … 1126 981 * @return The number of characters printed; negative on failure. 1127 982 */ 1128 static int print_double_generic(double g, int precision, int width,1129 uint32_t flags, printf_spec_t *ps )983 static errno_t _format_double_generic(double g, int precision, int width, 984 uint32_t flags, printf_spec_t *ps, size_t *written_bytes) 1130 985 { 1131 986 ieee_double_t val = extract_ieee_double(g); 1132 987 1133 if (val.is_special) { 1134 return print_special(val, width, flags, ps); 1135 } 988 if (val.is_special) 989 return _format_special(val, width, flags, ps, written_bytes); 1136 990 1137 991 char buf[MAX_DOUBLE_STR_BUF_SIZE]; … … 1153 1007 if (-4 <= dec_exp && dec_exp < precision) { 1154 1008 precision = precision - (dec_exp + 1); 1155 return print_double_fixed(g, precision, width,1156 flags | __PRINTF_FLAG_NOFRACZEROS, ps );1009 return _format_double_fixed(g, precision, width, 1010 flags | __PRINTF_FLAG_NOFRACZEROS, ps, written_bytes); 1157 1011 } else { 1158 1012 --precision; 1159 return print_double_scientific(g, precision, width,1160 flags | __PRINTF_FLAG_NOFRACZEROS, ps );1013 return _format_double_scientific(g, precision, width, 1014 flags | __PRINTF_FLAG_NOFRACZEROS, ps, written_bytes); 1161 1015 } 1162 1016 } else { … … 1182 1036 /* Precision needed for the last significant digit. */ 1183 1037 precision = max(0, -val_str.dec_exp); 1184 return print_double_str_fixed(&val_str, precision, width, flags, ps);1038 return _format_double_str_fixed(&val_str, precision, width, flags, ps, written_bytes); 1185 1039 } else { 1186 1040 /* Use all produced digits. */ 1187 1041 precision = val_str.len - 1; 1188 return print_double_str_scient(&val_str, precision, width, flags, ps);1042 return _format_double_str_scient(&val_str, precision, width, flags, ps, written_bytes); 1189 1043 } 1190 1044 } … … 1207 1061 * @param flags Printf flags. 1208 1062 * @param ps Printing functions. 1209 * 1210 * @return The number of characters printed; negative on failure. 1211 */ 1212 static int print_double(double g, char spec, int precision, int width, 1213 uint32_t flags, printf_spec_t *ps) 1063 */ 1064 static errno_t _format_double(double g, char spec, int precision, int width, 1065 uint32_t flags, printf_spec_t *ps, size_t *written_chars) 1214 1066 { 1215 1067 switch (spec) { … … 1219 1071 case 'f': 1220 1072 precision = (precision < 0) ? 6 : precision; 1221 return print_double_fixed(g, precision, width, flags, ps);1073 return _format_double_fixed(g, precision, width, flags, ps, written_chars); 1222 1074 1223 1075 case 'E': … … 1226 1078 case 'e': 1227 1079 precision = (precision < 0) ? 6 : precision; 1228 return print_double_scientific(g, precision, width, flags, ps);1080 return _format_double_scientific(g, precision, width, flags, ps, written_chars); 1229 1081 1230 1082 case 'G': … … 1232 1084 /* Fallthrough */ 1233 1085 case 'g': 1234 return print_double_generic(g, precision, width, flags, ps);1086 return _format_double_generic(g, precision, width, flags, ps, written_chars); 1235 1087 1236 1088 default: … … 1241 1093 1242 1094 #endif 1095 1096 static const char *_strchrnul(const char *s, int c) 1097 { 1098 while (*s != c && *s != 0) 1099 s++; 1100 return s; 1101 } 1102 1103 /** Read a sequence of digits from the format string as a number. 1104 * If the number has too many digits to fit in int, returns INT_MAX. 1105 */ 1106 static int _read_num(const char *fmt, size_t *i) 1107 { 1108 const char *s; 1109 unsigned n = 0; 1110 1111 for (s = &fmt[*i]; isdigit(*s); s++) { 1112 unsigned digit = (*s - '0'); 1113 1114 /* Check for overflow */ 1115 if (n > INT_MAX / 10 || n * 10 > INT_MAX - digit) { 1116 n = INT_MAX; 1117 while (isdigit(*s)) 1118 s++; 1119 break; 1120 } 1121 1122 n = n * 10 + digit; 1123 } 1124 1125 *i = s - fmt; 1126 return n; 1127 } 1128 1129 static uint32_t _parse_flags(const char *fmt, size_t *i) 1130 { 1131 uint32_t flags = 0; 1132 1133 while (true) { 1134 switch (fmt[(*i)++]) { 1135 case '#': 1136 flags |= __PRINTF_FLAG_PREFIX; 1137 flags |= __PRINTF_FLAG_DECIMALPT; 1138 continue; 1139 case '-': 1140 flags |= __PRINTF_FLAG_LEFTALIGNED; 1141 continue; 1142 case '+': 1143 flags |= __PRINTF_FLAG_SHOWPLUS; 1144 continue; 1145 case ' ': 1146 flags |= __PRINTF_FLAG_SPACESIGN; 1147 continue; 1148 case '0': 1149 flags |= __PRINTF_FLAG_ZEROPADDED; 1150 continue; 1151 } 1152 1153 --*i; 1154 break; 1155 } 1156 1157 return flags; 1158 } 1159 1160 static bool _eat_char(const char *s, size_t *idx, int c) 1161 { 1162 if (s[*idx] != c) 1163 return false; 1164 1165 (*idx)++; 1166 return true; 1167 } 1168 1169 static qualifier_t _read_qualifier(const char *s, size_t *idx) 1170 { 1171 switch (s[(*idx)++]) { 1172 case 't': /* ptrdiff_t */ 1173 case 'z': /* size_t */ 1174 if (sizeof(ptrdiff_t) == sizeof(int)) 1175 return PrintfQualifierInt; 1176 else 1177 return PrintfQualifierLong; 1178 1179 case 'h': 1180 if (_eat_char(s, idx, 'h')) 1181 return PrintfQualifierByte; 1182 else 1183 return PrintfQualifierShort; 1184 1185 case 'l': 1186 if (_eat_char(s, idx, 'l')) 1187 return PrintfQualifierLongLong; 1188 else 1189 return PrintfQualifierLong; 1190 1191 case 'j': 1192 return PrintfQualifierLongLong; 1193 1194 default: 1195 --*idx; 1196 1197 /* Unspecified */ 1198 return PrintfQualifierInt; 1199 } 1200 } 1243 1201 1244 1202 /** Print formatted string. … … 1333 1291 int printf_core(const char *fmt, printf_spec_t *ps, va_list ap) 1334 1292 { 1335 size_t i; /* Index of the currently processed character from fmt */1293 errno_t rc = EOK; 1336 1294 size_t nxt = 0; /* Index of the next character from fmt */ 1337 size_t j = 0; /* Index to the first not printed nonformating character */1338 1295 1339 1296 size_t counter = 0; /* Number of characters printed */ 1340 int retval; /* Return values from nested functions */ 1341 1342 while (true) { 1343 i = nxt; 1344 char32_t uc = str_decode(fmt, &nxt, STR_NO_LIMIT); 1345 1346 if (uc == 0) 1347 break; 1348 1349 /* Control character */ 1350 if (uc == '%') { 1351 /* Print common characters if any processed */ 1352 if (i > j) { 1353 if ((retval = printf_putnchars(&fmt[j], i - j, ps)) < 0) { 1354 /* Error */ 1355 counter = -counter; 1356 goto out; 1357 } 1358 counter += retval; 1297 1298 while (rc == EOK) { 1299 /* Find the next specifier and write all the bytes before it. */ 1300 const char *s = _strchrnul(&fmt[nxt], '%'); 1301 size_t bytes = s - &fmt[nxt]; 1302 rc = _write_bytes(&fmt[nxt], bytes, ps, &counter); 1303 if (rc != EOK) 1304 break; 1305 1306 nxt += bytes; 1307 1308 /* Check for end of string. */ 1309 if (_eat_char(fmt, &nxt, 0)) 1310 break; 1311 1312 /* We must be at the start of a specifier. */ 1313 bool spec = _eat_char(fmt, &nxt, '%'); 1314 assert(spec); 1315 1316 /* Parse modifiers */ 1317 uint32_t flags = _parse_flags(fmt, &nxt); 1318 1319 /* Width & '*' operator */ 1320 int width = -1; 1321 if (_eat_char(fmt, &nxt, '*')) { 1322 /* Get width value from argument list */ 1323 width = va_arg(ap, int); 1324 1325 if (width < 0) { 1326 /* Negative width sets '-' flag */ 1327 width = (width == INT_MIN) ? INT_MAX : -width; 1328 flags |= __PRINTF_FLAG_LEFTALIGNED; 1359 1329 } 1360 1361 j = i; 1362 1363 /* Parse modifiers */ 1364 uint32_t flags = 0; 1365 bool end = false; 1366 1367 do { 1368 i = nxt; 1369 uc = str_decode(fmt, &nxt, STR_NO_LIMIT); 1370 switch (uc) { 1371 case '#': 1372 flags |= __PRINTF_FLAG_PREFIX; 1373 flags |= __PRINTF_FLAG_DECIMALPT; 1374 break; 1375 case '-': 1376 flags |= __PRINTF_FLAG_LEFTALIGNED; 1377 break; 1378 case '+': 1379 flags |= __PRINTF_FLAG_SHOWPLUS; 1380 break; 1381 case ' ': 1382 flags |= __PRINTF_FLAG_SPACESIGN; 1383 break; 1384 case '0': 1385 flags |= __PRINTF_FLAG_ZEROPADDED; 1386 break; 1387 default: 1388 end = true; 1389 } 1390 } while (!end); 1391 1392 /* Width & '*' operator */ 1393 int width = 0; 1394 if (isdigit(uc)) { 1395 while (true) { 1396 width *= 10; 1397 width += uc - '0'; 1398 1399 i = nxt; 1400 uc = str_decode(fmt, &nxt, STR_NO_LIMIT); 1401 if (uc == 0) 1402 break; 1403 if (!isdigit(uc)) 1404 break; 1405 } 1406 } else if (uc == '*') { 1407 /* Get width value from argument list */ 1408 i = nxt; 1409 uc = str_decode(fmt, &nxt, STR_NO_LIMIT); 1410 width = (int) va_arg(ap, int); 1411 if (width < 0) { 1412 /* Negative width sets '-' flag */ 1413 width *= -1; 1414 flags |= __PRINTF_FLAG_LEFTALIGNED; 1415 } 1330 } else { 1331 width = _read_num(fmt, &nxt); 1332 } 1333 1334 /* Precision and '*' operator */ 1335 int precision = -1; 1336 if (_eat_char(fmt, &nxt, '.')) { 1337 if (_eat_char(fmt, &nxt, '*')) { 1338 /* Get precision value from the argument list */ 1339 precision = va_arg(ap, int); 1340 1341 /* Negative is treated as omitted. */ 1342 if (precision < 0) 1343 precision = -1; 1344 } else { 1345 precision = _read_num(fmt, &nxt); 1416 1346 } 1417 1418 /* Precision and '*' operator */ 1419 int precision = -1; 1420 if (uc == '.') { 1421 i = nxt; 1422 uc = str_decode(fmt, &nxt, STR_NO_LIMIT); 1423 if (isdigit(uc)) { 1424 precision = 0; 1425 while (true) { 1426 precision *= 10; 1427 precision += uc - '0'; 1428 1429 i = nxt; 1430 uc = str_decode(fmt, &nxt, STR_NO_LIMIT); 1431 if (uc == 0) 1432 break; 1433 if (!isdigit(uc)) 1434 break; 1435 } 1436 } else if (uc == '*') { 1437 /* Get precision value from the argument list */ 1438 i = nxt; 1439 uc = str_decode(fmt, &nxt, STR_NO_LIMIT); 1440 precision = (int) va_arg(ap, int); 1441 if (precision < 0) { 1442 /* Ignore negative precision - use default instead */ 1443 precision = -1; 1444 } 1445 } 1446 } 1447 1448 qualifier_t qualifier; 1449 1450 switch (uc) { 1451 case 't': 1452 /* ptrdiff_t */ 1453 if (sizeof(ptrdiff_t) == sizeof(int32_t)) 1454 qualifier = PrintfQualifierInt; 1455 else 1456 qualifier = PrintfQualifierLongLong; 1457 i = nxt; 1458 uc = str_decode(fmt, &nxt, STR_NO_LIMIT); 1459 break; 1460 case 'h': 1461 /* Char or short */ 1462 qualifier = PrintfQualifierShort; 1463 i = nxt; 1464 uc = str_decode(fmt, &nxt, STR_NO_LIMIT); 1465 if (uc == 'h') { 1466 i = nxt; 1467 uc = str_decode(fmt, &nxt, STR_NO_LIMIT); 1468 qualifier = PrintfQualifierByte; 1469 } 1470 break; 1471 case 'l': 1472 /* Long or long long */ 1473 qualifier = PrintfQualifierLong; 1474 i = nxt; 1475 uc = str_decode(fmt, &nxt, STR_NO_LIMIT); 1476 if (uc == 'l') { 1477 i = nxt; 1478 uc = str_decode(fmt, &nxt, STR_NO_LIMIT); 1479 qualifier = PrintfQualifierLongLong; 1480 } 1481 break; 1482 case 'z': 1483 qualifier = PrintfQualifierSize; 1484 i = nxt; 1485 uc = str_decode(fmt, &nxt, STR_NO_LIMIT); 1486 break; 1487 case 'j': 1488 qualifier = PrintfQualifierMax; 1489 i = nxt; 1490 uc = str_decode(fmt, &nxt, STR_NO_LIMIT); 1491 break; 1492 default: 1493 /* Default type */ 1494 qualifier = PrintfQualifierInt; 1495 } 1496 1497 unsigned int base = 10; 1498 1499 switch (uc) { 1500 /* 1501 * String and character conversions. 1502 */ 1503 case 's': 1504 precision = max(0, precision); 1505 1506 if (qualifier == PrintfQualifierLong) 1507 retval = print_wstr(va_arg(ap, char32_t *), width, precision, flags, ps); 1508 else 1509 retval = print_str(va_arg(ap, char *), width, precision, flags, ps); 1510 1511 if (retval < 0) { 1512 counter = -counter; 1513 goto out; 1514 } 1515 1516 counter += retval; 1517 j = nxt; 1518 continue; 1519 case 'c': 1520 if (qualifier == PrintfQualifierLong) 1521 retval = print_wchar(va_arg(ap, wint_t), width, flags, ps); 1522 else 1523 retval = print_char(va_arg(ap, unsigned int), width, flags, ps); 1524 1525 if (retval < 0) { 1526 counter = -counter; 1527 goto out; 1528 } 1529 1530 counter += retval; 1531 j = nxt; 1532 continue; 1533 1347 } 1348 1349 qualifier_t qualifier = _read_qualifier(fmt, &nxt); 1350 unsigned int base = 10; 1351 char specifier = fmt[nxt++]; 1352 1353 switch (specifier) { 1354 /* 1355 * String and character conversions. 1356 */ 1357 case 's': 1358 if (qualifier == PrintfQualifierLong) 1359 rc = _format_wstr(va_arg(ap, char32_t *), width, precision, flags, ps, &counter); 1360 else 1361 rc = _format_cstr(va_arg(ap, char *), width, precision, flags, ps, &counter); 1362 continue; 1363 1364 case 'c': 1365 if (qualifier == PrintfQualifierLong) 1366 rc = _format_uchar(va_arg(ap, wint_t), width, flags, ps, &counter); 1367 else 1368 rc = _format_char(va_arg(ap, int), width, flags, ps, &counter); 1369 continue; 1370 1371 /* 1372 * Floating point values 1373 */ 1374 case 'G': 1375 case 'g': 1376 case 'F': 1377 case 'f': 1378 case 'E': 1379 case 'e':; 1534 1380 #ifdef HAS_FLOAT 1535 /* 1536 * Floating point values 1537 */ 1538 case 'G': 1539 case 'g': 1540 case 'F': 1541 case 'f': 1542 case 'E': 1543 case 'e': 1544 retval = print_double(va_arg(ap, double), uc, precision, 1545 width, flags, ps); 1546 1547 if (retval < 0) { 1548 counter = -counter; 1549 goto out; 1550 } 1551 1552 counter += retval; 1553 j = nxt; 1554 continue; 1381 rc = _format_double(va_arg(ap, double), specifier, precision, 1382 width, flags, ps, &counter); 1383 #else 1384 rc = _format_cstr("<float unsupported>", width, -1, 0, ps, &counter); 1555 1385 #endif 1556 1557 /* 1558 * Integer values 1559 */ 1560 case 'P': 1561 /* Pointer */ 1562 flags |= __PRINTF_FLAG_BIGCHARS; 1563 /* Fallthrough */ 1564 case 'p': 1565 flags |= __PRINTF_FLAG_PREFIX; 1566 flags |= __PRINTF_FLAG_ZEROPADDED; 1567 base = 16; 1568 qualifier = PrintfQualifierPointer; 1569 break; 1570 case 'b': 1571 base = 2; 1572 break; 1573 case 'o': 1574 base = 8; 1575 break; 1576 case 'd': 1577 case 'i': 1578 flags |= __PRINTF_FLAG_SIGNED; 1579 /* Fallthrough */ 1580 case 'u': 1581 break; 1582 case 'X': 1583 flags |= __PRINTF_FLAG_BIGCHARS; 1584 /* Fallthrough */ 1585 case 'x': 1586 base = 16; 1587 break; 1588 1589 case '%': 1590 /* Percentile itself */ 1591 j = i; 1592 continue; 1593 1594 /* 1595 * Bad formatting. 1596 */ 1597 default: 1598 /* 1599 * Unknown format. Now, j is the index of '%' 1600 * so we will print whole bad format sequence. 1601 */ 1602 continue; 1603 } 1604 1605 /* Print integers */ 1606 size_t size; 1607 uint64_t number; 1608 1609 switch (qualifier) { 1610 case PrintfQualifierByte: 1611 size = sizeof(unsigned char); 1612 number = PRINTF_GET_INT_ARGUMENT(int, ap, flags); 1613 break; 1614 case PrintfQualifierShort: 1615 size = sizeof(unsigned short); 1616 number = PRINTF_GET_INT_ARGUMENT(int, ap, flags); 1617 break; 1618 case PrintfQualifierInt: 1619 size = sizeof(unsigned int); 1620 number = PRINTF_GET_INT_ARGUMENT(int, ap, flags); 1621 break; 1622 case PrintfQualifierLong: 1623 size = sizeof(unsigned long); 1624 number = PRINTF_GET_INT_ARGUMENT(long, ap, flags); 1625 break; 1626 case PrintfQualifierLongLong: 1627 size = sizeof(unsigned long long); 1628 number = PRINTF_GET_INT_ARGUMENT(long long, ap, flags); 1629 break; 1630 case PrintfQualifierPointer: 1631 size = sizeof(void *); 1632 precision = size << 1; 1633 number = (uint64_t) (uintptr_t) va_arg(ap, void *); 1634 break; 1635 case PrintfQualifierSize: 1636 size = sizeof(size_t); 1637 number = (uint64_t) va_arg(ap, size_t); 1638 break; 1639 case PrintfQualifierMax: 1640 size = sizeof(uintmax_t); 1641 number = (uint64_t) va_arg(ap, uintmax_t); 1642 break; 1643 default: 1644 /* Unknown qualifier */ 1645 counter = -counter; 1646 goto out; 1647 } 1648 1649 if ((retval = print_number(number, width, precision, 1650 base, flags, ps)) < 0) { 1651 counter = -counter; 1652 goto out; 1653 } 1654 1655 counter += retval; 1656 j = nxt; 1657 } 1658 } 1659 1660 if (i > j) { 1661 if ((retval = printf_putnchars(&fmt[j], i - j, ps)) < 0) { 1662 /* Error */ 1663 counter = -counter; 1664 goto out; 1665 } 1666 counter += retval; 1667 } 1668 1669 out: 1670 return ((int) counter); 1386 continue; 1387 1388 /* 1389 * Integer values 1390 */ 1391 case 'P': 1392 /* Pointer */ 1393 flags |= __PRINTF_FLAG_BIGCHARS; 1394 /* Fallthrough */ 1395 case 'p': 1396 flags |= __PRINTF_FLAG_PREFIX; 1397 flags |= __PRINTF_FLAG_ZEROPADDED; 1398 base = 16; 1399 qualifier = PrintfQualifierPointer; 1400 break; 1401 case 'b': 1402 base = 2; 1403 break; 1404 case 'o': 1405 base = 8; 1406 break; 1407 case 'd': 1408 case 'i': 1409 flags |= __PRINTF_FLAG_SIGNED; 1410 break; 1411 case 'u': 1412 break; 1413 case 'X': 1414 flags |= __PRINTF_FLAG_BIGCHARS; 1415 /* Fallthrough */ 1416 case 'x': 1417 base = 16; 1418 break; 1419 1420 case '%': 1421 /* Percentile itself */ 1422 rc = _write_char('%', ps, &counter); 1423 continue; 1424 1425 /* 1426 * Bad formatting. 1427 */ 1428 default: 1429 rc = EINVAL; 1430 continue; 1431 } 1432 1433 /* Print integers */ 1434 uint64_t number; 1435 1436 switch (qualifier) { 1437 case PrintfQualifierByte: 1438 number = PRINTF_GET_INT_ARGUMENT(int, ap, flags); 1439 break; 1440 case PrintfQualifierShort: 1441 number = PRINTF_GET_INT_ARGUMENT(int, ap, flags); 1442 break; 1443 case PrintfQualifierInt: 1444 number = PRINTF_GET_INT_ARGUMENT(int, ap, flags); 1445 break; 1446 case PrintfQualifierLong: 1447 number = PRINTF_GET_INT_ARGUMENT(long, ap, flags); 1448 break; 1449 case PrintfQualifierLongLong: 1450 number = PRINTF_GET_INT_ARGUMENT(long long, ap, flags); 1451 break; 1452 case PrintfQualifierPointer: 1453 precision = sizeof(void *) << 1; 1454 number = (uint64_t) (uintptr_t) va_arg(ap, void *); 1455 break; 1456 default: 1457 /* Unknown qualifier */ 1458 rc = EINVAL; 1459 continue; 1460 } 1461 1462 rc = _format_number(number, width, precision, base, flags, ps, &counter); 1463 } 1464 1465 if (rc != EOK) { 1466 _set_errno(rc); 1467 return -1; 1468 } 1469 1470 if (counter > INT_MAX) { 1471 _set_errno(EOVERFLOW); 1472 return -1; 1473 } 1474 1475 return (int) counter; 1671 1476 } 1672 1477
Note:
See TracChangeset
for help on using the changeset viewer.