Differences From Artifact [bff5bd9808]:
- File src/of_asprintf.m — part of check-in [e0b9167693] at 2016-02-21 15:37:42 on branch trunk — Make use of C99-style for loops (user: js, size: 14348) [annotate] [blame] [check-ins using]
To Artifact [91cd8b629a]:
- File
src/of_asprintf.m
— part of check-in
[6dff0f5922]
at
2017-01-07 02:34:39
on branch trunk
— Always use "." for the decimal point
This is achieved by replacing the locale's decimal point with "." after
formatting and replacing "." with the locale's decimal point before
parsing.To still use the decimal point from the locale for formatting, the new
flag "," is introduced to formats. This is useful for just printing a
string to the user that is not saved to a file or sent via a network.While this is an ugly hack, there is no better way to do this other than
implementing the functionality of printf and strtod myself, as POSIX
does not specify versions of these that take a locale as an argument.
While this is a lot of work and error-prone, I will most likely end up
doing this eventually.This commit also enables the locale in OFApplication to notice when
things break. As a nice side effect, ofhttp now uses the locale's
decimal point in its user interface. (user: js, size: 15256) [annotate] [blame] [check-ins using]
︙ | ︙ | |||
22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #include <stdarg.h> #include <stdbool.h> #include <wchar.h> #include <sys/types.h> #import "OFString.h" #define MAX_SUBFORMAT_LEN 64 #ifndef HAVE_ASPRINTF /* * (v)asprintf might be declared, but HAVE_ASPRINTF not defined because * configure determined it is broken. In this case, we must make sure there is | > | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | #include <stdarg.h> #include <stdbool.h> #include <wchar.h> #include <sys/types.h> #import "OFString.h" #import "OFSystemInfo.h" #define MAX_SUBFORMAT_LEN 64 #ifndef HAVE_ASPRINTF /* * (v)asprintf might be declared, but HAVE_ASPRINTF not defined because * configure determined it is broken. In this case, we must make sure there is |
︙ | ︙ | |||
62 63 64 65 66 67 68 69 70 71 72 73 74 75 | LENGTH_MODIFIER_L, LENGTH_MODIFIER_LL, LENGTH_MODIFIER_J, LENGTH_MODIFIER_Z, LENGTH_MODIFIER_T, LENGTH_MODIFIER_CAPITAL_L } lengthModifier; }; #ifndef HAVE_ASPRINTF static int vasprintf(char **string, const char *format, va_list arguments) { int length; | > | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | LENGTH_MODIFIER_L, LENGTH_MODIFIER_LL, LENGTH_MODIFIER_J, LENGTH_MODIFIER_Z, LENGTH_MODIFIER_T, LENGTH_MODIFIER_CAPITAL_L } lengthModifier; bool useLocale; }; #ifndef HAVE_ASPRINTF static int vasprintf(char **string, const char *format, va_list arguments) { int length; |
︙ | ︙ | |||
161 162 163 164 165 166 167 168 169 170 171 172 173 174 | case ' ': case '#': case '0': if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) return false; break; default: ctx->state = STATE_FORMAT_FIELD_WIDTH; ctx->i--; break; } | > > > > | 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | case ' ': case '#': case '0': if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) return false; break; case ',': /* ObjFW extension: Use decimal point from locale */ ctx->useLocale = true; break; default: ctx->state = STATE_FORMAT_FIELD_WIDTH; ctx->i--; break; } |
︙ | ︙ | |||
497 498 499 500 501 502 503 504 505 506 507 508 509 510 | case LENGTH_MODIFIER_CAPITAL_L: tmpLen = asprintf(&tmp, ctx->subformat, va_arg(ctx->arguments, long double)); break; default: return false; } break; case 'c': switch (ctx->lengthModifier) { case LENGTH_MODIFIER_NONE: tmpLen = asprintf(&tmp, ctx->subformat, va_arg(ctx->arguments, int)); | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 | case LENGTH_MODIFIER_CAPITAL_L: tmpLen = asprintf(&tmp, ctx->subformat, va_arg(ctx->arguments, long double)); break; default: return false; } /* * Ugly hack to undo locale, as there is nothing such as * asprintf_l in POSIX. */ if (!ctx->useLocale) { void *pool = objc_autoreleasePoolPush(); char *tmp2; @try { OFMutableString *tmpStr = [OFMutableString stringWithUTF8String: tmp length: tmpLen]; OFString *decimalPoint = [OFSystemInfo decimalPoint]; [tmpStr replaceOccurrencesOfString: decimalPoint withString: @"."]; if ([tmpStr UTF8StringLength] > INT_MAX) return false; tmpLen = (int)[tmpStr UTF8StringLength]; tmp2 = malloc(tmpLen); memcpy(tmp2, [tmpStr UTF8String], tmpLen); } @finally { free(tmp); objc_autoreleasePoolPop(pool); } tmp = tmp2; } break; case 'c': switch (ctx->lengthModifier) { case LENGTH_MODIFIER_NONE: tmpLen = asprintf(&tmp, ctx->subformat, va_arg(ctx->arguments, int)); |
︙ | ︙ | |||
608 609 610 611 612 613 614 615 616 617 618 619 620 621 | free(tmp); } memset(ctx->subformat, 0, MAX_SUBFORMAT_LEN); ctx->subformatLen = 0; ctx->lengthModifier = LENGTH_MODIFIER_NONE; ctx->last = ctx->i + 1; ctx->state = STATE_STRING; return true; } | > | 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 | free(tmp); } memset(ctx->subformat, 0, MAX_SUBFORMAT_LEN); ctx->subformatLen = 0; ctx->lengthModifier = LENGTH_MODIFIER_NONE; ctx->useLocale = false; ctx->last = ctx->i + 1; ctx->state = STATE_STRING; return true; } |
︙ | ︙ | |||
637 638 639 640 641 642 643 644 645 646 647 648 649 650 | memset(ctx.subformat, 0, MAX_SUBFORMAT_LEN + 1); ctx.subformatLen = 0; va_copy(ctx.arguments, arguments); ctx.bufferLen = 0; ctx.last = 0; ctx.state = STATE_STRING; ctx.lengthModifier = LENGTH_MODIFIER_NONE; if ((ctx.buffer = malloc(1)) == NULL) return -1; for (ctx.i = 0; ctx.i < ctx.formatLen; ctx.i++) { if (!states[ctx.state](&ctx)) { free(ctx.buffer); | > | 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 | memset(ctx.subformat, 0, MAX_SUBFORMAT_LEN + 1); ctx.subformatLen = 0; va_copy(ctx.arguments, arguments); ctx.bufferLen = 0; ctx.last = 0; ctx.state = STATE_STRING; ctx.lengthModifier = LENGTH_MODIFIER_NONE; ctx.useLocale = false; if ((ctx.buffer = malloc(1)) == NULL) return -1; for (ctx.i = 0; ctx.i < ctx.formatLen; ctx.i++) { if (!states[ctx.state](&ctx)) { free(ctx.buffer); |
︙ | ︙ |