Changeset 97f6b71 in mainline
- Timestamp:
- 2025-04-13T18:21:02Z (3 weeks ago)
- Branches:
- master
- Children:
- 163e34c
- Parents:
- 28c39f3
- git-author:
- Jiří Zárevúcky <zarevucky.jiri@…> (2025-04-12 10:47:26)
- git-committer:
- Jiří Zárevúcky <zarevucky.jiri@…> (2025-04-13 18:21:02)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
common/printf/printf_core.c
r28c39f3 r97f6b71 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 int written = ps->str_write(buf, n, ps->data); 204 if (written < 0) 205 return EIO; 206 _saturating_add(written_bytes, n); 207 return EOK; 208 209 #if 0 210 errno_t rc = ps->write(buf, &n, ps->data); 211 _saturating_add(written_bytes, n); 212 return rc; 213 #endif 214 } 215 216 /** Write one UTF-32 character. */ 217 static errno_t _write_uchar(char32_t ch, printf_spec_t *ps, 218 size_t *written_bytes) 219 { 220 char utf8[4]; 221 size_t offset = 0; 222 223 if (chr_encode(ch, utf8, &offset, sizeof(utf8)) == EOK) 224 return _write_bytes(utf8, offset, ps, written_bytes); 225 226 /* Invalid character. */ 227 return _write_bytes(_replacement, sizeof(_replacement) - 1, ps, written_bytes); 228 } 229 230 /** Write n UTF-32 characters. */ 231 static errno_t _write_chars(const char32_t *buf, size_t n, printf_spec_t *ps, 232 size_t *written_bytes) 233 { 234 for (size_t i = 0; i < n; i++) 235 TRY(_write_uchar(buf[i], ps, written_bytes)); 236 237 return EOK; 238 } 239 240 static errno_t _write_char(char c, printf_spec_t *ps, size_t *written_bytes) 241 { 242 return _write_bytes(&c, 1, ps, written_bytes); 243 } 244 245 static errno_t _write_spaces(size_t n, printf_spec_t *ps, size_t *written_bytes) 246 { 247 size_t max_spaces = sizeof(_spaces) - 1; 248 249 while (n > max_spaces) { 250 TRY(_write_bytes(_spaces, max_spaces, ps, written_bytes)); 251 n -= max_spaces; 252 } 253 254 return _write_bytes(_spaces, n, ps, written_bytes); 255 } 256 257 static errno_t _write_zeros(size_t n, printf_spec_t *ps, size_t *written_bytes) 258 { 259 size_t max_zeros = sizeof(_zeros) - 1; 260 261 while (n > max_zeros) { 262 TRY(_write_bytes(_zeros, max_zeros, ps, written_bytes)); 263 n -= max_zeros; 264 } 265 266 return _write_bytes(_zeros, n, ps, written_bytes); 211 267 } 212 268 … … 216 272 * @param width Width modifier. 217 273 * @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); 274 */ 275 static errno_t _format_char(const char c, size_t width, uint32_t flags, 276 printf_spec_t *ps, size_t *written_bytes) 277 { 278 size_t bytes = 1; 279 280 if (width <= bytes) 281 return _write_char(c, ps, written_bytes); 282 283 if (flags & __PRINTF_FLAG_LEFTALIGNED) { 284 TRY(_write_char(c, ps, written_bytes)); 285 TRY(_write_spaces(width - bytes, ps, written_bytes)); 286 } else { 287 TRY(_write_spaces(width - bytes, ps, written_bytes)); 288 TRY(_write_char(c, ps, written_bytes)); 289 } 290 291 return EOK; 249 292 } 250 293 … … 254 297 * @param width Width modifier. 255 298 * @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); 299 */ 300 static errno_t _format_uchar(const char32_t ch, size_t width, uint32_t flags, 301 printf_spec_t *ps, size_t *written_bytes) 302 { 303 /* 304 * All widths in printf() are specified in bytes. It might seem nonsensical 305 * with unicode text, but that's the way the function is defined. The width 306 * is barely useful if you want column alignment in terminal, but keep in 307 * mind that counting code points is only marginally better for that. 308 * Characters can span more than one unicode code point, even in languages 309 * based on latin alphabet, and a single unicode code point can occupy two 310 * spaces in east asian scripts. 311 * 312 * What the width can actually be useful for is padding, when you need the 313 * output to fill an exact number of bytes in a file. That use would break 314 * if we did our own thing here. 315 */ 316 317 size_t bytes = _utf8_bytes(ch); 318 319 if (width <= bytes) 320 return _write_uchar(ch, ps, written_bytes); 321 322 if (flags & __PRINTF_FLAG_LEFTALIGNED) { 323 TRY(_write_uchar(ch, ps, written_bytes)); 324 TRY(_write_spaces(width - bytes, ps, written_bytes)); 325 } else { 326 TRY(_write_spaces(width - bytes, ps, written_bytes)); 327 TRY(_write_uchar(ch, ps, written_bytes)); 328 } 329 330 return EOK; 287 331 } 288 332 … … 293 337 * @param precision Precision modifier. 294 338 * @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) 339 */ 340 static errno_t _format_cstr(const char *str, size_t width, int precision, 341 uint32_t flags, printf_spec_t *ps, size_t *written_bytes) 300 342 { 301 343 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 344 str = _nullstr; 345 346 /* Negative precision == unspecified. */ 347 size_t max_bytes = (precision < 0) ? SIZE_MAX : (size_t) precision; 348 size_t bytes = str_nsize(str, max_bytes); 349 350 if (width <= bytes) 351 return _write_bytes(str, bytes, ps, written_bytes); 352 353 if (flags & __PRINTF_FLAG_LEFTALIGNED) { 354 TRY(_write_bytes(str, bytes, ps, written_bytes)); 355 TRY(_write_spaces(width - bytes, ps, written_bytes)); 356 } else { 357 TRY(_write_spaces(width - bytes, ps, written_bytes)); 358 TRY(_write_bytes(str, bytes, ps, written_bytes)); 359 } 360 361 return EOK; 336 362 } 337 363 … … 342 368 * @param precision Precision modifier. 343 369 * @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); 370 */ 371 static errno_t _format_wstr(char32_t *str, size_t width, int precision, 372 uint32_t flags, printf_spec_t *ps, size_t *written_bytes) 373 { 374 if (!str) 375 return _format_cstr(_nullstr, width, precision, flags, ps, written_bytes); 376 377 /* Width and precision are always byte-based. See _format_uchar() */ 378 /* Negative precision == unspecified. */ 379 size_t max_bytes = (precision < 0) ? SIZE_MAX : (size_t) precision; 380 381 size_t len; 382 size_t bytes = _utf8_wstr_bytes_len(str, max_bytes, &len); 383 384 if (width <= bytes) 385 return _write_chars(str, len, ps, written_bytes); 386 387 if (flags & __PRINTF_FLAG_LEFTALIGNED) { 388 TRY(_write_chars(str, len, ps, written_bytes)); 389 TRY(_write_spaces(width - bytes, ps, written_bytes)); 390 } else { 391 TRY(_write_spaces(width - bytes, ps, written_bytes)); 392 TRY(_write_chars(str, len, ps, written_bytes)); 393 } 394 395 return EOK; 396 } 397 398 static char _sign(uint32_t flags) 399 { 400 if (!(flags & __PRINTF_FLAG_SIGNED)) 401 return 0; 402 403 if (flags & __PRINTF_FLAG_NEGATIVE) 404 return '-'; 405 406 if (flags & __PRINTF_FLAG_SHOWPLUS) 407 return '+'; 408 409 if (flags & __PRINTF_FLAG_SPACESIGN) 410 return ' '; 411 412 return 0; 384 413 } 385 414 … … 393 422 * @param base Base to print the number in (must be between 2 and 16). 394 423 * @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); 424 */ 425 static errno_t _format_number(uint64_t num, size_t width, int precision, int base, 426 uint32_t flags, printf_spec_t *ps, size_t *written_bytes) 427 { 428 assert(base >= 2 && base <= 16); 429 430 /* Default precision for numeric output is 1. */ 431 size_t min_digits = (precision < 0) ? 1 : precision; 432 433 bool bigchars = flags & __PRINTF_FLAG_BIGCHARS; 434 bool prefix = flags & __PRINTF_FLAG_PREFIX; 435 bool left_aligned = flags & __PRINTF_FLAG_LEFTALIGNED; 436 bool zero_padded = flags & __PRINTF_FLAG_ZEROPADDED; 437 438 const char *digits = bigchars ? _digits_big : _digits_small; 439 440 char buffer[PRINT_NUMBER_BUFFER_SIZE]; 441 char *end = &buffer[PRINT_NUMBER_BUFFER_SIZE]; 442 443 /* Write number to the buffer. */ 444 int offset = 0; 445 while (num > 0) { 446 end[--offset] = digits[num % base]; 447 num /= base; 448 } 449 450 char *number = &end[offset]; 451 size_t number_len = end - number; 452 char sign = _sign(flags); 453 454 if (left_aligned) { 455 /* Space padded right-aligned. */ 456 size_t real_size = max(number_len, min_digits); 457 458 if (sign) { 459 TRY(_write_char(sign, ps, written_bytes)); 460 real_size++; 461 } 462 463 if (prefix && base == 2 && number_len > 0) { 464 TRY(_write_bytes(bigchars ? "0B" : "0b", 2, ps, written_bytes)); 465 real_size += 2; 466 } 467 468 if (prefix && base == 16 && number_len > 0) { 469 TRY(_write_bytes(bigchars ? "0X" : "0x", 2, ps, written_bytes)); 470 real_size += 2; 471 } 472 473 if (min_digits > number_len) { 474 TRY(_write_zeros(min_digits - number_len, ps, written_bytes)); 475 } else if (prefix && base == 8) { 476 TRY(_write_zeros(1, ps, written_bytes)); 477 real_size++; 478 } 479 480 TRY(_write_bytes(number, number_len, ps, written_bytes)); 481 482 if (width > real_size) 483 TRY(_write_spaces(width - real_size, ps, written_bytes)); 484 485 return EOK; 486 } 487 488 /* Zero padded number (ignored when left aligned or if precision is specified). */ 489 if (precision < 0 && zero_padded) { 490 size_t real_size = number_len; 491 492 if (sign) { 493 TRY(_write_char(sign, ps, written_bytes)); 494 real_size++; 495 } 496 497 if (prefix && base == 2 && number_len > 0) { 498 TRY(_write_bytes(bigchars ? "0B" : "0b", 2, ps, written_bytes)); 499 real_size += 2; 500 } 501 502 if (prefix && base == 16 && number_len > 0) { 503 TRY(_write_bytes(bigchars ? "0X" : "0x", 2, ps, written_bytes)); 504 real_size += 2; 505 } 506 507 if (width > real_size) 508 TRY(_write_zeros(width - real_size, ps, written_bytes)); 509 else if (number_len == 0 || (prefix && base == 8)) 510 TRY(_write_char('0', ps, written_bytes)); 511 512 return _write_bytes(number, number_len, ps, written_bytes); 513 } 514 515 /* Space padded right-aligned. */ 516 size_t real_size = max(number_len, min_digits); 517 if (sign) 518 real_size++; 519 520 if (prefix && (base == 2 || base == 16) && number_len > 0) 521 real_size += 2; 522 523 if (prefix && base == 8 && number_len >= min_digits) 524 real_size += 1; 525 526 if (width > real_size) 527 TRY(_write_spaces(width - real_size, ps, written_bytes)); 528 529 if (sign) 530 TRY(_write_char(sign, ps, written_bytes)); 531 532 if (prefix && base == 2 && number_len > 0) 533 TRY(_write_bytes(bigchars ? "0B" : "0b", 2, ps, written_bytes)); 534 535 if (prefix && base == 16 && number_len > 0) 536 TRY(_write_bytes(bigchars ? "0X" : "0x", 2, ps, written_bytes)); 537 538 if (min_digits > number_len) 539 TRY(_write_zeros(min_digits - number_len, ps, written_bytes)); 540 else if (prefix && base == 8) 541 TRY(_write_char('0', ps, written_bytes)); 542 543 return _write_bytes(number, number_len, ps, written_bytes); 555 544 } 556 545 … … 570 559 571 560 /** Returns the sign character or 0 if no sign should be printed. */ 572 static intget_sign_char(bool negative, uint32_t flags)561 static char _get_sign_char(bool negative, uint32_t flags) 573 562 { 574 563 if (negative) { … … 583 572 } 584 573 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 574 /** 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 )575 static errno_t _format_special(ieee_double_t val, int width, uint32_t flags, 576 printf_spec_t *ps, size_t *written_bytes) 600 577 { 601 578 assert(val.is_special); 602 579 603 char sign = get_sign_char(val.is_negative, flags);580 char sign = _get_sign_char(val.is_negative, flags); 604 581 605 582 const int str_len = 3; … … 614 591 int padding_len = max(0, width - ((sign ? 1 : 0) + str_len)); 615 592 616 int counter = 0;617 int ret;618 619 593 /* 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; 594 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) 595 TRY(_write_spaces(padding_len, ps, written_bytes)); 596 597 if (sign) 598 TRY(_write_char(sign, ps, written_bytes)); 599 600 TRY(_write_bytes(str, str_len, ps, written_bytes)); 638 601 639 602 /* 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; 603 if (flags & __PRINTF_FLAG_LEFTALIGNED) 604 TRY(_write_spaces(padding_len, ps, written_bytes)); 605 606 return EOK; 648 607 } 649 608 650 609 /** Trims trailing zeros but leaves a single "0" intact. */ 651 static void fp_trim_trailing_zeros(char *buf, int *len, int *dec_exp)610 static void _fp_trim_trailing_zeros(char *buf, int *len, int *dec_exp) 652 611 { 653 612 /* Cut the zero off by adjusting the exponent. */ … … 659 618 660 619 /** Textually round up the last digit thereby eliminating it. */ 661 static void fp_round_up(char *buf, int *len, int *dec_exp)620 static void _fp_round_up(char *buf, int *len, int *dec_exp) 662 621 { 663 622 assert(1 <= *len); … … 703 662 * to the %f specifier. 704 663 */ 705 static int print_double_str_fixed(double_str_t *val_str, int precision, int width,706 uint32_t flags, printf_spec_t *ps )664 static errno_t _format_double_str_fixed(double_str_t *val_str, int precision, int width, 665 uint32_t flags, printf_spec_t *ps, size_t *written_bytes) 707 666 { 708 667 int len = val_str->len; … … 717 676 int int_len = max(1, len + dec_exp); 718 677 719 char sign = get_sign_char(val_str->neg, flags);678 char sign = _get_sign_char(val_str->neg, flags); 720 679 721 680 /* Fractional portion lengths. */ … … 726 685 char *buf_frac = buf + len - signif_frac_figs; 727 686 728 if (flags & __PRINTF_FLAG_NOFRACZEROS) {687 if (flags & __PRINTF_FLAG_NOFRACZEROS) 729 688 trailing_frac_zeros = 0; 730 }731 689 732 690 int frac_len = leading_frac_zeros + signif_frac_figs + trailing_frac_zeros; … … 738 696 739 697 int padding_len = max(0, width - num_len); 740 int ret = 0;741 int counter = 0;742 698 743 699 /* Leading padding and sign. */ 744 700 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 } 701 if (!(flags & (__PRINTF_FLAG_LEFTALIGNED | __PRINTF_FLAG_ZEROPADDED))) 702 TRY(_write_spaces(padding_len, ps, written_bytes)); 703 704 if (sign) 705 TRY(_write_char(sign, ps, written_bytes)); 706 707 if (flags & __PRINTF_FLAG_ZEROPADDED) 708 TRY(_write_zeros(padding_len, ps, written_bytes)); 765 709 766 710 /* Print the intergral part of the buffer. */ … … 769 713 770 714 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; 715 TRY(_write_bytes(buf, buf_int_len, ps, written_bytes)); 775 716 776 717 /* 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; 718 TRY(_write_zeros(int_len - buf_int_len, ps, written_bytes)); 779 719 } else { 780 720 /* 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; 721 TRY(_write_char('0', ps, written_bytes)); 722 } 787 723 788 724 /* Print the decimal point and the fractional part. */ 789 725 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; 726 TRY(_write_char('.', ps, written_bytes)); 796 727 797 728 /* 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; 729 TRY(_write_zeros(leading_frac_zeros, ps, written_bytes)); 802 730 803 731 /* 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 } 732 if (0 < signif_frac_figs) 733 TRY(_write_bytes(buf_frac, signif_frac_figs, ps, written_bytes)); 810 734 811 735 /* 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; 736 TRY(_write_zeros(trailing_frac_zeros, ps, written_bytes)); 816 737 } 817 738 818 739 /* 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; 740 if (flags & __PRINTF_FLAG_LEFTALIGNED) 741 TRY(_write_spaces(padding_len, ps, written_bytes)); 742 743 return EOK; 827 744 } 828 745 … … 837 754 * @param flags Printf flags. 838 755 * @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) 756 */ 757 static errno_t _format_double_fixed(double g, int precision, int width, 758 uint32_t flags, printf_spec_t *ps, size_t *written_bytes) 844 759 { 845 760 if (flags & __PRINTF_FLAG_LEFTALIGNED) { … … 854 769 855 770 if (val.is_special) { 856 return print_special(val, width, flags, ps);771 return _format_special(val, width, flags, ps, written_bytes); 857 772 } 858 773 … … 877 792 * digit is definitely inaccurate so also round to get rid of it. 878 793 */ 879 fp_round_up(buf, &val_str.len, &val_str.dec_exp);794 _fp_round_up(buf, &val_str.len, &val_str.dec_exp); 880 795 881 796 /* Rounding could have introduced trailing zeros. */ 882 797 if (flags & __PRINTF_FLAG_NOFRACZEROS) { 883 fp_trim_trailing_zeros(buf, &val_str.len, &val_str.dec_exp);798 _fp_trim_trailing_zeros(buf, &val_str.len, &val_str.dec_exp); 884 799 } 885 800 } else { … … 891 806 } 892 807 893 return print_double_str_fixed(&val_str, precision, width, flags, ps);808 return _format_double_str_fixed(&val_str, precision, width, flags, ps, written_bytes); 894 809 } 895 810 896 811 /** 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 812 static errno_t _format_exponent(int exp_val, uint32_t flags, printf_spec_t *ps, 813 size_t *written_bytes) 814 { 902 815 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; 816 TRY(_write_char(exp_ch, ps, written_bytes)); 908 817 909 818 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; 819 TRY(_write_char(exp_sign, ps, written_bytes)); 915 820 916 821 /* Print the exponent. */ … … 926 831 const char *exp_str_start = &exp_str[3] - exp_len; 927 832 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; 833 return _write_bytes(exp_str_start, exp_len, ps, written_bytes); 934 834 } 935 835 … … 937 837 * to the %e specifier. 938 838 */ 939 static int print_double_str_scient(double_str_t *val_str, int precision,940 int width, uint32_t flags, printf_spec_t *ps )839 static errno_t _format_double_str_scient(double_str_t *val_str, int precision, 840 int width, uint32_t flags, printf_spec_t *ps, size_t *written_bytes) 941 841 { 942 842 int len = val_str->len; … … 946 846 assert(0 < len); 947 847 948 char sign = get_sign_char(val_str->neg, flags);848 char sign = _get_sign_char(val_str->neg, flags); 949 849 bool has_decimal_pt = (0 < precision) || (flags & __PRINTF_FLAG_DECIMALPT); 950 850 int dec_pt_len = has_decimal_pt ? 1 : 0; … … 968 868 969 869 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 } 870 871 if (!(flags & (__PRINTF_FLAG_LEFTALIGNED | __PRINTF_FLAG_ZEROPADDED))) 872 TRY(_write_spaces(padding_len, ps, written_bytes)); 873 874 if (sign) 875 TRY(_write_char(sign, ps, written_bytes)); 876 877 if (flags & __PRINTF_FLAG_ZEROPADDED) 878 TRY(_write_zeros(padding_len, ps, written_bytes)); 993 879 994 880 /* Single leading integer. */ 995 if ((ret = ps->str_write(buf, 1, ps->data)) < 0) 996 return -1; 997 998 counter += ret; 881 TRY(_write_char(buf[0], ps, written_bytes)); 999 882 1000 883 /* Print the decimal point and the fractional part. */ 1001 884 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; 885 TRY(_write_char('.', ps, written_bytes)); 1008 886 1009 887 /* 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 } 888 if (0 < signif_frac_figs) 889 TRY(_write_bytes(buf + 1, signif_frac_figs, ps, written_bytes)); 1016 890 1017 891 /* 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; 892 TRY(_write_zeros(trailing_frac_zeros, ps, written_bytes)); 1022 893 } 1023 894 1024 895 /* 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; 896 TRY(_format_exponent(exp_val, flags, ps, written_bytes)); 897 898 if (flags & __PRINTF_FLAG_LEFTALIGNED) 899 TRY(_write_spaces(padding_len, ps, written_bytes)); 900 901 return EOK; 1038 902 } 1039 903 … … 1057 921 * @param flags Printf flags. 1058 922 * @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) { 923 */ 924 static errno_t _format_double_scientific(double g, int precision, int width, 925 uint32_t flags, printf_spec_t *ps, size_t *written_bytes) 926 { 927 if (flags & __PRINTF_FLAG_LEFTALIGNED) 1066 928 flags &= ~__PRINTF_FLAG_ZEROPADDED; 1067 }1068 929 1069 930 ieee_double_t val = extract_ieee_double(g); 1070 931 1071 if (val.is_special) { 1072 return print_special(val, width, flags, ps); 1073 } 932 if (val.is_special) 933 return _format_special(val, width, flags, ps, written_bytes); 1074 934 1075 935 char buf[MAX_DOUBLE_STR_BUF_SIZE]; … … 1094 954 * digit is definitely inaccurate so also round to get rid of it. 1095 955 */ 1096 fp_round_up(buf, &val_str.len, &val_str.dec_exp);956 _fp_round_up(buf, &val_str.len, &val_str.dec_exp); 1097 957 1098 958 /* Rounding could have introduced trailing zeros. */ 1099 959 if (flags & __PRINTF_FLAG_NOFRACZEROS) { 1100 fp_trim_trailing_zeros(buf, &val_str.len, &val_str.dec_exp);960 _fp_trim_trailing_zeros(buf, &val_str.len, &val_str.dec_exp); 1101 961 } 1102 962 } else { … … 1108 968 } 1109 969 1110 return print_double_str_scient(&val_str, precision, width, flags, ps);970 return _format_double_str_scient(&val_str, precision, width, flags, ps, written_bytes); 1111 971 } 1112 972 … … 1126 986 * @return The number of characters printed; negative on failure. 1127 987 */ 1128 static int print_double_generic(double g, int precision, int width,1129 uint32_t flags, printf_spec_t *ps )988 static errno_t _format_double_generic(double g, int precision, int width, 989 uint32_t flags, printf_spec_t *ps, size_t *written_bytes) 1130 990 { 1131 991 ieee_double_t val = extract_ieee_double(g); 1132 992 1133 if (val.is_special) { 1134 return print_special(val, width, flags, ps); 1135 } 993 if (val.is_special) 994 return _format_special(val, width, flags, ps, written_bytes); 1136 995 1137 996 char buf[MAX_DOUBLE_STR_BUF_SIZE]; … … 1153 1012 if (-4 <= dec_exp && dec_exp < precision) { 1154 1013 precision = precision - (dec_exp + 1); 1155 return print_double_fixed(g, precision, width,1156 flags | __PRINTF_FLAG_NOFRACZEROS, ps );1014 return _format_double_fixed(g, precision, width, 1015 flags | __PRINTF_FLAG_NOFRACZEROS, ps, written_bytes); 1157 1016 } else { 1158 1017 --precision; 1159 return print_double_scientific(g, precision, width,1160 flags | __PRINTF_FLAG_NOFRACZEROS, ps );1018 return _format_double_scientific(g, precision, width, 1019 flags | __PRINTF_FLAG_NOFRACZEROS, ps, written_bytes); 1161 1020 } 1162 1021 } else { … … 1182 1041 /* Precision needed for the last significant digit. */ 1183 1042 precision = max(0, -val_str.dec_exp); 1184 return print_double_str_fixed(&val_str, precision, width, flags, ps);1043 return _format_double_str_fixed(&val_str, precision, width, flags, ps, written_bytes); 1185 1044 } else { 1186 1045 /* Use all produced digits. */ 1187 1046 precision = val_str.len - 1; 1188 return print_double_str_scient(&val_str, precision, width, flags, ps);1047 return _format_double_str_scient(&val_str, precision, width, flags, ps, written_bytes); 1189 1048 } 1190 1049 } … … 1207 1066 * @param flags Printf flags. 1208 1067 * @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) 1068 */ 1069 static errno_t _format_double(double g, char spec, int precision, int width, 1070 uint32_t flags, printf_spec_t *ps, size_t *written_chars) 1214 1071 { 1215 1072 switch (spec) { … … 1219 1076 case 'f': 1220 1077 precision = (precision < 0) ? 6 : precision; 1221 return print_double_fixed(g, precision, width, flags, ps);1078 return _format_double_fixed(g, precision, width, flags, ps, written_chars); 1222 1079 1223 1080 case 'E': … … 1226 1083 case 'e': 1227 1084 precision = (precision < 0) ? 6 : precision; 1228 return print_double_scientific(g, precision, width, flags, ps);1085 return _format_double_scientific(g, precision, width, flags, ps, written_chars); 1229 1086 1230 1087 case 'G': … … 1232 1089 /* Fallthrough */ 1233 1090 case 'g': 1234 return print_double_generic(g, precision, width, flags, ps);1091 return _format_double_generic(g, precision, width, flags, ps, written_chars); 1235 1092 1236 1093 default: … … 1241 1098 1242 1099 #endif 1100 1101 static const char *_strchrnul(const char *s, int c) 1102 { 1103 while (*s != c && *s != 0) 1104 s++; 1105 return s; 1106 } 1107 1108 /** Read a sequence of digits from the format string as a number. 1109 * If the number has too many digits to fit in int, returns INT_MAX. 1110 */ 1111 static int _read_num(const char *fmt, size_t *i) 1112 { 1113 const char *s; 1114 unsigned n = 0; 1115 1116 for (s = &fmt[*i]; isdigit(*s); s++) { 1117 unsigned digit = (*s - '0'); 1118 1119 /* Check for overflow */ 1120 if (n > INT_MAX / 10 || n * 10 > INT_MAX - digit) { 1121 n = INT_MAX; 1122 while (isdigit(*s)) 1123 s++; 1124 break; 1125 } 1126 1127 n = n * 10 + digit; 1128 } 1129 1130 *i = s - fmt; 1131 return n; 1132 } 1133 1134 static uint32_t _parse_flags(const char *fmt, size_t *i) 1135 { 1136 uint32_t flags = 0; 1137 1138 while (true) { 1139 switch (fmt[(*i)++]) { 1140 case '#': 1141 flags |= __PRINTF_FLAG_PREFIX; 1142 flags |= __PRINTF_FLAG_DECIMALPT; 1143 continue; 1144 case '-': 1145 flags |= __PRINTF_FLAG_LEFTALIGNED; 1146 continue; 1147 case '+': 1148 flags |= __PRINTF_FLAG_SHOWPLUS; 1149 continue; 1150 case ' ': 1151 flags |= __PRINTF_FLAG_SPACESIGN; 1152 continue; 1153 case '0': 1154 flags |= __PRINTF_FLAG_ZEROPADDED; 1155 continue; 1156 } 1157 1158 --*i; 1159 break; 1160 } 1161 1162 return flags; 1163 } 1164 1165 static bool _eat_char(const char *s, size_t *idx, int c) 1166 { 1167 if (s[*idx] != c) 1168 return false; 1169 1170 (*idx)++; 1171 return true; 1172 } 1173 1174 static qualifier_t _read_qualifier(const char *s, size_t *idx) 1175 { 1176 switch (s[(*idx)++]) { 1177 case 't': /* ptrdiff_t */ 1178 case 'z': /* size_t */ 1179 if (sizeof(ptrdiff_t) == sizeof(int)) 1180 return PrintfQualifierInt; 1181 else 1182 return PrintfQualifierLong; 1183 1184 case 'h': 1185 if (_eat_char(s, idx, 'h')) 1186 return PrintfQualifierByte; 1187 else 1188 return PrintfQualifierShort; 1189 1190 case 'l': 1191 if (_eat_char(s, idx, 'l')) 1192 return PrintfQualifierLongLong; 1193 else 1194 return PrintfQualifierLong; 1195 1196 case 'j': 1197 return PrintfQualifierLongLong; 1198 1199 default: 1200 --*idx; 1201 1202 /* Unspecified */ 1203 return PrintfQualifierInt; 1204 } 1205 } 1243 1206 1244 1207 /** Print formatted string. … … 1333 1296 int printf_core(const char *fmt, printf_spec_t *ps, va_list ap) 1334 1297 { 1335 size_t i; /* Index of the currently processed character from fmt */1298 errno_t rc = EOK; 1336 1299 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 1300 1339 1301 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; 1302 1303 while (rc == EOK) { 1304 /* Find the next specifier and write all the bytes before it. */ 1305 const char *s = _strchrnul(&fmt[nxt], '%'); 1306 size_t bytes = s - &fmt[nxt]; 1307 rc = _write_bytes(&fmt[nxt], bytes, ps, &counter); 1308 if (rc != EOK) 1309 break; 1310 1311 nxt += bytes; 1312 1313 /* Check for end of string. */ 1314 if (_eat_char(fmt, &nxt, 0)) 1315 break; 1316 1317 /* We must be at the start of a specifier. */ 1318 bool spec = _eat_char(fmt, &nxt, '%'); 1319 assert(spec); 1320 1321 /* Parse modifiers */ 1322 uint32_t flags = _parse_flags(fmt, &nxt); 1323 1324 /* Width & '*' operator */ 1325 int width = -1; 1326 if (_eat_char(fmt, &nxt, '*')) { 1327 /* Get width value from argument list */ 1328 width = va_arg(ap, int); 1329 1330 if (width < 0) { 1331 /* Negative width sets '-' flag */ 1332 width = (width == INT_MIN) ? INT_MAX : -width; 1333 flags |= __PRINTF_FLAG_LEFTALIGNED; 1359 1334 } 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 } 1335 } else { 1336 width = _read_num(fmt, &nxt); 1337 } 1338 1339 /* Precision and '*' operator */ 1340 int precision = -1; 1341 if (_eat_char(fmt, &nxt, '.')) { 1342 if (_eat_char(fmt, &nxt, '*')) { 1343 /* Get precision value from the argument list */ 1344 precision = va_arg(ap, int); 1345 1346 /* Negative is treated as omitted. */ 1347 if (precision < 0) 1348 precision = -1; 1349 } else { 1350 precision = _read_num(fmt, &nxt); 1416 1351 } 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 1352 } 1353 1354 qualifier_t qualifier = _read_qualifier(fmt, &nxt); 1355 unsigned int base = 10; 1356 char specifier = fmt[nxt++]; 1357 1358 switch (specifier) { 1359 /* 1360 * String and character conversions. 1361 */ 1362 case 's': 1363 if (qualifier == PrintfQualifierLong) 1364 rc = _format_wstr(va_arg(ap, char32_t *), width, precision, flags, ps, &counter); 1365 else 1366 rc = _format_cstr(va_arg(ap, char *), width, precision, flags, ps, &counter); 1367 continue; 1368 1369 case 'c': 1370 if (qualifier == PrintfQualifierLong) 1371 rc = _format_uchar(va_arg(ap, wint_t), width, flags, ps, &counter); 1372 else 1373 rc = _format_char(va_arg(ap, int), width, flags, ps, &counter); 1374 continue; 1375 1376 /* 1377 * Floating point values 1378 */ 1379 case 'G': 1380 case 'g': 1381 case 'F': 1382 case 'f': 1383 case 'E': 1384 case 'e':; 1534 1385 #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; 1386 rc = _format_double(va_arg(ap, double), specifier, precision, 1387 width, flags, ps, &counter); 1388 #else 1389 rc = _format_cstr("<float unsupported>", width, -1, 0, ps, &counter); 1555 1390 #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); 1391 continue; 1392 1393 /* 1394 * Integer values 1395 */ 1396 case 'P': 1397 /* Pointer */ 1398 flags |= __PRINTF_FLAG_BIGCHARS; 1399 /* Fallthrough */ 1400 case 'p': 1401 flags |= __PRINTF_FLAG_PREFIX; 1402 flags |= __PRINTF_FLAG_ZEROPADDED; 1403 base = 16; 1404 qualifier = PrintfQualifierPointer; 1405 break; 1406 case 'b': 1407 base = 2; 1408 break; 1409 case 'o': 1410 base = 8; 1411 break; 1412 case 'd': 1413 case 'i': 1414 flags |= __PRINTF_FLAG_SIGNED; 1415 break; 1416 case 'u': 1417 break; 1418 case 'X': 1419 flags |= __PRINTF_FLAG_BIGCHARS; 1420 /* Fallthrough */ 1421 case 'x': 1422 base = 16; 1423 break; 1424 1425 case '%': 1426 /* Percentile itself */ 1427 rc = _write_char('%', ps, &counter); 1428 continue; 1429 1430 /* 1431 * Bad formatting. 1432 */ 1433 default: 1434 rc = EINVAL; 1435 continue; 1436 } 1437 1438 /* Print integers */ 1439 uint64_t number; 1440 1441 switch (qualifier) { 1442 case PrintfQualifierByte: 1443 number = PRINTF_GET_INT_ARGUMENT(int, ap, flags); 1444 break; 1445 case PrintfQualifierShort: 1446 number = PRINTF_GET_INT_ARGUMENT(int, ap, flags); 1447 break; 1448 case PrintfQualifierInt: 1449 number = PRINTF_GET_INT_ARGUMENT(int, ap, flags); 1450 break; 1451 case PrintfQualifierLong: 1452 number = PRINTF_GET_INT_ARGUMENT(long, ap, flags); 1453 break; 1454 case PrintfQualifierLongLong: 1455 number = PRINTF_GET_INT_ARGUMENT(long long, ap, flags); 1456 break; 1457 case PrintfQualifierPointer: 1458 precision = sizeof(void *) << 1; 1459 number = (uint64_t) (uintptr_t) va_arg(ap, void *); 1460 break; 1461 default: 1462 /* Unknown qualifier */ 1463 rc = EINVAL; 1464 continue; 1465 } 1466 1467 rc = _format_number(number, width, precision, base, flags, ps, &counter); 1468 if (rc != EOK) 1469 continue; 1470 } 1471 1472 if (rc != EOK) { 1473 _set_errno(rc); 1474 return -1; 1475 } 1476 1477 if (counter > INT_MAX) { 1478 _set_errno(EOVERFLOW); 1479 return -1; 1480 } 1481 1482 return (int) counter; 1671 1483 } 1672 1484
Note:
See TracChangeset
for help on using the changeset viewer.