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"
38 #include "debug-print.h"
40 /* In older versions, numbers got their trailing zeros stripped.
41 Newer versions leave them on when there's room. Comment this next
42 line out for retro styling. */
45 /* Public functions. */
47 typedef int convert_func (char *, const struct fmt_spec *,
50 static convert_func convert_F, convert_N, convert_E, convert_F_plus;
51 static convert_func convert_Z, convert_A, convert_AHEX, convert_IB;
52 static convert_func convert_P, convert_PIB, convert_PIBHEX, convert_PK;
53 static convert_func convert_RB, convert_RBHEX, convert_CCx, convert_date;
54 static convert_func convert_time, convert_WKDAY, convert_MONTH;
55 static convert_func try_F;
57 /* Converts binary value V into printable form in string S according
58 to format specification FP. The string as written has exactly
59 FP->W characters. It is not null-terminated. Returns 1 on
60 success, 0 on failure. */
62 data_out (char *s, const struct fmt_spec *fp, const union value *v)
67 int cat = formats[fp->type].cat;
68 if ((cat & FCAT_BLANKS_SYSMIS) && v->f == SYSMIS)
70 memset (s, ' ', fp->w);
71 s[fp->w - fp->d - 1] = '.';
74 if ((cat & FCAT_SHIFT_DECIMAL) && v->f != SYSMIS && fp->d)
76 tmp_val.f = v->f * pow (10.0, fp->d);
82 static convert_func *const handlers[FMT_NUMBER_OF_FORMATS] =
84 convert_F, convert_N, convert_E, convert_F_plus,
85 convert_F_plus, convert_F_plus, convert_F_plus,
86 convert_Z, convert_A, convert_AHEX, convert_IB, convert_P, convert_PIB,
87 convert_PIBHEX, convert_PK, convert_RB, convert_RBHEX,
88 convert_CCx, convert_CCx, convert_CCx, convert_CCx, convert_CCx,
89 convert_date, convert_date, convert_date, convert_date, convert_date,
90 convert_date, convert_date, convert_date, convert_date,
91 convert_time, convert_time,
92 convert_WKDAY, convert_MONTH,
95 return handlers[fp->type] (s, fp, v);
99 /* Converts V into S in F format with width W and D decimal places,
100 then deletes trailing zeros. S is not null-terminated. */
102 num_to_string (double v, char *s, int w, int d)
104 /* Dummies to pass to convert_F. */
109 /* Pointer to `.' in S. */
112 /* Pointer to `E' in S. */
115 /* Number of characters to delete. */
123 /* Cut out the jokers. */
131 memcpy (temp, "NaN", 3);
136 memcpy (temp, "+Infinity", 9);
143 memcpy (temp, _("Unknown"), 7);
149 memset (s, ' ', pad);
160 decp = memchr (s, set_decimal, w);
164 /* If there's an `E' we can only delete 0s before the E. */
165 expp = memchr (s, 'E', w);
168 while (expp[-n - 1] == '0')
170 if (expp[-n - 1] == set_decimal)
172 memmove (&s[n], s, expp - s - n);
177 /* Otherwise delete all trailing 0s. */
179 while (s[w - n] == '0')
181 if (s[w - n] != set_decimal)
183 /* Avoid stripping `.0' to `'. */
184 if (w == n || !isdigit ((unsigned char) s[w - n - 1]))
189 memmove (&s[n], s, w - n);
194 /* Main conversion functions. */
196 static void insert_commas (char *dst, const char *src,
197 const struct fmt_spec *fp);
198 static int year4 (int year);
199 static int try_CCx (char *s, const struct fmt_spec *fp, double v);
202 #error Write your own floating-point output routines.
207 Some of the routines in this file are likely very specific to
208 base-2 representation of floating-point numbers, most notably the
209 routines that use frexp() or ldexp(). These attempt to extract
210 individual digits by setting the base-2 exponent and
211 multiplying/dividing by powers of 2. In base-2 numeration systems,
212 this just nudges the exponent up or down, but in base-10 floating
213 point, such multiplications/division can cause catastrophic loss of
216 The author has never personally used a machine that didn't use
217 binary floating point formats, so he is unwilling, and perhaps
218 unable, to code around this "problem". */
220 /* Converts a number between 0 and 15 inclusive to a `hexit'
222 #define MAKE_HEXIT(X) ("0123456789ABCDEF"[X])
224 /* Table of powers of 10. */
225 static const double power10[] =
228 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, 1e09, 1e10,
229 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20,
230 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29, 1e30,
231 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39, 1e40,
234 /* Handles F format. */
236 convert_F (char *dst, const struct fmt_spec *fp, const union value *v)
238 if (!try_F (dst, fp, v))
239 convert_E (dst, fp, v);
243 /* Handles N format. */
245 convert_N (char *dst, const struct fmt_spec *fp, const union value *v)
247 double d = floor (v->f);
249 if (d < 0 || d == SYSMIS)
251 msg (ME, _("The N output format cannot be used to output a "
252 "negative number or the system-missing value."));
256 if (d < power10[fp->w])
259 sprintf (buf, "%0*.0f", fp->w, v->f);
260 memcpy (dst, buf, fp->w);
263 memset (dst, '*', fp->w);
268 /* Handles E format. Also operates as fallback for some other
271 convert_E (char *dst, const struct fmt_spec *fp, const union value *v)
273 /* Temporary buffer. */
276 /* Ranged number of decimal places. */
279 /* Check that the format is width enough.
280 Although PSPP generally checks this, convert_E() can be called as
281 a fallback from other formats which do not check. */
284 memset (dst, '*', fp->w);
288 /* Put decimal places in usable range. */
289 d = min (fp->d, fp->w - 6);
294 sprintf (buf, "%*.*E", fp->w, d, v->f);
296 /* What we do here is force the exponent part to have four
297 characters whenever possible. That is, 1.00E+99 is okay (`E+99')
298 but 1.00E+100 (`E+100') must be coerced to 1.00+100 (`+100'). On
299 the other hand, 1.00E1000 (`E+100') cannot be canonicalized.
300 Note that ANSI C guarantees at least two digits in the
302 if (fabs (v->f) > 1e99)
304 /* Pointer to the `E' in buf. */
307 cp = strchr (buf, 'E');
310 /* Exponent better not be bigger than an int. */
311 int exp = atoi (cp + 1);
313 if (abs (exp) > 99 && abs (exp) < 1000)
315 /* Shift everything left one place: 1.00e+100 -> 1.00+100. */
321 else if (abs (exp) >= 1000)
322 memset (buf, '*', fp->w);
326 /* The C locale always uses a period `.' as a decimal point.
327 Translate to comma if necessary. */
328 if ((set_decimal == ',' && fp->type != FMT_DOT)
329 || (set_decimal == '.' && fp->type == FMT_DOT))
331 char *cp = strchr (buf, '.');
336 memcpy (dst, buf, fp->w);
340 /* Handles COMMA, DOT, DOLLAR, and PCT formats. */
342 convert_F_plus (char *dst, const struct fmt_spec *fp, const union value *v)
346 if (try_F (buf, fp, v))
347 insert_commas (dst, buf, fp);
349 convert_E (dst, fp, v);
355 convert_Z (char *dst, const struct fmt_spec *fp, const union value *v)
357 static int warned = 0;
361 msg (MW, _("Quality of zoned decimal (Z) output format code is "
362 "suspect. Check your results, report bugs to author."));
368 msg (ME, _("The system-missing value cannot be output as a zoned "
378 d = fabs (floor (v->f));
379 if (d >= power10[fp->w])
381 msg (ME, _("Number %g too big to fit in field with format Z%d.%d."),
386 sprintf (buf, "%*.0f", fp->w, v->f);
387 for (i = 0; i < fp->w; i++)
388 dst[i] = (buf[i] - '0') | 0xf0;
390 dst[fp->w - 1] &= 0xdf;
397 convert_A (char *dst, const struct fmt_spec *fp, const union value *v)
399 memcpy (dst, v->c, fp->w);
404 convert_AHEX (char *dst, const struct fmt_spec *fp, const union value *v)
408 for (i = 0; i < fp->w / 2; i++)
410 ((unsigned char *) dst)[i * 2] = MAKE_HEXIT ((v->c[i]) >> 4);
411 ((unsigned char *) dst)[i * 2 + 1] = MAKE_HEXIT ((v->c[i]) & 0xf);
418 convert_IB (char *dst, const struct fmt_spec *fp, const union value *v)
420 /* Strategy: Basically the same as convert_PIBHEX() but with base
421 256. Then it's necessary to negate the two's-complement result if
424 /* Used for constructing the two's-complement result. */
427 /* Fraction (mantissa). */
433 /* Difference between exponent and (-8*fp->w-1). */
439 /* Make the exponent (-8*fp->w-1). */
440 frac = frexp (fabs (v->f), &exp);
441 diff = exp - (-8 * fp->w - 1);
443 frac *= ldexp (1.0, diff);
445 /* Extract each base-256 digit. */
446 for (i = 0; i < fp->w; i++)
450 temp[i] = floor (frac);
453 /* Perform two's-complement negation if v->f is negative. */
456 /* Perform NOT operation. */
457 for (i = 0; i < fp->w; i++)
459 /* Add 1 to the whole number. */
460 for (i = fp->w - 1; i >= 0; i--)
467 memcpy (dst, temp, fp->w);
468 #ifndef WORDS_BIGENDIAN
469 mm_reverse (dst, fp->w);
476 convert_P (char *dst, const struct fmt_spec *fp, const union value *v)
478 /* Buffer for v->f*2-1 characters + a decimal point if library is
479 not quite compliant + a null. */
485 /* Main extraction. */
486 sprintf (buf, "%0*.0f", fp->w * 2 - 1, floor (fabs (v->f)));
488 for (i = 0; i < fp->w; i++)
489 ((unsigned char *) dst)[i]
490 = ((buf[i * 2] - '0') << 4) + buf[i * 2 + 1] - '0';
493 dst[fp->w - 1] &= 0xf0;
495 dst[fp->w - 1] |= 0xf;
497 dst[fp->w - 1] |= 0xd;
503 convert_PIB (char *dst, const struct fmt_spec *fp, const union value *v)
505 /* Strategy: Basically the same as convert_IB(). */
507 /* Fraction (mantissa). */
513 /* Difference between exponent and (-8*fp->w). */
519 /* Make the exponent (-8*fp->w). */
520 frac = frexp (fabs (v->f), &exp);
521 diff = exp - (-8 * fp->w);
523 frac *= ldexp (1.0, diff);
525 /* Extract each base-256 digit. */
526 for (i = 0; i < fp->w; i++)
530 ((unsigned char *) dst)[i] = floor (frac);
532 #ifndef WORDS_BIGENDIAN
533 mm_reverse (dst, fp->w);
540 convert_PIBHEX (char *dst, const struct fmt_spec *fp, const union value *v)
542 /* Strategy: Use frexp() to create a normalized result (but mostly
543 to find the base-2 exponent), then change the base-2 exponent to
544 (-4*fp->w) using multiplication and division by powers of two.
545 Extract each hexit by multiplying by 16. */
547 /* Fraction (mantissa). */
553 /* Difference between exponent and (-4*fp->w). */
559 /* Make the exponent (-4*fp->w). */
560 frac = frexp (fabs (v->f), &exp);
561 diff = exp - (-4 * fp->w);
563 frac *= ldexp (1.0, diff);
565 /* Extract each hexit. */
566 for (i = 0; i < fp->w; i++)
570 *dst++ = MAKE_HEXIT ((int) floor (frac));
577 convert_PK (char *dst, const struct fmt_spec *fp, const union value *v)
579 /* Buffer for v->f*2 characters + a decimal point if library is not
580 quite compliant + a null. */
586 /* Main extraction. */
587 sprintf (buf, "%0*.0f", fp->w * 2, floor (fabs (v->f)));
589 for (i = 0; i < fp->w; i++)
590 ((unsigned char *) dst)[i]
591 = ((buf[i * 2] - '0') << 4) + buf[i * 2 + 1] - '0';
597 convert_RB (char *dst, const struct fmt_spec *fp, const union value *v)
607 memcpy (dst, u.c, fp->w);
613 convert_RBHEX (char *dst, const struct fmt_spec *fp, const union value *v)
625 for (i = 0; i < fp->w / 2; i++)
627 *dst++ = MAKE_HEXIT (u.c[i] >> 4);
628 *dst++ = MAKE_HEXIT (u.c[i] & 15);
635 convert_CCx (char *dst, const struct fmt_spec *fp, const union value *v)
637 if (try_CCx (dst, fp, v->f))
647 return convert_F (dst, &f, v);
652 convert_date (char *dst, const struct fmt_spec *fp, const union value *v)
654 static const char *months[12] =
656 "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
657 "JUL", "AUG", "SEP", "OCT", "NOV", "DEC",
661 int month, day, year;
663 julian_to_calendar (v->f / 86400., &year, &month, &day);
668 sprintf (buf, "%02d-%s-%04d", day, months[month - 1], year);
670 sprintf (buf, "%02d-%s-%02d", day, months[month - 1], year % 100);
674 sprintf (buf, "%02d.%02d.%04d", day, month, year);
676 sprintf (buf, "%02d.%02d.%02d", day, month, year % 100);
680 sprintf (buf, "%04d/%02d/%02d", year, month, day);
682 sprintf (buf, "%02d/%02d/%02d", year % 100, month, day);
686 sprintf (buf, "%02d/%02d/%04d", month, day, year);
688 sprintf (buf, "%02d/%02d/%02d", month, day, year % 100);
692 int yday = (v->f / 86400.) - calendar_to_julian (year, 1, 1) + 1;
697 sprintf (buf, "%04d%03d", year, yday);
700 sprintf (buf, "%02d%03d", year % 100, yday);
705 sprintf (buf, "%d Q% 04d", (month - 1) / 3 + 1, year);
707 sprintf (buf, "%d Q% 02d", (month - 1) / 3 + 1, year % 100);
711 sprintf (buf, "%s% 04d", months[month - 1], year);
713 sprintf (buf, "%s% 02d", months[month - 1], year % 100);
717 int yday = (v->f / 86400.) - calendar_to_julian (year, 1, 1) + 1;
720 sprintf (buf, "%02d WK% 04d", (yday - 1) / 7 + 1, year);
722 sprintf (buf, "%02d WK% 02d", (yday - 1) / 7 + 1, year % 100);
729 cp = spprintf (buf, "%02d-%s-%04d %02d:%02d",
730 day, months[month - 1], year,
731 (int) fmod (floor (v->f / 60. / 60.), 24.),
732 (int) fmod (floor (v->f / 60.), 60.));
737 if (fp->w >= 22 && fp->d > 0)
739 d = min (fp->d, fp->w - 21);
748 cp = spprintf (cp, ":%0*.*f", w, d, fmod (v->f, 60.));
758 st_bare_pad_copy (dst, buf, fp->w);
763 convert_time (char *dst, const struct fmt_spec *fp, const union value *v)
771 if (fabs (v->f) > 1e20)
773 msg (ME, _("Time value %g too large in magnitude to convert to "
774 "alphanumeric time."), v->f);
782 *cp++ = '-', time = -time;
783 if (fp->type == FMT_DTIME)
785 double days = floor (time / 60. / 60. / 24.);
786 cp = spprintf (temp_buf, "%02.0f ", days);
787 time = time - days * 60. * 60. * 24.;
793 cp = spprintf (cp, "%02.0f:%02.0f",
794 fmod (floor (time / 60. / 60.), 24.),
795 fmod (floor (time / 60.), 60.));
801 if (width >= 10 && fp->d >= 0 && fp->d != 0)
802 d = min (fp->d, width - 9), w = 3 + d;
806 cp = spprintf (cp, ":%0*.*f", w, d, fmod (time, 60.));
808 st_bare_pad_copy (dst, temp_buf, fp->w);
814 convert_WKDAY (char *dst, const struct fmt_spec *fp, const union value *v)
816 static const char *weekdays[7] =
818 "SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY",
819 "THURSDAY", "FRIDAY", "SATURDAY",
826 msg (ME, _("Weekday index %d does not lie between 1 and 7."), x);
829 st_bare_pad_copy (dst, weekdays[x - 1], fp->w);
835 convert_MONTH (char *dst, const struct fmt_spec *fp, const union value *v)
837 static const char *months[12] =
839 "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
840 "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER",
847 msg (ME, _("Month index %d does not lie between 1 and 12."), x);
851 st_bare_pad_copy (dst, months[x - 1], fp->w);
856 /* Helper functions. */
858 /* Copies SRC to DST, inserting commas and dollar signs as appropriate
859 for format spec *FP. */
861 insert_commas (char *dst, const char *src, const struct fmt_spec *fp)
863 /* Number of leading spaces in the number. This is the amount of
864 room we have for inserting commas and dollar signs. */
867 /* Number of digits before the decimal point. This is used to
868 determine the Number of commas to insert. */
871 /* Number of commas to insert. */
874 /* Number of items ,%$ to insert. */
877 /* Number of n_items items not to use for commas. */
880 /* Digit iterator. */
883 /* Source pointer. */
886 /* Count spaces and digits. */
888 while (sp < src + fp->w && *sp == ' ')
895 while (sp + n_digits < src + fp->w && isdigit ((unsigned char) sp[n_digits]))
897 n_commas = (n_digits - 1) / 3;
898 n_items = n_commas + (fp->type == FMT_DOLLAR || fp->type == FMT_PCT);
900 /* Check whether we have enough space to do insertions. */
901 if (!n_spaces || !n_items)
903 memcpy (dst, src, fp->w);
906 if (n_items > n_spaces)
911 memcpy (dst, src, fp->w);
916 /* Put spaces at the beginning if there's extra room. */
917 if (n_spaces > n_items)
919 memset (dst, ' ', n_spaces - n_items);
920 dst += n_spaces - n_items;
923 /* Insert $ and reserve space for %. */
925 if (fp->type == FMT_DOLLAR)
930 else if (fp->type == FMT_PCT)
933 /* Copy negative sign and digits, inserting commas. */
934 if (sp - src > n_spaces)
936 for (i = n_digits; i; i--)
938 if (i % 3 == 0 && n_digits > i && n_items > n_reserved)
941 *dst++ = fp->type == FMT_COMMA ? set_grouping : set_decimal;
946 /* Copy decimal places and insert % if necessary. */
947 memcpy (dst, sp, fp->w - (sp - src));
948 if (fp->type == FMT_PCT && n_items > 0)
949 dst[fp->w - (sp - src)] = '%';
952 /* Returns 1 if YEAR (i.e., 1987) can be represented in four digits, 0
957 if (year >= 1 && year <= 9999)
959 msg (ME, _("Year %d cannot be represented in four digits for "
960 "output formatting purposes."), year);
965 try_CCx (char *dst, const struct fmt_spec *fp, double v)
967 struct set_cust_currency *cc = &set_cc[fp->type - FMT_CCA];
975 /* Determine length available, decimal character for number
977 f.type = cc->decimal == set_decimal ? FMT_COMMA : FMT_DOT;
978 f.w = fp->w - strlen (cc->prefix) - strlen (cc->suffix);
980 f.w -= strlen (cc->neg_prefix) + strlen (cc->neg_suffix) - 1;
982 /* Convert -0 to +0. */
989 /* There's room for all that currency crap. Let's do the F
991 if (!convert_F (buf, &f, (union value *) &v) || *buf == '*')
993 insert_commas (buf2, buf, &f);
995 /* Postprocess back into buf. */
998 cp = stpcpy (cp, cc->neg_prefix);
999 cp = stpcpy (cp, cc->prefix);
1005 assert ((v >= 0) ^ (*bp == '-'));
1009 memcpy (cp, bp, f.w - (bp - buf2));
1010 cp += f.w - (bp - buf2);
1012 cp = stpcpy (cp, cc->suffix);
1014 cp = stpcpy (cp, cc->neg_suffix);
1016 /* Copy into dst. */
1017 assert (cp - buf <= fp->w);
1018 if (cp - buf < fp->w)
1020 memcpy (&dst[fp->w - (cp - buf)], buf, cp - buf);
1021 memset (dst, ' ', fp->w - (cp - buf));
1024 memcpy (dst, buf, fp->w);
1029 /* This routine relies on the underlying implementation of sprintf:
1031 If the number has a magnitude 1e40 or greater, then we needn't
1032 bother with it, since it's guaranteed to need processing in
1033 scientific notation.
1035 Otherwise, do a binary search for the base-10 magnitude of the
1036 thing. log10() is not accurate enough, and the alternatives are
1037 frightful. Besides, we never need as many as 6 (pairs of)
1038 comparisons. The algorithm used for searching is Knuth's Algorithm
1039 6.2.1C (Uniform binary search).
1041 DON'T CHANGE ANYTHING HERE UNLESS YOU'VE THOUGHT ABOUT IT FOR A
1042 LONG TIME! The rest of the program is heavily dependent on
1043 specific properties of this routine's output. LOG ALL CHANGES! */
1045 try_F (char *dst, const struct fmt_spec *fp, const union value *value)
1047 /* This is the DELTA array from Knuth.
1048 DELTA[j] = floor((40+2**(j-1))/(2**j)). */
1049 static const int delta[8] =
1051 0, (40 + 1) / 2, (40 + 2) / 4, (40 + 4) / 8, (40 + 8) / 16,
1052 (40 + 16) / 32, (40 + 32) / 64, (40 + 64) / 128,
1055 /* The number of digits in floor(v), including sign. This is `i'
1057 int n_int = (40 + 1) / 2;
1059 /* Used to step through delta[]. This is `j' from Knuth. */
1063 double v = value->f;
1065 /* Magnitude of v. This is `K' from Knuth. */
1068 /* Number of characters for the fractional part, including the
1072 /* Pointer into buf used for formatting. */
1075 /* Used to count characters formatted by nsprintf(). */
1078 /* Temporary buffer. */
1081 /* First check for infinities and NaNs. 12/13/96. */
1084 n = nsprintf (buf, "%f", v);
1086 memset (buf, '*', fp->w);
1089 memmove (&buf[fp->w - n], buf, n);
1090 memset (buf, ' ', fp->w - n);
1092 memcpy (dst, buf, fp->w);
1096 /* Then check for radically out-of-range values. */
1098 if (mag >= power10[fp->w])
1105 /* Avoid printing `-.000'. 7/6/96. */
1106 if (approx_eq (v, 0.0))
1110 /* Now perform a `uniform binary search' based on the tables
1111 power10[] and delta[]. After this step, nint is the number of
1112 digits in floor(v), including any sign. */
1115 if (mag >= power10[n_int]) /* Should this be approx_ge()? */
1118 n_int += delta[j++];
1120 else if (mag < power10[n_int - 1])
1123 n_int -= delta[j++];
1129 /* If we have any decimal places, then there is a decimal point,
1135 /* 1/10/96: If there aren't any digits at all, add one. This occurs
1136 only when fabs(v) < 1.0. */
1137 if (n_int + n_dec == 0)
1140 /* Give space for a minus sign. Moved 1/10/96. */
1144 /* Normally we only go through the loop once; occasionally twice.
1145 Three times or more indicates a very serious bug somewhere. */
1148 /* Check out the total length of the string. */
1150 if (n_int + n_dec > fp->w)
1152 /* The string is too long. Let's see what can be done. */
1154 /* If we can, just reduce the number of decimal places. */
1155 n_dec = fp->w - n_int;
1159 else if (n_int + n_dec < fp->w)
1161 /* The string is too short. Left-pad with spaces. */
1162 int n_spaces = fp->w - n_int - n_dec;
1163 memset (cp, ' ', n_spaces);
1167 /* Finally, format the number. */
1169 n = nsprintf (cp, "%.*f", n_dec - 1, v);
1171 n = nsprintf (cp, "%.0f", v);
1173 /* If v is positive and its magnitude is less than 1... */
1178 /* The value rounds to `.###'. */
1179 memmove (cp, &cp[1], n - 1);
1184 /* The value rounds to `1.###'. */
1189 /* Else if v is negative and its magnitude is less than 1... */
1190 else if (v < 0 && n_int == 1)
1194 /* The value rounds to `-.###'. */
1195 memmove (&cp[1], &cp[2], n - 2);
1200 /* The value rounds to `-1.###'. */
1206 /* Check for a correct number of digits & decimal places & stuff.
1207 This is just a desperation check. Hopefully it won't fail too
1208 often, because then we have to run through the whole loop again:
1209 sprintf() is not a fast operation with floating-points! */
1210 if (n == n_int + n_dec)
1212 /* Convert periods `.' to commas `,' for our foreign friends. */
1213 if ((set_decimal == ',' && fp->type != FMT_DOT)
1214 || (set_decimal == '.' && fp->type == FMT_DOT))
1216 cp = strchr (cp, '.');
1221 memcpy (dst, buf, fp->w);
1225 n_int = n - n_dec; /* FIXME? Need an idiot check on resulting n_int? */