1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3 Written by Ben Pfaff <blp@gnu.org>.
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 #include <libpspp/message.h>
28 #include <libpspp/message.h>
30 #include <libpspp/magic.h>
31 #include <libpspp/misc.h>
32 #include <libpspp/misc.h>
34 #include <libpspp/str.h>
38 #define _(msgid) gettext (msgid)
40 /* Public functions. */
42 typedef int numeric_converter (char *, const struct fmt_spec *, double);
43 static numeric_converter convert_F, convert_N, convert_E, convert_F_plus;
44 static numeric_converter convert_Z, convert_IB, convert_P, convert_PIB;
45 static numeric_converter convert_PIBHEX, convert_PK, convert_RB;
46 static numeric_converter convert_RBHEX, convert_CCx, convert_date;
47 static numeric_converter convert_time, convert_WKDAY, convert_MONTH;
49 static numeric_converter try_F, convert_infinite;
51 typedef int string_converter (char *, const struct fmt_spec *, const char *);
52 static string_converter convert_A, convert_AHEX;
54 /* Converts binary value V into printable form in the exactly
55 FP->W character in buffer S according to format specification
56 FP. No null terminator is appended to the buffer. */
58 data_out (char *s, const struct fmt_spec *fp, const union value *v)
60 int cat = formats[fp->type].cat;
63 assert (check_output_specifier (fp, 0));
64 if (!(cat & FCAT_STRING))
66 /* Numeric formatting. */
69 /* Handle SYSMIS turning into blanks. */
70 if ((cat & FCAT_BLANKS_SYSMIS) && number == SYSMIS)
72 memset (s, ' ', fp->w);
73 s[fp->w - fp->d - 1] = '.';
77 /* Handle decimal shift. */
78 if ((cat & FCAT_SHIFT_DECIMAL) && number != SYSMIS && fp->d)
79 number *= pow (10.0, fp->d);
84 ok = convert_F (s, fp, number);
88 ok = convert_N (s, fp, number);
92 ok = convert_E (s, fp, number);
95 case FMT_COMMA: case FMT_DOT: case FMT_DOLLAR: case FMT_PCT:
96 ok = convert_F_plus (s, fp, number);
100 ok = convert_Z (s, fp, number);
112 ok = convert_IB (s, fp, number);
116 ok = convert_P (s, fp, number);
120 ok = convert_PIB (s, fp, number);
124 ok = convert_PIBHEX (s, fp, number);
128 ok = convert_PK (s, fp, number);
132 ok = convert_RB (s, fp, number);
136 ok = convert_RBHEX (s, fp, number);
139 case FMT_CCA: case FMT_CCB: case FMT_CCC: case FMT_CCD: case FMT_CCE:
140 ok = convert_CCx (s, fp, number);
143 case FMT_DATE: case FMT_EDATE: case FMT_SDATE: case FMT_ADATE:
144 case FMT_JDATE: case FMT_QYR: case FMT_MOYR: case FMT_WKYR:
146 ok = convert_date (s, fp, number);
149 case FMT_TIME: case FMT_DTIME:
150 ok = convert_time (s, fp, number);
154 ok = convert_WKDAY (s, fp, number);
158 ok = convert_MONTH (s, fp, number);
168 /* String formatting. */
169 const char *string = v->s;
174 ok = convert_A (s, fp, string);
178 ok = convert_AHEX (s, fp, string);
187 /* Error handling. */
189 strncpy (s, "ERROR", fp->w);
194 /* Converts V into S in F format with width W and D decimal places,
195 then deletes trailing zeros. S is not null-terminated. */
197 num_to_string (double v, char *s, int w, int d)
199 struct fmt_spec f = make_output_format (FMT_F, w, d);
200 convert_F (s, &f, v);
203 /* Main conversion functions. */
205 static void insert_commas (char *dst, const char *src,
206 const struct fmt_spec *fp);
207 static int year4 (int year);
208 static int try_CCx (char *s, const struct fmt_spec *fp, double v);
211 #error Write your own floating-point output routines.
214 /* Converts a number between 0 and 15 inclusive to a `hexit'
216 #define MAKE_HEXIT(X) ("0123456789ABCDEF"[X])
218 /* Table of powers of 10. */
219 static const double power10[] =
222 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, 1e09, 1e10,
223 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20,
224 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29, 1e30,
225 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39, 1e40,
228 /* Handles F format. */
230 convert_F (char *dst, const struct fmt_spec *fp, double number)
232 if (!try_F (dst, fp, number))
233 convert_E (dst, fp, number);
237 /* Handles N format. */
239 convert_N (char *dst, const struct fmt_spec *fp, double number)
241 double d = floor (number);
243 if (d < 0 || d == SYSMIS)
245 msg (ME, _("The N output format cannot be used to output a "
246 "negative number or the system-missing value."));
250 if (d < power10[fp->w])
253 sprintf (buf, "%0*.0f", fp->w, number);
254 memcpy (dst, buf, fp->w);
257 memset (dst, '*', fp->w);
262 /* Handles E format. Also operates as fallback for some other
265 convert_E (char *dst, const struct fmt_spec *fp, double number)
267 /* Temporary buffer. */
270 /* Ranged number of decimal places. */
273 if (!finite (number))
274 return convert_infinite (dst, fp, number);
276 /* Check that the format is wide enough.
277 Although PSPP generally checks this, convert_E() can be called as
278 a fallback from other formats which do not check. */
281 memset (dst, '*', fp->w);
285 /* Put decimal places in usable range. */
286 d = min (fp->d, fp->w - 6);
291 sprintf (buf, "%*.*E", fp->w, d, number);
293 /* What we do here is force the exponent part to have four
294 characters whenever possible. That is, 1.00E+99 is okay (`E+99')
295 but 1.00E+100 (`E+100') must be coerced to 1.00+100 (`+100'). On
296 the other hand, 1.00E1000 (`E+100') cannot be canonicalized.
297 Note that ANSI C guarantees at least two digits in the
299 if (fabs (number) > 1e99)
301 /* Pointer to the `E' in buf. */
304 cp = strchr (buf, 'E');
307 /* Exponent better not be bigger than an int. */
308 int exp = atoi (cp + 1);
310 if (abs (exp) > 99 && abs (exp) < 1000)
312 /* Shift everything left one place: 1.00e+100 -> 1.00+100. */
318 else if (abs (exp) >= 1000)
319 memset (buf, '*', fp->w);
323 /* The C locale always uses a period `.' as a decimal point.
324 Translate to comma if necessary. */
325 if ((get_decimal() == ',' && fp->type != FMT_DOT)
326 || (get_decimal() == '.' && fp->type == FMT_DOT))
328 char *cp = strchr (buf, '.');
333 memcpy (dst, buf, fp->w);
337 /* Handles COMMA, DOT, DOLLAR, and PCT formats. */
339 convert_F_plus (char *dst, const struct fmt_spec *fp, double number)
343 if (try_F (buf, fp, number))
344 insert_commas (dst, buf, fp);
346 convert_E (dst, fp, number);
352 convert_Z (char *dst, const struct fmt_spec *fp, double number)
354 static int warned = 0;
359 _("Quality of zoned decimal (Z) output format code is "
360 "suspect. Check your results. Report bugs to %s."),
365 if (number == SYSMIS)
367 msg (ME, _("The system-missing value cannot be output as a zoned "
377 d = fabs (floor (number));
378 if (d >= power10[fp->w])
380 msg (ME, _("Number %g too big to fit in field with format Z%d.%d."),
381 number, fp->w, fp->d);
385 sprintf (buf, "%*.0f", fp->w, number);
386 for (i = 0; i < fp->w; i++)
387 dst[i] = (buf[i] - '0') | 0xf0;
389 dst[fp->w - 1] &= 0xdf;
396 convert_A (char *dst, const struct fmt_spec *fp, const char *string)
398 memcpy (dst, string, fp->w);
403 convert_AHEX (char *dst, const struct fmt_spec *fp, const char *string)
407 for (i = 0; i < fp->w / 2; i++)
409 *dst++ = MAKE_HEXIT ((string[i]) >> 4);
410 *dst++ = MAKE_HEXIT ((string[i]) & 0xf);
417 convert_IB (char *dst, const struct fmt_spec *fp, double number)
419 /* Strategy: Basically the same as convert_PIBHEX() but with
420 base 256. Then negate the two's-complement result if number
423 /* Used for constructing the two's-complement result. */
426 /* Fraction (mantissa). */
432 /* Difference between exponent and (-8*fp->w-1). */
438 /* Make the exponent (-8*fp->w-1). */
439 frac = frexp (fabs (number), &exp);
440 diff = exp - (-8 * fp->w - 1);
442 frac *= ldexp (1.0, diff);
444 /* Extract each base-256 digit. */
445 for (i = 0; i < fp->w; i++)
449 temp[i] = floor (frac);
452 /* Perform two's-complement negation if number is negative. */
455 /* Perform NOT operation. */
456 for (i = 0; i < fp->w; i++)
458 /* Add 1 to the whole number. */
459 for (i = fp->w - 1; i >= 0; i--)
466 memcpy (dst, temp, fp->w);
467 #ifndef WORDS_BIGENDIAN
468 buf_reverse (dst, fp->w);
475 convert_P (char *dst, const struct fmt_spec *fp, double number)
477 /* Buffer for fp->w*2-1 characters + a decimal point if library is
478 not quite compliant + a null. */
484 /* Main extraction. */
485 sprintf (buf, "%0*.0f", fp->w * 2 - 1, floor (fabs (number)));
487 for (i = 0; i < fp->w; i++)
488 ((unsigned char *) dst)[i]
489 = ((buf[i * 2] - '0') << 4) + buf[i * 2 + 1] - '0';
492 dst[fp->w - 1] &= 0xf0;
494 dst[fp->w - 1] |= 0xf;
496 dst[fp->w - 1] |= 0xd;
502 convert_PIB (char *dst, const struct fmt_spec *fp, double number)
504 /* Strategy: Basically the same as convert_IB(). */
506 /* Fraction (mantissa). */
512 /* Difference between exponent and (-8*fp->w). */
518 /* Make the exponent (-8*fp->w). */
519 frac = frexp (fabs (number), &exp);
520 diff = exp - (-8 * fp->w);
522 frac *= ldexp (1.0, diff);
524 /* Extract each base-256 digit. */
525 for (i = 0; i < fp->w; i++)
529 ((unsigned char *) dst)[i] = floor (frac);
531 #ifndef WORDS_BIGENDIAN
532 buf_reverse (dst, fp->w);
539 convert_PIBHEX (char *dst, const struct fmt_spec *fp, double number)
541 /* Strategy: Use frexp() to create a normalized result (but mostly
542 to find the base-2 exponent), then change the base-2 exponent to
543 (-4*fp->w) using multiplication and division by powers of two.
544 Extract each hexit by multiplying by 16. */
546 /* Fraction (mantissa). */
552 /* Difference between exponent and (-4*fp->w). */
558 /* Make the exponent (-4*fp->w). */
559 frac = frexp (fabs (number), &exp);
560 diff = exp - (-4 * fp->w);
562 frac *= ldexp (1.0, diff);
564 /* Extract each hexit. */
565 for (i = 0; i < fp->w; i++)
569 *dst++ = MAKE_HEXIT ((int) floor (frac));
576 convert_PK (char *dst, const struct fmt_spec *fp, double number)
578 /* Buffer for fp->w*2 characters + a decimal point if library is not
579 quite compliant + a null. */
585 /* Main extraction. */
586 sprintf (buf, "%0*.0f", fp->w * 2, floor (fabs (number)));
588 for (i = 0; i < fp->w; i++)
589 ((unsigned char *) dst)[i]
590 = ((buf[i * 2] - '0') << 4) + buf[i * 2 + 1] - '0';
596 convert_RB (char *dst, const struct fmt_spec *fp, double number)
606 memcpy (dst, u.c, fp->w);
612 convert_RBHEX (char *dst, const struct fmt_spec *fp, double number)
624 for (i = 0; i < fp->w / 2; i++)
626 *dst++ = MAKE_HEXIT (u.c[i] >> 4);
627 *dst++ = MAKE_HEXIT (u.c[i] & 15);
634 convert_CCx (char *dst, const struct fmt_spec *fp, double number)
636 if (try_CCx (dst, fp, number))
646 return convert_F_plus (dst, &f, number);
651 convert_date (char *dst, const struct fmt_spec *fp, double number)
653 static const char *months[12] =
655 "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
656 "JUL", "AUG", "SEP", "OCT", "NOV", "DEC",
660 int ofs = number / 86400.;
661 int month, day, year;
666 calendar_offset_to_gregorian (ofs, &year, &month, &day);
671 sprintf (buf, "%02d-%s-%04d", day, months[month - 1], year);
673 sprintf (buf, "%02d-%s-%02d", day, months[month - 1], year % 100);
677 sprintf (buf, "%02d.%02d.%04d", day, month, year);
679 sprintf (buf, "%02d.%02d.%02d", day, month, year % 100);
683 sprintf (buf, "%04d/%02d/%02d", year, month, day);
685 sprintf (buf, "%02d/%02d/%02d", year % 100, month, day);
689 sprintf (buf, "%02d/%02d/%04d", month, day, year);
691 sprintf (buf, "%02d/%02d/%02d", month, day, year % 100);
695 int yday = calendar_offset_to_yday (ofs);
698 sprintf (buf, "%02d%03d", year % 100, yday);
699 else if (year4 (year))
700 sprintf (buf, "%04d%03d", year, yday);
706 sprintf (buf, "%d Q% 04d", (month - 1) / 3 + 1, year);
708 sprintf (buf, "%d Q% 02d", (month - 1) / 3 + 1, year % 100);
712 sprintf (buf, "%s% 04d", months[month - 1], year);
714 sprintf (buf, "%s% 02d", months[month - 1], year % 100);
718 int yday = calendar_offset_to_yday (ofs);
721 sprintf (buf, "%02d WK% 04d", (yday - 1) / 7 + 1, year);
723 sprintf (buf, "%02d WK% 02d", (yday - 1) / 7 + 1, year % 100);
730 cp = spprintf (buf, "%02d-%s-%04d %02d:%02d",
731 day, months[month - 1], year,
732 (int) fmod (floor (number / 60. / 60.), 24.),
733 (int) fmod (floor (number / 60.), 60.));
738 if (fp->w >= 22 && fp->d > 0)
740 d = min (fp->d, fp->w - 21);
749 cp = spprintf (cp, ":%0*.*f", w, d, fmod (number, 60.));
759 buf_copy_str_rpad (dst, fp->w, buf);
764 convert_time (char *dst, const struct fmt_spec *fp, double number)
772 if (fabs (number) > 1e20)
774 msg (ME, _("Time value %g too large in magnitude to convert to "
775 "alphanumeric time."), number);
783 *cp++ = '-', time = -time;
784 if (fp->type == FMT_DTIME)
786 double days = floor (time / 60. / 60. / 24.);
787 cp = spprintf (temp_buf, "%02.0f ", days);
788 time = time - days * 60. * 60. * 24.;
794 cp = spprintf (cp, "%02.0f:%02.0f",
795 fmod (floor (time / 60. / 60.), 24.),
796 fmod (floor (time / 60.), 60.));
802 if (width >= 10 && fp->d >= 0 && fp->d != 0)
803 d = min (fp->d, width - 9), w = 3 + d;
807 cp = spprintf (cp, ":%0*.*f", w, d, fmod (time, 60.));
809 buf_copy_str_rpad (dst, fp->w, temp_buf);
815 convert_WKDAY (char *dst, const struct fmt_spec *fp, double wkday)
817 static const char *weekdays[7] =
819 "SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY",
820 "THURSDAY", "FRIDAY", "SATURDAY",
823 if (wkday < 1 || wkday > 7)
825 msg (ME, _("Weekday index %f does not lie between 1 and 7."),
829 buf_copy_str_rpad (dst, fp->w, weekdays[(int) wkday - 1]);
835 convert_MONTH (char *dst, const struct fmt_spec *fp, double month)
837 static const char *months[12] =
839 "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
840 "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER",
843 if (month < 1 || month > 12)
845 msg (ME, _("Month index %f does not lie between 1 and 12."),
850 buf_copy_str_rpad (dst, fp->w, months[(int) month - 1]);
855 /* Helper functions. */
857 /* Copies SRC to DST, inserting commas and dollar signs as appropriate
858 for format spec *FP. */
860 insert_commas (char *dst, const char *src, const struct fmt_spec *fp)
862 /* Number of leading spaces in the number. This is the amount of
863 room we have for inserting commas and dollar signs. */
866 /* Number of digits before the decimal point. This is used to
867 determine the Number of commas to insert. */
870 /* Number of commas to insert. */
873 /* Number of items ,%$ to insert. */
876 /* Number of n_items items not to use for commas. */
879 /* Digit iterator. */
882 /* Source pointer. */
885 /* Count spaces and digits. */
887 while (sp < src + fp->w && *sp == ' ')
894 while (sp + n_digits < src + fp->w && isdigit ((unsigned char) sp[n_digits]))
896 n_commas = (n_digits - 1) / 3;
897 n_items = n_commas + (fp->type == FMT_DOLLAR || fp->type == FMT_PCT);
899 /* Check whether we have enough space to do insertions. */
900 if (!n_spaces || !n_items)
902 memcpy (dst, src, fp->w);
905 if (n_items > n_spaces)
910 memcpy (dst, src, fp->w);
915 /* Put spaces at the beginning if there's extra room. */
916 if (n_spaces > n_items)
918 memset (dst, ' ', n_spaces - n_items);
919 dst += n_spaces - n_items;
922 /* Insert $ and reserve space for %. */
924 if (fp->type == FMT_DOLLAR)
929 else if (fp->type == FMT_PCT)
932 /* Copy negative sign and digits, inserting commas. */
933 if (sp - src > n_spaces)
935 for (i = n_digits; i; i--)
937 if (i % 3 == 0 && n_digits > i && n_items > n_reserved)
940 *dst++ = fp->type == FMT_COMMA ? get_grouping() : get_decimal();
945 /* Copy decimal places and insert % if necessary. */
946 memcpy (dst, sp, fp->w - (sp - src));
947 if (fp->type == FMT_PCT && n_items > 0)
948 dst[fp->w - (sp - src)] = '%';
951 /* Returns 1 if YEAR (i.e., 1987) can be represented in four digits, 0
956 if (year >= 1 && year <= 9999)
958 msg (ME, _("Year %d cannot be represented in four digits for "
959 "output formatting purposes."), year);
964 try_CCx (char *dst, const struct fmt_spec *fp, double number)
966 const struct custom_currency *cc = get_cc(fp->type - FMT_CCA);
974 /* Determine length available, decimal character for number
976 f.type = cc->decimal == get_decimal () ? FMT_COMMA : FMT_DOT;
977 f.w = fp->w - strlen (cc->prefix) - strlen (cc->suffix);
979 f.w -= strlen (cc->neg_prefix) + strlen (cc->neg_suffix) - 1;
981 /* Convert -0 to +0. */
982 number = fabs (number);
988 /* There's room for all that currency crap. Let's do the F
990 if (!convert_F (buf, &f, number) || *buf == '*')
992 insert_commas (buf2, buf, &f);
994 /* Postprocess back into buf. */
997 cp = stpcpy (cp, cc->neg_prefix);
998 cp = stpcpy (cp, cc->prefix);
1004 assert ((number >= 0) ^ (*bp == '-'));
1008 memcpy (cp, bp, f.w - (bp - buf2));
1009 cp += f.w - (bp - buf2);
1011 cp = stpcpy (cp, cc->suffix);
1013 cp = stpcpy (cp, cc->neg_suffix);
1015 /* Copy into dst. */
1016 assert (cp - buf <= fp->w);
1017 if (cp - buf < fp->w)
1019 memcpy (&dst[fp->w - (cp - buf)], buf, cp - buf);
1020 memset (dst, ' ', fp->w - (cp - buf));
1023 memcpy (dst, buf, fp->w);
1029 format_and_round (char *dst, double number, const struct fmt_spec *fp,
1032 /* Tries to format NUMBER into DST as the F format specified in
1033 *FP. Return true if successful, false on failure. */
1035 try_F (char *dst, const struct fmt_spec *fp, double number)
1037 assert (fp->w <= 40);
1038 if (finite (number))
1040 if (fabs (number) < power10[fp->w])
1042 /* The value may fit in the field. */
1045 /* There are no decimal places, so there's no way
1046 that the value can be shortened. Either it fits
1049 sprintf (buf, "%*.0f", fp->w, number);
1050 if (strlen (buf) <= fp->w)
1052 buf_copy_str_lpad (dst, fp->w, buf);
1060 /* First try to format it with 2 extra decimal
1061 places. This gives us a good chance of not
1062 needing even more decimal places, but it also
1063 avoids wasting too much time formatting more
1064 decimal places on the first try. */
1065 int result = format_and_round (dst, number, fp, fp->d + 2);
1069 /* 2 extra decimal places weren't enough to
1070 correctly round. Try again with the maximum
1071 number of places. */
1072 return format_and_round (dst, number, fp, LDBL_DIG + 1);
1077 /* The value is too big to fit in the field. */
1082 return convert_infinite (dst, fp, number);
1085 /* Tries to compose NUMBER into DST in format FP by first
1086 formatting it with DECIMALS decimal places, then rounding off
1087 to as many decimal places will fit or the number specified in
1088 FP, whichever is fewer.
1090 Returns 1 if conversion succeeds, 0 if this try at conversion
1091 failed and so will any other tries (because the integer part
1092 of the number is too long), or -1 if this try failed but
1093 another with higher DECIMALS might succeed (because we'd be
1094 able to properly round). */
1096 format_and_round (char *dst, double number, const struct fmt_spec *fp,
1099 /* Number of characters before the decimal point,
1100 which includes digits and possibly a minus sign. */
1103 /* Number of digits in the output fraction,
1104 which may be smaller than fp->d if there's not enough room. */
1105 int fraction_digits;
1107 /* Points to last digit that will remain in the fraction after
1109 char *final_frac_dig;
1116 assert (decimals > fp->d);
1117 if (decimals > LDBL_DIG)
1118 decimals = LDBL_DIG + 1;
1120 sprintf (buf, "%.*f", decimals, number);
1122 /* Omit integer part if it's 0. */
1123 if (!memcmp (buf, "0.", 2))
1124 memmove (buf, buf + 1, strlen (buf));
1125 else if (!memcmp (buf, "-0.", 3))
1126 memmove (buf + 1, buf + 2, strlen (buf + 1));
1128 predot_chars = strcspn (buf, ".");
1129 if (predot_chars > fp->w)
1131 /* Can't possibly fit. */
1134 else if (predot_chars == fp->w)
1136 /* Exact fit for integer part and sign. */
1137 memcpy (dst, buf, fp->w);
1140 else if (predot_chars + 1 == fp->w)
1142 /* There's room for the decimal point, but not for any
1143 digits of the fraction.
1144 Right-justify the integer part and sign. */
1146 memcpy (dst + 1, buf, fp->w);
1150 /* It looks like we have room for at least one digit of the
1151 fraction. Figure out how many. */
1152 fraction_digits = fp->w - predot_chars - 1;
1153 if (fraction_digits > fp->d)
1154 fraction_digits = fp->d;
1155 final_frac_dig = buf + predot_chars + fraction_digits;
1157 /* Decide rounding direction and truncate string. */
1158 if (final_frac_dig[1] == '5'
1159 && strspn (final_frac_dig + 2, "0") == strlen (final_frac_dig + 2))
1162 if (decimals <= LDBL_DIG)
1164 /* Don't have enough fractional digits to know which way to
1165 round. We can format with more decimal places, so go
1171 /* We used up all our fractional digits and still don't
1172 know. Round to even. */
1173 round_up = (final_frac_dig[0] - '0') % 2 != 0;
1177 round_up = final_frac_dig[1] >= '5';
1178 final_frac_dig[1] = '\0';
1183 char *cp = final_frac_dig;
1186 if (*cp >= '0' && *cp <= '8')
1191 else if (*cp == '9')
1194 assert (*cp == '.');
1196 if (cp == buf || *--cp == '-')
1200 /* Tried to go past the leftmost digit. Insert a 1. */
1201 memmove (cp + 1, cp, strlen (cp) + 1);
1204 length = strlen (buf);
1207 /* Inserting the `1' overflowed our space.
1208 Drop a decimal place. */
1209 buf[--length] = '\0';
1211 /* If that was the last decimal place, drop the
1212 decimal point too. */
1213 if (buf[length - 1] == '.')
1214 buf[length - 1] = '\0';
1222 /* Omit `-' if value output is zero. */
1223 if (buf[0] == '-' && buf[strspn (buf, "-.0")] == '\0')
1224 memmove (buf, buf + 1, strlen (buf));
1226 buf_copy_str_lpad (dst, fp->w, buf);
1230 /* Formats non-finite NUMBER into DST according to the width
1233 convert_infinite (char *dst, const struct fmt_spec *fp, double number)
1235 assert (!finite (number));
1243 else if (isinf (number))
1244 s = number > 0 ? "+Infinity" : "-Infinity";
1248 buf_copy_str_lpad (dst, fp->w, s);
1251 memset (dst, '*', fp->w);