Mercurial > vim
comparison src/message.c @ 10038:7cf4e210cf3c v7.4.2291
commit https://github.com/vim/vim/commit/04186095346daa60e82e981dad114de2b641d672
Author: Bram Moolenaar <Bram@vim.org>
Date: Mon Aug 29 21:55:35 2016 +0200
patch 7.4.2291
Problem: printf() handles floats wrong when there is a sign.
Solution: Fix placing the sign. Add tests. (Dominique Pelle)
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Mon, 29 Aug 2016 22:00:07 +0200 |
parents | ab6320d74331 |
children | 48f70e0c696a |
comparison
equal
deleted
inserted
replaced
10037:f359ee3f123e | 10038:7cf4e210cf3c |
---|---|
4028 * This snprintf() only supports the following conversion specifiers: | 4028 * This snprintf() only supports the following conversion specifiers: |
4029 * s, c, d, u, o, x, X, p (and synonyms: i, D, U, O - see below) | 4029 * s, c, d, u, o, x, X, p (and synonyms: i, D, U, O - see below) |
4030 * with flags: '-', '+', ' ', '0' and '#'. | 4030 * with flags: '-', '+', ' ', '0' and '#'. |
4031 * An asterisk is supported for field width as well as precision. | 4031 * An asterisk is supported for field width as well as precision. |
4032 * | 4032 * |
4033 * Limited support for floating point was added: 'f', 'e', 'E', 'g', 'G'. | 4033 * Limited support for floating point was added: 'f', 'F', 'e', 'E', 'g', 'G'. |
4034 * | 4034 * |
4035 * Length modifiers 'h' (short int) and 'l' (long int) and 'll' (long long int) | 4035 * Length modifiers 'h' (short int) and 'l' (long int) and 'll' (long long int) |
4036 * are supported. | 4036 * are supported. |
4037 * | 4037 * |
4038 * The locale is not used, the string is used as a byte string. This is only | 4038 * The locale is not used, the string is used as a byte string. This is only |
4284 { | 4284 { |
4285 case 'i': fmt_spec = 'd'; break; | 4285 case 'i': fmt_spec = 'd'; break; |
4286 case 'D': fmt_spec = 'd'; length_modifier = 'l'; break; | 4286 case 'D': fmt_spec = 'd'; length_modifier = 'l'; break; |
4287 case 'U': fmt_spec = 'u'; length_modifier = 'l'; break; | 4287 case 'U': fmt_spec = 'u'; length_modifier = 'l'; break; |
4288 case 'O': fmt_spec = 'o'; length_modifier = 'l'; break; | 4288 case 'O': fmt_spec = 'o'; length_modifier = 'l'; break; |
4289 case 'F': fmt_spec = 'f'; break; | |
4290 default: break; | 4289 default: break; |
4291 } | 4290 } |
4292 | 4291 |
4293 # if defined(FEAT_EVAL) && defined(FEAT_NUM64) | 4292 # if defined(FEAT_EVAL) && defined(FEAT_NUM64) |
4294 switch (fmt_spec) | 4293 switch (fmt_spec) |
4713 break; | 4712 break; |
4714 } | 4713 } |
4715 | 4714 |
4716 # ifdef FEAT_FLOAT | 4715 # ifdef FEAT_FLOAT |
4717 case 'f': | 4716 case 'f': |
4717 case 'F': | |
4718 case 'e': | 4718 case 'e': |
4719 case 'E': | 4719 case 'E': |
4720 case 'g': | 4720 case 'g': |
4721 case 'G': | 4721 case 'G': |
4722 { | 4722 { |
4738 { | 4738 { |
4739 /* Would be nice to use %g directly, but it prints | 4739 /* Would be nice to use %g directly, but it prints |
4740 * "1.0" as "1", we don't want that. */ | 4740 * "1.0" as "1", we don't want that. */ |
4741 if ((abs_f >= 0.001 && abs_f < 10000000.0) | 4741 if ((abs_f >= 0.001 && abs_f < 10000000.0) |
4742 || abs_f == 0.0) | 4742 || abs_f == 0.0) |
4743 fmt_spec = 'f'; | 4743 fmt_spec = ASCII_ISUPPER(fmt_spec) ? 'F' : 'f'; |
4744 else | 4744 else |
4745 fmt_spec = fmt_spec == 'g' ? 'e' : 'E'; | 4745 fmt_spec = fmt_spec == 'g' ? 'e' : 'E'; |
4746 remove_trailing_zeroes = TRUE; | 4746 remove_trailing_zeroes = TRUE; |
4747 } | 4747 } |
4748 | 4748 |
4749 if (fmt_spec == 'f' && | 4749 if ((fmt_spec == 'f' || fmt_spec == 'F') && |
4750 # ifdef VAX | 4750 # ifdef VAX |
4751 abs_f > 1.0e38 | 4751 abs_f > 1.0e38 |
4752 # else | 4752 # else |
4753 abs_f > 1.0e307 | 4753 abs_f > 1.0e307 |
4754 # endif | 4754 # endif |
4760 str_arg_l = STRLEN(tmp); | 4760 str_arg_l = STRLEN(tmp); |
4761 zero_padding = 0; | 4761 zero_padding = 0; |
4762 } | 4762 } |
4763 else | 4763 else |
4764 { | 4764 { |
4765 format[0] = '%'; | |
4766 l = 1; | |
4767 if (precision_specified) | |
4768 { | |
4769 size_t max_prec = TMP_LEN - 10; | |
4770 | |
4771 /* Make sure we don't get more digits than we | |
4772 * have room for. */ | |
4773 if (fmt_spec == 'f' && abs_f > 1.0) | |
4774 max_prec -= (size_t)log10(abs_f); | |
4775 if (precision > max_prec) | |
4776 precision = max_prec; | |
4777 l += sprintf(format + 1, ".%d", (int)precision); | |
4778 } | |
4779 format[l] = fmt_spec; | |
4780 format[l + 1] = NUL; | |
4781 | |
4782 if (isnan(f)) | 4765 if (isnan(f)) |
4783 { | 4766 { |
4784 /* Not a number: nan or NAN */ | 4767 /* Not a number: nan or NAN */ |
4785 STRCPY(tmp, ASCII_ISUPPER(fmt_spec) ? "NAN" | 4768 STRCPY(tmp, ASCII_ISUPPER(fmt_spec) ? "NAN" |
4786 : "nan"); | 4769 : "nan"); |
4793 force_sign, space_for_positive)); | 4776 force_sign, space_for_positive)); |
4794 str_arg_l = STRLEN(tmp); | 4777 str_arg_l = STRLEN(tmp); |
4795 zero_padding = 0; | 4778 zero_padding = 0; |
4796 } | 4779 } |
4797 else | 4780 else |
4781 { | |
4798 /* Regular float number */ | 4782 /* Regular float number */ |
4783 format[0] = '%'; | |
4784 l = 1; | |
4785 if (force_sign) | |
4786 format[l++] = space_for_positive ? ' ' : '+'; | |
4787 if (precision_specified) | |
4788 { | |
4789 size_t max_prec = TMP_LEN - 10; | |
4790 | |
4791 /* Make sure we don't get more digits than we | |
4792 * have room for. */ | |
4793 if ((fmt_spec == 'f' || fmt_spec == 'F') | |
4794 && abs_f > 1.0) | |
4795 max_prec -= (size_t)log10(abs_f); | |
4796 if (precision > max_prec) | |
4797 precision = max_prec; | |
4798 l += sprintf(format + l, ".%d", (int)precision); | |
4799 } | |
4800 format[l] = fmt_spec; | |
4801 format[l + 1] = NUL; | |
4802 | |
4799 str_arg_l = sprintf(tmp, format, f); | 4803 str_arg_l = sprintf(tmp, format, f); |
4804 } | |
4800 | 4805 |
4801 if (remove_trailing_zeroes) | 4806 if (remove_trailing_zeroes) |
4802 { | 4807 { |
4803 int i; | 4808 int i; |
4804 char *tp; | 4809 char *tp; |
4805 | 4810 |
4806 /* Using %g or %G: remove superfluous zeroes. */ | 4811 /* Using %g or %G: remove superfluous zeroes. */ |
4807 if (fmt_spec == 'f') | 4812 if (fmt_spec == 'f' || fmt_spec == 'F') |
4808 tp = tmp + str_arg_l - 1; | 4813 tp = tmp + str_arg_l - 1; |
4809 else | 4814 else |
4810 { | 4815 { |
4811 tp = (char *)vim_strchr((char_u *)tmp, | 4816 tp = (char *)vim_strchr((char_u *)tmp, |
4812 fmt_spec == 'e' ? 'e' : 'E'); | 4817 fmt_spec == 'e' ? 'e' : 'E'); |
4859 STRMOVE(tp + 2, tp + 3); | 4864 STRMOVE(tp + 2, tp + 3); |
4860 --str_arg_l; | 4865 --str_arg_l; |
4861 } | 4866 } |
4862 } | 4867 } |
4863 } | 4868 } |
4869 if (zero_padding && min_field_width > str_arg_l | |
4870 && (tmp[0] == '-' || force_sign)) | |
4871 { | |
4872 /* padding 0's should be inserted after the sign */ | |
4873 number_of_zeros_to_pad = min_field_width - str_arg_l; | |
4874 zero_padding_insertion_ind = 1; | |
4875 } | |
4864 str_arg = tmp; | 4876 str_arg = tmp; |
4865 break; | 4877 break; |
4866 } | 4878 } |
4867 # endif | 4879 # endif |
4868 | 4880 |