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., 59 Temple Place - Suite 330, Boston, MA
30 #include "julcal/julcal.h"
39 /*#define DEBUGGING 1*/
40 #include "debug-print.h"
42 /* In older versions, numbers got their trailing zeros stripped.
43 Newer versions leave them on when there's room. Comment this next
44 line out for retro styling. */
47 /* Public functions. */
49 typedef int convert_func (char *, const struct fmt_spec *,
52 static convert_func convert_F, convert_N, convert_E, convert_F_plus;
53 static convert_func convert_Z, convert_A, convert_AHEX, convert_IB;
54 static convert_func convert_P, convert_PIB, convert_PIBHEX, convert_PK;
55 static convert_func convert_RB, convert_RBHEX, convert_CCx, convert_date;
56 static convert_func convert_time, convert_WKDAY, convert_MONTH;
57 static convert_func try_F;
59 /* Converts binary value V into printable form in string S according
60 to format specification FP. The string as written has exactly
61 FP->W characters. It is not null-terminated. Returns 1 on
62 success, 0 on failure. */
64 data_out (char *s, const struct fmt_spec *fp, const union value *v)
69 int cat = formats[fp->type].cat;
70 if ((cat & FCAT_BLANKS_SYSMIS) && v->f == SYSMIS)
72 memset (s, ' ', fp->w);
73 s[fp->w - fp->d - 1] = '.';
76 if ((cat & FCAT_SHIFT_DECIMAL) && v->f != SYSMIS && fp->d)
78 tmp_val.f = v->f * pow (10.0, fp->d);
84 static convert_func *const handlers[FMT_NUMBER_OF_FORMATS] =
86 convert_F, convert_N, convert_E, convert_F_plus,
87 convert_F_plus, convert_F_plus, convert_F_plus,
88 convert_Z, convert_A, convert_AHEX, convert_IB, convert_P, convert_PIB,
89 convert_PIBHEX, convert_PK, convert_RB, convert_RBHEX,
90 convert_CCx, convert_CCx, convert_CCx, convert_CCx, convert_CCx,
91 convert_date, convert_date, convert_date, convert_date, convert_date,
92 convert_date, convert_date, convert_date, convert_date,
93 convert_time, convert_time,
94 convert_WKDAY, convert_MONTH,
97 return handlers[fp->type] (s, fp, v);
101 /* Converts V into S in F format with width W and D decimal places,
102 then deletes trailing zeros. S is not null-terminated. */
104 num_to_string (double v, char *s, int w, int d)
106 /* Dummies to pass to convert_F. */
111 /* Pointer to `.' in S. */
114 /* Pointer to `E' in S. */
117 /* Number of characters to delete. */
125 /* Cut out the jokers. */
133 memcpy (temp, "NaN", 3);
138 memcpy (temp, "+Infinity", 9);
145 memcpy (temp, _("Unknown"), 7);
151 memset (s, ' ', pad);
162 decp = memchr (s, set_decimal, w);
166 /* If there's an `E' we can only delete 0s before the E. */
167 expp = memchr (s, 'E', w);
170 while (expp[-n - 1] == '0')
172 if (expp[-n - 1] == set_decimal)
174 memmove (&s[n], s, expp - s - n);
179 /* Otherwise delete all trailing 0s. */
181 while (s[w - n] == '0')
183 if (s[w - n] != set_decimal)
185 /* Avoid stripping `.0' to `'. */
186 if (w == n || !isdigit ((unsigned char) s[w - n - 1]))
191 memmove (&s[n], s, w - n);
196 /* Main conversion functions. */
198 static void insert_commas (char *dst, const char *src,
199 const struct fmt_spec *fp);
200 static int year4 (int year);
201 static int try_CCx (char *s, const struct fmt_spec *fp, double v);
204 #error Write your own floating-point output routines.
209 Some of the routines in this file are likely very specific to
210 base-2 representation of floating-point numbers, most notably the
211 routines that use frexp() or ldexp(). These attempt to extract
212 individual digits by setting the base-2 exponent and
213 multiplying/dividing by powers of 2. In base-2 numeration systems,
214 this just nudges the exponent up or down, but in base-10 floating
215 point, such multiplications/division can cause catastrophic loss of
218 The author has never personally used a machine that didn't use
219 binary floating point formats, so he is unwilling, and perhaps
220 unable, to code around this "problem". */
222 /* Converts a number between 0 and 15 inclusive to a `hexit'
224 #define MAKE_HEXIT(X) ("0123456789ABCDEF"[X])
226 /* Table of powers of 10. */
227 static const double power10[] =
230 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, 1e09, 1e10,
231 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20,
232 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29, 1e30,
233 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39, 1e40,
236 /* Handles F format. */
238 convert_F (char *dst, const struct fmt_spec *fp, const union value *v)
240 if (!try_F (dst, fp, v))
241 convert_E (dst, fp, v);
245 /* Handles N format. */
247 convert_N (char *dst, const struct fmt_spec *fp, const union value *v)
249 double d = floor (v->f);
251 if (d < 0 || d == SYSMIS)
253 msg (ME, _("The N output format cannot be used to output a "
254 "negative number or the system-missing value."));
258 if (d < power10[fp->w])
261 sprintf (buf, "%0*.0f", fp->w, v->f);
262 memcpy (dst, buf, fp->w);
265 memset (dst, '*', fp->w);
270 /* Handles E format. Also operates as fallback for some other
273 convert_E (char *dst, const struct fmt_spec *fp, const union value *v)
275 /* Temporary buffer. */
278 /* Ranged number of decimal places. */
281 /* Check that the format is width enough.
282 Although PSPP generally checks this, convert_E() can be called as
283 a fallback from other formats which do not check. */
286 memset (dst, '*', fp->w);
290 /* Put decimal places in usable range. */
291 d = min (fp->d, fp->w - 6);
296 sprintf (buf, "%*.*E", fp->w, d, v->f);
298 /* What we do here is force the exponent part to have four
299 characters whenever possible. That is, 1.00E+99 is okay (`E+99')
300 but 1.00E+100 (`E+100') must be coerced to 1.00+100 (`+100'). On
301 the other hand, 1.00E1000 (`E+100') cannot be canonicalized.
302 Note that ANSI C guarantees at least two digits in the
304 if (fabs (v->f) > 1e99)
306 /* Pointer to the `E' in buf. */
309 cp = strchr (buf, 'E');
312 /* Exponent better not be bigger than an int. */
313 int exp = atoi (cp + 1);
315 if (abs (exp) > 99 && abs (exp) < 1000)
317 /* Shift everything left one place: 1.00e+100 -> 1.00+100. */
323 else if (abs (exp) >= 1000)
324 memset (buf, '*', fp->w);
328 /* The C locale always uses a period `.' as a decimal point.
329 Translate to comma if necessary. */
330 if ((set_decimal == ',' && fp->type != FMT_DOT)
331 || (set_decimal == '.' && fp->type == FMT_DOT))
333 char *cp = strchr (buf, '.');
338 memcpy (dst, buf, fp->w);
342 /* Handles COMMA, DOT, DOLLAR, and PCT formats. */
344 convert_F_plus (char *dst, const struct fmt_spec *fp, const union value *v)
348 if (try_F (buf, fp, v))
349 insert_commas (dst, buf, fp);
351 convert_E (dst, fp, v);
357 convert_Z (char *dst, const struct fmt_spec *fp, const union value *v)
359 static int warned = 0;
363 msg (MW, _("Quality of zoned decimal (Z) output format code is "
364 "suspect. Check your results, report bugs to author."));
370 msg (ME, _("The system-missing value cannot be output as a zoned "
380 d = fabs (floor (v->f));
381 if (d >= power10[fp->w])
383 msg (ME, _("Number %g too big to fit in field with format Z%d.%d."),
388 sprintf (buf, "%*.0f", fp->w, v->f);
389 for (i = 0; i < fp->w; i++)
390 dst[i] = (buf[i] - '0') | 0xf0;
392 dst[fp->w - 1] &= 0xdf;
399 convert_A (char *dst, const struct fmt_spec *fp, const union value *v)
401 memcpy (dst, v->c, fp->w);
406 convert_AHEX (char *dst, const struct fmt_spec *fp, const union value *v)
410 for (i = 0; i < fp->w / 2; i++)
412 ((unsigned char *) dst)[i * 2] = MAKE_HEXIT ((v->c[i]) >> 4);
413 ((unsigned char *) dst)[i * 2 + 1] = MAKE_HEXIT ((v->c[i]) & 0xf);
420 convert_IB (char *dst, const struct fmt_spec *fp, const union value *v)
422 /* Strategy: Basically the same as convert_PIBHEX() but with base
423 256. Then it's necessary to negate the two's-complement result if
426 /* Used for constructing the two's-complement result. */
429 /* Fraction (mantissa). */
435 /* Difference between exponent and (-8*fp->w-1). */
441 /* Make the exponent (-8*fp->w-1). */
442 frac = frexp (fabs (v->f), &exp);
443 diff = exp - (-8 * fp->w - 1);
445 frac *= ldexp (1.0, diff);
447 /* Extract each base-256 digit. */
448 for (i = 0; i < fp->w; i++)
452 temp[i] = floor (frac);
455 /* Perform two's-complement negation if v->f is negative. */
458 /* Perform NOT operation. */
459 for (i = 0; i < fp->w; i++)
461 /* Add 1 to the whole number. */
462 for (i = fp->w - 1; i >= 0; i--)
469 memcpy (dst, temp, fp->w);
470 #ifndef WORDS_BIGENDIAN
471 mm_reverse (dst, fp->w);
478 convert_P (char *dst, const struct fmt_spec *fp, const union value *v)
480 /* Buffer for v->f*2-1 characters + a decimal point if library is
481 not quite compliant + a null. */
487 /* Main extraction. */
488 sprintf (buf, "%0*.0f", fp->w * 2 - 1, floor (fabs (v->f)));
490 for (i = 0; i < fp->w; i++)
491 ((unsigned char *) dst)[i]
492 = ((buf[i * 2] - '0') << 4) + buf[i * 2 + 1] - '0';
495 dst[fp->w - 1] &= 0xf0;
497 dst[fp->w - 1] |= 0xf;
499 dst[fp->w - 1] |= 0xd;
505 convert_PIB (char *dst, const struct fmt_spec *fp, const union value *v)
507 /* Strategy: Basically the same as convert_IB(). */
509 /* Fraction (mantissa). */
515 /* Difference between exponent and (-8*fp->w). */
521 /* Make the exponent (-8*fp->w). */
522 frac = frexp (fabs (v->f), &exp);
523 diff = exp - (-8 * fp->w);
525 frac *= ldexp (1.0, diff);
527 /* Extract each base-256 digit. */
528 for (i = 0; i < fp->w; i++)
532 ((unsigned char *) dst)[i] = floor (frac);
534 #ifndef WORDS_BIGENDIAN
535 mm_reverse (dst, fp->w);
542 convert_PIBHEX (char *dst, const struct fmt_spec *fp, const union value *v)
544 /* Strategy: Use frexp() to create a normalized result (but mostly
545 to find the base-2 exponent), then change the base-2 exponent to
546 (-4*fp->w) using multiplication and division by powers of two.
547 Extract each hexit by multiplying by 16. */
549 /* Fraction (mantissa). */
555 /* Difference between exponent and (-4*fp->w). */
561 /* Make the exponent (-4*fp->w). */
562 frac = frexp (fabs (v->f), &exp);
563 diff = exp - (-4 * fp->w);
565 frac *= ldexp (1.0, diff);
567 /* Extract each hexit. */
568 for (i = 0; i < fp->w; i++)
572 *dst++ = MAKE_HEXIT ((int) floor (frac));
579 convert_PK (char *dst, const struct fmt_spec *fp, const union value *v)
581 /* Buffer for v->f*2 characters + a decimal point if library is not
582 quite compliant + a null. */
588 /* Main extraction. */
589 sprintf (buf, "%0*.0f", fp->w * 2, floor (fabs (v->f)));
591 for (i = 0; i < fp->w; i++)
592 ((unsigned char *) dst)[i]
593 = ((buf[i * 2] - '0') << 4) + buf[i * 2 + 1] - '0';
599 convert_RB (char *dst, const struct fmt_spec *fp, const union value *v)
609 memcpy (dst, u.c, fp->w);
615 convert_RBHEX (char *dst, const struct fmt_spec *fp, const union value *v)
627 for (i = 0; i < fp->w / 2; i++)
629 *dst++ = MAKE_HEXIT (u.c[i] >> 4);
630 *dst++ = MAKE_HEXIT (u.c[i] & 15);
637 convert_CCx (char *dst, const struct fmt_spec *fp, const union value *v)
639 if (try_CCx (dst, fp, v->f))
649 return convert_F (dst, &f, v);
654 convert_date (char *dst, const struct fmt_spec *fp, const union value *v)
656 static const char *months[12] =
658 "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
659 "JUL", "AUG", "SEP", "OCT", "NOV", "DEC",
663 int month, day, year;
665 julian_to_calendar (v->f / 86400., &year, &month, &day);
670 sprintf (buf, "%02d-%s-%04d", day, months[month - 1], year);
672 sprintf (buf, "%02d-%s-%02d", day, months[month - 1], year % 100);
676 sprintf (buf, "%02d.%02d.%04d", day, month, year);
678 sprintf (buf, "%02d.%02d.%02d", day, month, year % 100);
682 sprintf (buf, "%04d/%02d/%02d", year, month, day);
684 sprintf (buf, "%02d/%02d/%02d", year % 100, month, day);
688 sprintf (buf, "%02d/%02d/%04d", month, day, year);
690 sprintf (buf, "%02d/%02d/%02d", month, day, year % 100);
694 int yday = (v->f / 86400.) - calendar_to_julian (year, 1, 1) + 1;
699 sprintf (buf, "%04d%03d", year, yday);
702 sprintf (buf, "%02d%03d", year % 100, yday);
707 sprintf (buf, "%d Q% 04d", (month - 1) / 3 + 1, year);
709 sprintf (buf, "%d Q% 02d", (month - 1) / 3 + 1, year % 100);
713 sprintf (buf, "%s% 04d", months[month - 1], year);
715 sprintf (buf, "%s% 02d", months[month - 1], year % 100);
719 int yday = (v->f / 86400.) - calendar_to_julian (year, 1, 1) + 1;
722 sprintf (buf, "%02d WK% 04d", (yday - 1) / 7 + 1, year);
724 sprintf (buf, "%02d WK% 02d", (yday - 1) / 7 + 1, year % 100);
731 cp = spprintf (buf, "%02d-%s-%04d %02d:%02d",
732 day, months[month - 1], year,
733 (int) fmod (floor (v->f / 60. / 60.), 24.),
734 (int) fmod (floor (v->f / 60.), 60.));
739 if (fp->w >= 22 && fp->d > 0)
741 d = min (fp->d, fp->w - 21);
750 cp = spprintf (cp, ":%0*.*f", w, d, fmod (v->f, 60.));
764 st_bare_pad_copy (dst, buf, fp->w);
769 convert_time (char *dst, const struct fmt_spec *fp, const union value *v)
777 if (fabs (v->f) > 1e20)
779 msg (ME, _("Time value %g too large in magnitude to convert to "
780 "alphanumeric time."), v->f);
788 *cp++ = '-', time = -time;
789 if (fp->type == FMT_DTIME)
791 double days = floor (time / 60. / 60. / 24.);
792 cp = spprintf (temp_buf, "%02.0f ", days);
793 time = time - days * 60. * 60. * 24.;
799 cp = spprintf (cp, "%02.0f:%02.0f",
800 fmod (floor (time / 60. / 60.), 24.),
801 fmod (floor (time / 60.), 60.));
807 if (width >= 10 && fp->d >= 0 && fp->d != 0)
808 d = min (fp->d, width - 9), w = 3 + d;
812 cp = spprintf (cp, ":%0*.*f", w, d, fmod (time, 60.));
814 st_bare_pad_copy (dst, temp_buf, fp->w);
820 convert_WKDAY (char *dst, const struct fmt_spec *fp, const union value *v)
822 static const char *weekdays[7] =
824 "SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY",
825 "THURSDAY", "FRIDAY", "SATURDAY",
832 msg (ME, _("Weekday index %d does not lie between 1 and 7."), x);
835 st_bare_pad_copy (dst, weekdays[x - 1], fp->w);
841 convert_MONTH (char *dst, const struct fmt_spec *fp, const union value *v)
843 static const char *months[12] =
845 "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
846 "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER",
853 msg (ME, _("Month index %d does not lie between 1 and 12."), x);
857 st_bare_pad_copy (dst, months[x - 1], fp->w);
862 /* Helper functions. */
864 /* Copies SRC to DST, inserting commas and dollar signs as appropriate
865 for format spec *FP. */
867 insert_commas (char *dst, const char *src, const struct fmt_spec *fp)
869 /* Number of leading spaces in the number. This is the amount of
870 room we have for inserting commas and dollar signs. */
873 /* Number of digits before the decimal point. This is used to
874 determine the Number of commas to insert. */
877 /* Number of commas to insert. */
880 /* Number of items ,%$ to insert. */
883 /* Number of n_items items not to use for commas. */
886 /* Digit iterator. */
889 /* Source pointer. */
892 /* Count spaces and digits. */
894 while (sp < src + fp->w && *sp == ' ')
901 while (sp + n_digits < src + fp->w && isdigit ((unsigned char) sp[n_digits]))
903 n_commas = (n_digits - 1) / 3;
904 n_items = n_commas + (fp->type == FMT_DOLLAR || fp->type == FMT_PCT);
906 /* Check whether we have enough space to do insertions. */
907 if (!n_spaces || !n_items)
909 memcpy (dst, src, fp->w);
912 if (n_items > n_spaces)
917 memcpy (dst, src, fp->w);
922 /* Put spaces at the beginning if there's extra room. */
923 if (n_spaces > n_items)
925 memset (dst, ' ', n_spaces - n_items);
926 dst += n_spaces - n_items;
929 /* Insert $ and reserve space for %. */
931 if (fp->type == FMT_DOLLAR)
936 else if (fp->type == FMT_PCT)
939 /* Copy negative sign and digits, inserting commas. */
940 if (sp - src > n_spaces)
942 for (i = n_digits; i; i--)
944 if (i % 3 == 0 && n_digits > i && n_items > n_reserved)
947 *dst++ = fp->type == FMT_COMMA ? set_grouping : set_decimal;
952 /* Copy decimal places and insert % if necessary. */
953 memcpy (dst, sp, fp->w - (sp - src));
954 if (fp->type == FMT_PCT && n_items > 0)
955 dst[fp->w - (sp - src)] = '%';
958 /* Returns 1 if YEAR (i.e., 1987) can be represented in four digits, 0
963 if (year >= 1 && year <= 9999)
965 msg (ME, _("Year %d cannot be represented in four digits for "
966 "output formatting purposes."), year);
971 try_CCx (char *dst, const struct fmt_spec *fp, double v)
973 struct set_cust_currency *cc = &set_cc[fp->type - FMT_CCA];
981 /* Determine length available, decimal character for number
983 f.type = cc->decimal == set_decimal ? FMT_COMMA : FMT_DOT;
984 f.w = fp->w - strlen (cc->prefix) - strlen (cc->suffix);
986 f.w -= strlen (cc->neg_prefix) + strlen (cc->neg_suffix) - 1;
988 /* Convert -0 to +0. */
995 /* There's room for all that currency crap. Let's do the F
997 if (!convert_F (buf, &f, (union value *) &v) || *buf == '*')
999 insert_commas (buf2, buf, &f);
1001 /* Postprocess back into buf. */
1004 cp = stpcpy (cp, cc->neg_prefix);
1005 cp = stpcpy (cp, cc->prefix);
1011 assert ((v >= 0) ^ (*bp == '-'));
1015 memcpy (cp, bp, f.w - (bp - buf2));
1016 cp += f.w - (bp - buf2);
1018 cp = stpcpy (cp, cc->suffix);
1020 cp = stpcpy (cp, cc->neg_suffix);
1022 /* Copy into dst. */
1023 assert (cp - buf <= fp->w);
1024 if (cp - buf < fp->w)
1026 memcpy (&dst[fp->w - (cp - buf)], buf, cp - buf);
1027 memset (dst, ' ', fp->w - (cp - buf));
1030 memcpy (dst, buf, fp->w);
1035 /* This routine relies on the underlying implementation of sprintf:
1037 If the number has a magnitude 1e40 or greater, then we needn't
1038 bother with it, since it's guaranteed to need processing in
1039 scientific notation.
1041 Otherwise, do a binary search for the base-10 magnitude of the
1042 thing. log10() is not accurate enough, and the alternatives are
1043 frightful. Besides, we never need as many as 6 (pairs of)
1044 comparisons. The algorithm used for searching is Knuth's Algorithm
1045 6.2.1C (Uniform binary search).
1047 DON'T CHANGE ANYTHING HERE UNLESS YOU'VE THOUGHT ABOUT IT FOR A
1048 LONG TIME! The rest of the program is heavily dependent on
1049 specific properties of this routine's output. LOG ALL CHANGES! */
1051 try_F (char *dst, const struct fmt_spec *fp, const union value *value)
1053 /* This is the DELTA array from Knuth.
1054 DELTA[j] = floor((40+2**(j-1))/(2**j)). */
1055 static const int delta[8] =
1057 0, (40 + 1) / 2, (40 + 2) / 4, (40 + 4) / 8, (40 + 8) / 16,
1058 (40 + 16) / 32, (40 + 32) / 64, (40 + 64) / 128,
1061 /* The number of digits in floor(v), including sign. This is `i'
1063 int n_int = (40 + 1) / 2;
1065 /* Used to step through delta[]. This is `j' from Knuth. */
1069 double v = value->f;
1071 /* Magnitude of v. This is `K' from Knuth. */
1074 /* Number of characters for the fractional part, including the
1078 /* Pointer into buf used for formatting. */
1081 /* Used to count characters formatted by nsprintf(). */
1084 /* Temporary buffer. */
1087 /* First check for infinities and NaNs. 12/13/96. */
1090 n = nsprintf (buf, "%f", v);
1092 memset (buf, '*', fp->w);
1095 memmove (&buf[fp->w - n], buf, n);
1096 memset (buf, ' ', fp->w - n);
1098 memcpy (dst, buf, fp->w);
1102 /* Then check for radically out-of-range values. */
1104 if (mag >= power10[fp->w])
1111 /* Avoid printing `-.000'. 7/6/96. */
1112 if (approx_eq (v, 0.0))
1116 /* Now perform a `uniform binary search' based on the tables
1117 power10[] and delta[]. After this step, nint is the number of
1118 digits in floor(v), including any sign. */
1121 if (mag >= power10[n_int]) /* Should this be approx_ge()? */
1124 n_int += delta[j++];
1126 else if (mag < power10[n_int - 1])
1129 n_int -= delta[j++];
1135 /* If we have any decimal places, then there is a decimal point,
1141 /* 1/10/96: If there aren't any digits at all, add one. This occurs
1142 only when fabs(v) < 1.0. */
1143 if (n_int + n_dec == 0)
1146 /* Give space for a minus sign. Moved 1/10/96. */
1150 /* Normally we only go through the loop once; occasionally twice.
1151 Three times or more indicates a very serious bug somewhere. */
1154 /* Check out the total length of the string. */
1156 if (n_int + n_dec > fp->w)
1158 /* The string is too long. Let's see what can be done. */
1160 /* If we can, just reduce the number of decimal places. */
1161 n_dec = fp->w - n_int;
1165 else if (n_int + n_dec < fp->w)
1167 /* The string is too short. Left-pad with spaces. */
1168 int n_spaces = fp->w - n_int - n_dec;
1169 memset (cp, ' ', n_spaces);
1173 /* Finally, format the number. */
1175 n = nsprintf (cp, "%.*f", n_dec - 1, v);
1177 n = nsprintf (cp, "%.0f", v);
1179 /* If v is positive and its magnitude is less than 1... */
1184 /* The value rounds to `.###'. */
1185 memmove (cp, &cp[1], n - 1);
1190 /* The value rounds to `1.###'. */
1195 /* Else if v is negative and its magnitude is less than 1... */
1196 else if (v < 0 && n_int == 1)
1200 /* The value rounds to `-.###'. */
1201 memmove (&cp[1], &cp[2], n - 2);
1206 /* The value rounds to `-1.###'. */
1212 /* Check for a correct number of digits & decimal places & stuff.
1213 This is just a desperation check. Hopefully it won't fail too
1214 often, because then we have to run through the whole loop again:
1215 sprintf() is not a fast operation with floating-points! */
1216 if (n == n_int + n_dec)
1218 /* Convert periods `.' to commas `,' for our foreign friends. */
1219 if ((set_decimal == ',' && fp->type != FMT_DOT)
1220 || (set_decimal == '.' && fp->type == FMT_DOT))
1222 cp = strchr (cp, '.');
1227 memcpy (dst, buf, fp->w);
1231 n_int = n - n_dec; /* FIXME? Need an idiot check on resulting n_int? */