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/assertion.h>
29 #include <libpspp/message.h>
31 #include <libpspp/magic.h>
32 #include <libpspp/misc.h>
33 #include <libpspp/misc.h>
35 #include <libpspp/str.h>
39 #define _(msgid) gettext (msgid)
41 /* Public functions. */
43 typedef int numeric_converter (char *, const struct fmt_spec *, double);
44 static numeric_converter convert_F, convert_N, convert_E, convert_F_plus;
45 static numeric_converter convert_Z, convert_IB, convert_P, convert_PIB;
46 static numeric_converter convert_PIBHEX, convert_PK, convert_RB;
47 static numeric_converter convert_RBHEX, convert_CCx, convert_date;
48 static numeric_converter convert_time, convert_WKDAY, convert_MONTH;
50 static numeric_converter try_F, convert_infinite;
52 typedef int string_converter (char *, const struct fmt_spec *, const char *);
53 static string_converter convert_A, convert_AHEX;
55 /* Converts binary value V into printable form in the exactly
56 FP->W character in buffer S according to format specification
57 FP. No null terminator is appended to the buffer. */
59 data_out (char *s, const struct fmt_spec *fp, const union value *v)
61 int cat = formats[fp->type].cat;
64 assert (check_output_specifier (fp, 0));
65 if (!(cat & FCAT_STRING))
67 /* Numeric formatting. */
70 /* Handle SYSMIS turning into blanks. */
71 if ((cat & FCAT_BLANKS_SYSMIS) && number == SYSMIS)
73 memset (s, ' ', fp->w);
74 s[fp->w - fp->d - 1] = '.';
78 /* Handle decimal shift. */
79 if ((cat & FCAT_SHIFT_DECIMAL) && number != SYSMIS && fp->d)
80 number *= pow (10.0, fp->d);
85 ok = convert_F (s, fp, number);
89 ok = convert_N (s, fp, number);
93 ok = convert_E (s, fp, number);
96 case FMT_COMMA: case FMT_DOT: case FMT_DOLLAR: case FMT_PCT:
97 ok = convert_F_plus (s, fp, number);
101 ok = convert_Z (s, fp, number);
111 ok = convert_IB (s, fp, number);
115 ok = convert_P (s, fp, number);
119 ok = convert_PIB (s, fp, number);
123 ok = convert_PIBHEX (s, fp, number);
127 ok = convert_PK (s, fp, number);
131 ok = convert_RB (s, fp, number);
135 ok = convert_RBHEX (s, fp, number);
138 case FMT_CCA: case FMT_CCB: case FMT_CCC: case FMT_CCD: case FMT_CCE:
139 ok = convert_CCx (s, fp, number);
142 case FMT_DATE: case FMT_EDATE: case FMT_SDATE: case FMT_ADATE:
143 case FMT_JDATE: case FMT_QYR: case FMT_MOYR: case FMT_WKYR:
145 ok = convert_date (s, fp, number);
148 case FMT_TIME: case FMT_DTIME:
149 ok = convert_time (s, fp, number);
153 ok = convert_WKDAY (s, fp, number);
157 ok = convert_MONTH (s, fp, number);
166 /* String formatting. */
167 const char *string = v->s;
172 ok = convert_A (s, fp, string);
176 ok = convert_AHEX (s, fp, string);
184 /* Error handling. */
186 strncpy (s, "ERROR", fp->w);
191 /* Main conversion functions. */
193 static void insert_commas (char *dst, const char *src,
194 const struct fmt_spec *fp);
195 static int year4 (int year);
196 static int try_CCx (char *s, const struct fmt_spec *fp, double v);
199 #error Write your own floating-point output routines.
202 /* Converts a number between 0 and 15 inclusive to a `hexit'
204 #define MAKE_HEXIT(X) ("0123456789ABCDEF"[X])
206 /* Table of powers of 10. */
207 static const double power10[] =
210 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, 1e09, 1e10,
211 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20,
212 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29, 1e30,
213 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39, 1e40,
216 /* Handles F format. */
218 convert_F (char *dst, const struct fmt_spec *fp, double number)
220 if (!try_F (dst, fp, number))
221 convert_E (dst, fp, number);
225 /* Handles N format. */
227 convert_N (char *dst, const struct fmt_spec *fp, double number)
229 double d = floor (number);
231 if (d < 0 || d == SYSMIS)
233 msg (ME, _("The N output format cannot be used to output a "
234 "negative number or the system-missing value."));
238 if (d < power10[fp->w])
241 sprintf (buf, "%0*.0f", fp->w, number);
242 memcpy (dst, buf, fp->w);
245 memset (dst, '*', fp->w);
250 /* Handles E format. Also operates as fallback for some other
253 convert_E (char *dst, const struct fmt_spec *fp, double number)
255 /* Temporary buffer. */
258 /* Ranged number of decimal places. */
261 if (!finite (number))
262 return convert_infinite (dst, fp, number);
264 /* Check that the format is wide enough.
265 Although PSPP generally checks this, convert_E() can be called as
266 a fallback from other formats which do not check. */
269 memset (dst, '*', fp->w);
273 /* Put decimal places in usable range. */
274 d = min (fp->d, fp->w - 6);
279 sprintf (buf, "%*.*E", fp->w, d, number);
281 /* What we do here is force the exponent part to have four
282 characters whenever possible. That is, 1.00E+99 is okay (`E+99')
283 but 1.00E+100 (`E+100') must be coerced to 1.00+100 (`+100'). On
284 the other hand, 1.00E1000 (`E+100') cannot be canonicalized.
285 Note that ANSI C guarantees at least two digits in the
287 if (fabs (number) > 1e99)
289 /* Pointer to the `E' in buf. */
292 cp = strchr (buf, 'E');
295 /* Exponent better not be bigger than an int. */
296 int exp = atoi (cp + 1);
298 if (abs (exp) > 99 && abs (exp) < 1000)
300 /* Shift everything left one place: 1.00e+100 -> 1.00+100. */
306 else if (abs (exp) >= 1000)
307 memset (buf, '*', fp->w);
311 /* The C locale always uses a period `.' as a decimal point.
312 Translate to comma if necessary. */
313 if ((get_decimal() == ',' && fp->type != FMT_DOT)
314 || (get_decimal() == '.' && fp->type == FMT_DOT))
316 char *cp = strchr (buf, '.');
321 memcpy (dst, buf, fp->w);
325 /* Handles COMMA, DOT, DOLLAR, and PCT formats. */
327 convert_F_plus (char *dst, const struct fmt_spec *fp, double number)
331 if (try_F (buf, fp, number))
332 insert_commas (dst, buf, fp);
334 convert_E (dst, fp, number);
340 convert_Z (char *dst, const struct fmt_spec *fp, double number)
342 static bool warned = false;
347 _("Quality of zoned decimal (Z) output format code is "
348 "suspect. Check your results. Report bugs to %s."),
353 if (number == SYSMIS)
355 msg (ME, _("The system-missing value cannot be output as a zoned "
365 d = fabs (floor (number));
366 if (d >= power10[fp->w])
368 msg (ME, _("Number %g too big to fit in field with format Z%d.%d."),
369 number, fp->w, fp->d);
373 sprintf (buf, "%*.0f", fp->w, number);
374 for (i = 0; i < fp->w; i++)
375 dst[i] = (buf[i] - '0') | 0xf0;
377 dst[fp->w - 1] &= 0xdf;
384 convert_A (char *dst, const struct fmt_spec *fp, const char *string)
386 memcpy(dst, string, fp->w);
391 convert_AHEX (char *dst, const struct fmt_spec *fp, const char *string)
395 for (i = 0; i < fp->w / 2; i++)
397 *dst++ = MAKE_HEXIT ((string[i]) >> 4);
398 *dst++ = MAKE_HEXIT ((string[i]) & 0xf);
405 convert_IB (char *dst, const struct fmt_spec *fp, double number)
407 /* Strategy: Basically the same as convert_PIBHEX() but with
408 base 256. Then negate the two's-complement result if number
411 /* Used for constructing the two's-complement result. */
414 /* Fraction (mantissa). */
420 /* Difference between exponent and (-8*fp->w-1). */
426 /* Make the exponent (-8*fp->w-1). */
427 frac = frexp (fabs (number), &exp);
428 diff = exp - (-8 * fp->w - 1);
430 frac *= ldexp (1.0, diff);
432 /* Extract each base-256 digit. */
433 for (i = 0; i < fp->w; i++)
437 temp[i] = floor (frac);
440 /* Perform two's-complement negation if number is negative. */
443 /* Perform NOT operation. */
444 for (i = 0; i < fp->w; i++)
446 /* Add 1 to the whole number. */
447 for (i = fp->w - 1; i >= 0; i--)
454 memcpy (dst, temp, fp->w);
455 #ifndef WORDS_BIGENDIAN
456 buf_reverse (dst, fp->w);
463 convert_P (char *dst, const struct fmt_spec *fp, double number)
465 /* Buffer for fp->w*2-1 characters + a decimal point if library is
466 not quite compliant + a null. */
472 /* Main extraction. */
473 sprintf (buf, "%0*.0f", fp->w * 2 - 1, floor (fabs (number)));
475 for (i = 0; i < fp->w; i++)
476 ((unsigned char *) dst)[i]
477 = ((buf[i * 2] - '0') << 4) + buf[i * 2 + 1] - '0';
480 dst[fp->w - 1] &= 0xf0;
482 dst[fp->w - 1] |= 0xf;
484 dst[fp->w - 1] |= 0xd;
490 convert_PIB (char *dst, const struct fmt_spec *fp, double number)
492 /* Strategy: Basically the same as convert_IB(). */
494 /* Fraction (mantissa). */
500 /* Difference between exponent and (-8*fp->w). */
506 /* Make the exponent (-8*fp->w). */
507 frac = frexp (fabs (number), &exp);
508 diff = exp - (-8 * fp->w);
510 frac *= ldexp (1.0, diff);
512 /* Extract each base-256 digit. */
513 for (i = 0; i < fp->w; i++)
517 ((unsigned char *) dst)[i] = floor (frac);
519 #ifndef WORDS_BIGENDIAN
520 buf_reverse (dst, fp->w);
527 convert_PIBHEX (char *dst, const struct fmt_spec *fp, double number)
529 /* Strategy: Use frexp() to create a normalized result (but mostly
530 to find the base-2 exponent), then change the base-2 exponent to
531 (-4*fp->w) using multiplication and division by powers of two.
532 Extract each hexit by multiplying by 16. */
534 /* Fraction (mantissa). */
540 /* Difference between exponent and (-4*fp->w). */
546 /* Make the exponent (-4*fp->w). */
547 frac = frexp (fabs (number), &exp);
548 diff = exp - (-4 * fp->w);
550 frac *= ldexp (1.0, diff);
552 /* Extract each hexit. */
553 for (i = 0; i < fp->w; i++)
557 *dst++ = MAKE_HEXIT ((int) floor (frac));
564 convert_PK (char *dst, const struct fmt_spec *fp, double number)
566 /* Buffer for fp->w*2 characters + a decimal point if library is not
567 quite compliant + a null. */
573 /* Main extraction. */
574 sprintf (buf, "%0*.0f", fp->w * 2, floor (fabs (number)));
576 for (i = 0; i < fp->w; i++)
577 ((unsigned char *) dst)[i]
578 = ((buf[i * 2] - '0') << 4) + buf[i * 2 + 1] - '0';
584 convert_RB (char *dst, const struct fmt_spec *fp, double number)
594 memcpy (dst, u.c, fp->w);
600 convert_RBHEX (char *dst, const struct fmt_spec *fp, double number)
612 for (i = 0; i < fp->w / 2; i++)
614 *dst++ = MAKE_HEXIT (u.c[i] >> 4);
615 *dst++ = MAKE_HEXIT (u.c[i] & 15);
622 convert_CCx (char *dst, const struct fmt_spec *fp, double number)
624 if (try_CCx (dst, fp, number))
634 return convert_F_plus (dst, &f, number);
639 convert_date (char *dst, const struct fmt_spec *fp, double number)
641 static const char *months[12] =
643 "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
644 "JUL", "AUG", "SEP", "OCT", "NOV", "DEC",
648 int ofs = number / 86400.;
649 int month, day, year;
654 calendar_offset_to_gregorian (ofs, &year, &month, &day);
659 sprintf (buf, "%02d-%s-%04d", day, months[month - 1], year);
661 sprintf (buf, "%02d-%s-%02d", day, months[month - 1], year % 100);
665 sprintf (buf, "%02d.%02d.%04d", day, month, year);
667 sprintf (buf, "%02d.%02d.%02d", day, month, year % 100);
671 sprintf (buf, "%04d/%02d/%02d", year, month, day);
673 sprintf (buf, "%02d/%02d/%02d", year % 100, month, day);
677 sprintf (buf, "%02d/%02d/%04d", month, day, year);
679 sprintf (buf, "%02d/%02d/%02d", month, day, year % 100);
683 int yday = calendar_offset_to_yday (ofs);
686 sprintf (buf, "%02d%03d", year % 100, yday);
687 else if (year4 (year))
688 sprintf (buf, "%04d%03d", year, yday);
694 sprintf (buf, "%d Q% 04d", (month - 1) / 3 + 1, year);
696 sprintf (buf, "%d Q% 02d", (month - 1) / 3 + 1, year % 100);
700 sprintf (buf, "%s% 04d", months[month - 1], year);
702 sprintf (buf, "%s% 02d", months[month - 1], year % 100);
706 int yday = calendar_offset_to_yday (ofs);
709 sprintf (buf, "%02d WK% 04d", (yday - 1) / 7 + 1, year);
711 sprintf (buf, "%02d WK% 02d", (yday - 1) / 7 + 1, year % 100);
718 cp = spprintf (buf, "%02d-%s-%04d %02d:%02d",
719 day, months[month - 1], year,
720 (int) fmod (floor (number / 60. / 60.), 24.),
721 (int) fmod (floor (number / 60.), 60.));
726 if (fp->w >= 22 && fp->d > 0)
728 d = min (fp->d, fp->w - 21);
737 cp = spprintf (cp, ":%0*.*f", w, d, fmod (number, 60.));
747 buf_copy_str_rpad (dst, fp->w, buf);
752 convert_time (char *dst, const struct fmt_spec *fp, double number)
760 if (fabs (number) > 1e20)
762 msg (ME, _("Time value %g too large in magnitude to convert to "
763 "alphanumeric time."), number);
771 *cp++ = '-', time = -time;
772 if (fp->type == FMT_DTIME)
774 double days = floor (time / 60. / 60. / 24.);
775 cp = spprintf (temp_buf, "%02.0f ", days);
776 time = time - days * 60. * 60. * 24.;
782 cp = spprintf (cp, "%02.0f:%02.0f",
783 fmod (floor (time / 60. / 60.), 24.),
784 fmod (floor (time / 60.), 60.));
790 if (width >= 10 && fp->d >= 0 && fp->d != 0)
791 d = min (fp->d, width - 9), w = 3 + d;
795 cp = spprintf (cp, ":%0*.*f", w, d, fmod (time, 60.));
797 buf_copy_str_rpad (dst, fp->w, temp_buf);
803 convert_WKDAY (char *dst, const struct fmt_spec *fp, double wkday)
805 static const char *weekdays[7] =
807 "SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY",
808 "THURSDAY", "FRIDAY", "SATURDAY",
811 if (wkday < 1 || wkday > 7)
813 msg (ME, _("Weekday index %f does not lie between 1 and 7."),
817 buf_copy_str_rpad (dst, fp->w, weekdays[(int) wkday - 1]);
823 convert_MONTH (char *dst, const struct fmt_spec *fp, double month)
825 static const char *months[12] =
827 "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
828 "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER",
831 if (month < 1 || month > 12)
833 msg (ME, _("Month index %f does not lie between 1 and 12."),
838 buf_copy_str_rpad (dst, fp->w, months[(int) month - 1]);
843 /* Helper functions. */
845 /* Copies SRC to DST, inserting commas and dollar signs as appropriate
846 for format spec *FP. */
848 insert_commas (char *dst, const char *src, const struct fmt_spec *fp)
850 /* Number of leading spaces in the number. This is the amount of
851 room we have for inserting commas and dollar signs. */
854 /* Number of digits before the decimal point. This is used to
855 determine the Number of commas to insert. */
858 /* Number of commas to insert. */
861 /* Number of items ,%$ to insert. */
864 /* Number of n_items items not to use for commas. */
867 /* Digit iterator. */
870 /* Source pointer. */
873 /* Count spaces and digits. */
875 while (sp < src + fp->w && *sp == ' ')
882 while (sp + n_digits < src + fp->w && isdigit ((unsigned char) sp[n_digits]))
884 n_commas = (n_digits - 1) / 3;
885 n_items = n_commas + (fp->type == FMT_DOLLAR || fp->type == FMT_PCT);
887 /* Check whether we have enough space to do insertions. */
888 if (!n_spaces || !n_items)
890 memcpy (dst, src, fp->w);
893 if (n_items > n_spaces)
898 memcpy (dst, src, fp->w);
903 /* Put spaces at the beginning if there's extra room. */
904 if (n_spaces > n_items)
906 memset (dst, ' ', n_spaces - n_items);
907 dst += n_spaces - n_items;
910 /* Insert $ and reserve space for %. */
912 if (fp->type == FMT_DOLLAR)
917 else if (fp->type == FMT_PCT)
920 /* Copy negative sign and digits, inserting commas. */
921 if (sp - src > n_spaces)
923 for (i = n_digits; i; i--)
925 if (i % 3 == 0 && n_digits > i && n_items > n_reserved)
928 *dst++ = fp->type == FMT_COMMA ? get_grouping() : get_decimal();
933 /* Copy decimal places and insert % if necessary. */
934 memcpy (dst, sp, fp->w - (sp - src));
935 if (fp->type == FMT_PCT && n_items > 0)
936 dst[fp->w - (sp - src)] = '%';
939 /* Returns 1 if YEAR (i.e., 1987) can be represented in four digits, 0
944 if (year >= 1 && year <= 9999)
946 msg (ME, _("Year %d cannot be represented in four digits for "
947 "output formatting purposes."), year);
952 try_CCx (char *dst, const struct fmt_spec *fp, double number)
954 const struct custom_currency *cc = get_cc(fp->type - FMT_CCA);
962 /* Determine length available, decimal character for number
964 f.type = cc->decimal == get_decimal () ? FMT_COMMA : FMT_DOT;
965 f.w = fp->w - strlen (cc->prefix) - strlen (cc->suffix);
967 f.w -= strlen (cc->neg_prefix) + strlen (cc->neg_suffix) - 1;
969 /* Convert -0 to +0. */
970 number = fabs (number);
976 /* There's room for all that currency crap. Let's do the F
978 if (!convert_F (buf, &f, number) || *buf == '*')
980 insert_commas (buf2, buf, &f);
982 /* Postprocess back into buf. */
985 cp = stpcpy (cp, cc->neg_prefix);
986 cp = stpcpy (cp, cc->prefix);
992 assert ((number >= 0) ^ (*bp == '-'));
996 memcpy (cp, bp, f.w - (bp - buf2));
997 cp += f.w - (bp - buf2);
999 cp = stpcpy (cp, cc->suffix);
1001 cp = stpcpy (cp, cc->neg_suffix);
1003 /* Copy into dst. */
1004 assert (cp - buf <= fp->w);
1005 if (cp - buf < fp->w)
1007 memcpy (&dst[fp->w - (cp - buf)], buf, cp - buf);
1008 memset (dst, ' ', fp->w - (cp - buf));
1011 memcpy (dst, buf, fp->w);
1017 format_and_round (char *dst, double number, const struct fmt_spec *fp,
1020 /* Tries to format NUMBER into DST as the F format specified in
1021 *FP. Return true if successful, false on failure. */
1023 try_F (char *dst, const struct fmt_spec *fp, double number)
1025 assert (fp->w <= 40);
1026 if (finite (number))
1028 if (fabs (number) < power10[fp->w])
1030 /* The value may fit in the field. */
1033 /* There are no decimal places, so there's no way
1034 that the value can be shortened. Either it fits
1037 sprintf (buf, "%*.0f", fp->w, number);
1038 if (strlen (buf) <= fp->w)
1040 buf_copy_str_lpad (dst, fp->w, buf);
1048 /* First try to format it with 2 extra decimal
1049 places. This gives us a good chance of not
1050 needing even more decimal places, but it also
1051 avoids wasting too much time formatting more
1052 decimal places on the first try. */
1053 int result = format_and_round (dst, number, fp, fp->d + 2);
1058 /* 2 extra decimal places weren't enough to
1059 correctly round. Try again with the maximum
1060 number of places. */
1061 return format_and_round (dst, number, fp, LDBL_DIG + 1);
1066 /* The value is too big to fit in the field. */
1071 return convert_infinite (dst, fp, number);
1074 /* Tries to compose NUMBER into DST in format FP by first
1075 formatting it with DECIMALS decimal places, then rounding off
1076 to as many decimal places will fit or the number specified in
1077 FP, whichever is fewer.
1079 Returns 1 if conversion succeeds, 0 if this try at conversion
1080 failed and so will any other tries (because the integer part
1081 of the number is too long), or -1 if this try failed but
1082 another with higher DECIMALS might succeed (because we'd be
1083 able to properly round). */
1085 format_and_round (char *dst, double number, const struct fmt_spec *fp,
1088 /* Number of characters before the decimal point,
1089 which includes digits and possibly a minus sign. */
1092 /* Number of digits in the output fraction,
1093 which may be smaller than fp->d if there's not enough room. */
1094 int fraction_digits;
1096 /* Points to last digit that will remain in the fraction after
1098 char *final_frac_dig;
1105 assert (decimals > fp->d);
1106 if (decimals > LDBL_DIG)
1107 decimals = LDBL_DIG + 1;
1109 sprintf (buf, "%.*f", decimals, number);
1111 /* Omit integer part if it's 0. */
1112 if (!memcmp (buf, "0.", 2))
1113 memmove (buf, buf + 1, strlen (buf));
1114 else if (!memcmp (buf, "-0.", 3))
1115 memmove (buf + 1, buf + 2, strlen (buf + 1));
1117 predot_chars = strcspn (buf, ".");
1118 if (predot_chars > fp->w)
1120 /* Can't possibly fit. */
1123 else if (predot_chars == fp->w)
1125 /* Exact fit for integer part and sign. */
1126 memcpy (dst, buf, fp->w);
1129 else if (predot_chars + 1 == fp->w)
1131 /* There's room for the decimal point, but not for any
1132 digits of the fraction.
1133 Right-justify the integer part and sign. */
1135 memcpy (dst + 1, buf, fp->w - 1);
1139 /* It looks like we have room for at least one digit of the
1140 fraction. Figure out how many. */
1141 fraction_digits = fp->w - predot_chars - 1;
1142 if (fraction_digits > fp->d)
1143 fraction_digits = fp->d;
1144 final_frac_dig = buf + predot_chars + fraction_digits;
1146 /* Decide rounding direction and truncate string. */
1147 if (final_frac_dig[1] == '5'
1148 && strspn (final_frac_dig + 2, "0") == strlen (final_frac_dig + 2))
1151 if (decimals <= LDBL_DIG)
1153 /* Don't have enough fractional digits to know which way to
1154 round. We can format with more decimal places, so go
1160 /* We used up all our fractional digits and still don't
1161 know. Round to even. */
1162 round_up = (final_frac_dig[0] - '0') % 2 != 0;
1166 round_up = final_frac_dig[1] >= '5';
1167 final_frac_dig[1] = '\0';
1172 char *cp = final_frac_dig;
1175 if (*cp >= '0' && *cp <= '8')
1180 else if (*cp == '9')
1183 assert (*cp == '.');
1185 if (cp == buf || *--cp == '-')
1189 /* Tried to go past the leftmost digit. Insert a 1. */
1190 memmove (cp + 1, cp, strlen (cp) + 1);
1193 length = strlen (buf);
1196 /* Inserting the `1' overflowed our space.
1197 Drop a decimal place. */
1198 buf[--length] = '\0';
1200 /* If that was the last decimal place, drop the
1201 decimal point too. */
1202 if (buf[length - 1] == '.')
1203 buf[length - 1] = '\0';
1211 /* Omit `-' if value output is zero. */
1212 if (buf[0] == '-' && buf[strspn (buf, "-.0")] == '\0')
1213 memmove (buf, buf + 1, strlen (buf));
1215 buf_copy_str_lpad (dst, fp->w, buf);
1219 /* Formats non-finite NUMBER into DST according to the width
1222 convert_infinite (char *dst, const struct fmt_spec *fp, double number)
1224 assert (!finite (number));
1232 else if (isinf (number))
1233 s = number > 0 ? "+Infinity" : "-Infinity";
1237 buf_copy_str_lpad (dst, fp->w, s);
1240 memset (dst, '*', fp->w);