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 the exactly
58 FP->W character in buffer S according to format specification
59 FP. No null terminator is appended to the buffer. */
61 data_out (char *s, const struct fmt_spec *fp, const union value *v)
63 static convert_func *const handlers[FMT_NUMBER_OF_FORMATS] =
65 convert_F, convert_N, convert_E, convert_F_plus,
66 convert_F_plus, convert_F_plus, convert_F_plus,
67 convert_Z, convert_A, convert_AHEX, convert_IB, convert_P, convert_PIB,
68 convert_PIBHEX, convert_PK, convert_RB, convert_RBHEX,
69 convert_CCx, convert_CCx, convert_CCx, convert_CCx, convert_CCx,
70 convert_date, convert_date, convert_date, convert_date, convert_date,
71 convert_date, convert_date, convert_date, convert_date,
72 convert_time, convert_time,
73 convert_WKDAY, convert_MONTH,
79 int cat = formats[fp->type].cat;
80 if ((cat & FCAT_BLANKS_SYSMIS) && v->f == SYSMIS)
82 memset (s, ' ', fp->w);
83 s[fp->w - fp->d - 1] = '.';
86 if ((cat & FCAT_SHIFT_DECIMAL) && v->f != SYSMIS && fp->d)
88 tmp_val.f = v->f * pow (10.0, fp->d);
93 if (!handlers[fp->type] (s, fp, v))
94 strncpy (s, "ERROR", fp->w);
97 /* Converts V into S in F format with width W and D decimal places,
98 then deletes trailing zeros. S is not null-terminated. */
100 num_to_string (double v, char *s, int w, int d)
102 /* Dummies to pass to convert_F. */
107 /* Pointer to `.' in S. */
110 /* Pointer to `E' in S. */
113 /* Number of characters to delete. */
121 /* Cut out the jokers. */
129 memcpy (temp, "NaN", 3);
134 memcpy (temp, "+Infinity", 9);
141 memcpy (temp, _("Unknown"), 7);
147 memset (s, ' ', pad);
158 decp = memchr (s, set_decimal, w);
162 /* If there's an `E' we can only delete 0s before the E. */
163 expp = memchr (s, 'E', w);
166 while (expp[-n - 1] == '0')
168 if (expp[-n - 1] == set_decimal)
170 memmove (&s[n], s, expp - s - n);
175 /* Otherwise delete all trailing 0s. */
177 while (s[w - n] == '0')
179 if (s[w - n] != set_decimal)
181 /* Avoid stripping `.0' to `'. */
182 if (w == n || !isdigit ((unsigned char) s[w - n - 1]))
187 memmove (&s[n], s, w - n);
192 /* Main conversion functions. */
194 static void insert_commas (char *dst, const char *src,
195 const struct fmt_spec *fp);
196 static int year4 (int year);
197 static int try_CCx (char *s, const struct fmt_spec *fp, double v);
200 #error Write your own floating-point output routines.
205 Some of the routines in this file are likely very specific to
206 base-2 representation of floating-point numbers, most notably the
207 routines that use frexp() or ldexp(). These attempt to extract
208 individual digits by setting the base-2 exponent and
209 multiplying/dividing by powers of 2. In base-2 numeration systems,
210 this just nudges the exponent up or down, but in base-10 floating
211 point, such multiplications/division can cause catastrophic loss of
214 The author has never personally used a machine that didn't use
215 binary floating point formats, so he is unwilling, and perhaps
216 unable, to code around this "problem". */
218 /* Converts a number between 0 and 15 inclusive to a `hexit'
220 #define MAKE_HEXIT(X) ("0123456789ABCDEF"[X])
222 /* Table of powers of 10. */
223 static const double power10[] =
226 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, 1e09, 1e10,
227 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20,
228 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29, 1e30,
229 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39, 1e40,
232 /* Handles F format. */
234 convert_F (char *dst, const struct fmt_spec *fp, const union value *v)
236 if (!try_F (dst, fp, v))
237 convert_E (dst, fp, v);
241 /* Handles N format. */
243 convert_N (char *dst, const struct fmt_spec *fp, const union value *v)
245 double d = floor (v->f);
247 if (d < 0 || d == SYSMIS)
249 msg (ME, _("The N output format cannot be used to output a "
250 "negative number or the system-missing value."));
254 if (d < power10[fp->w])
257 sprintf (buf, "%0*.0f", fp->w, v->f);
258 memcpy (dst, buf, fp->w);
261 memset (dst, '*', fp->w);
266 /* Handles E format. Also operates as fallback for some other
269 convert_E (char *dst, const struct fmt_spec *fp, const union value *v)
271 /* Temporary buffer. */
274 /* Ranged number of decimal places. */
277 /* Check that the format is width enough.
278 Although PSPP generally checks this, convert_E() can be called as
279 a fallback from other formats which do not check. */
282 memset (dst, '*', fp->w);
286 /* Put decimal places in usable range. */
287 d = min (fp->d, fp->w - 6);
292 sprintf (buf, "%*.*E", fp->w, d, v->f);
294 /* What we do here is force the exponent part to have four
295 characters whenever possible. That is, 1.00E+99 is okay (`E+99')
296 but 1.00E+100 (`E+100') must be coerced to 1.00+100 (`+100'). On
297 the other hand, 1.00E1000 (`E+100') cannot be canonicalized.
298 Note that ANSI C guarantees at least two digits in the
300 if (fabs (v->f) > 1e99)
302 /* Pointer to the `E' in buf. */
305 cp = strchr (buf, 'E');
308 /* Exponent better not be bigger than an int. */
309 int exp = atoi (cp + 1);
311 if (abs (exp) > 99 && abs (exp) < 1000)
313 /* Shift everything left one place: 1.00e+100 -> 1.00+100. */
319 else if (abs (exp) >= 1000)
320 memset (buf, '*', fp->w);
324 /* The C locale always uses a period `.' as a decimal point.
325 Translate to comma if necessary. */
326 if ((set_decimal == ',' && fp->type != FMT_DOT)
327 || (set_decimal == '.' && fp->type == FMT_DOT))
329 char *cp = strchr (buf, '.');
334 memcpy (dst, buf, fp->w);
338 /* Handles COMMA, DOT, DOLLAR, and PCT formats. */
340 convert_F_plus (char *dst, const struct fmt_spec *fp, const union value *v)
344 if (try_F (buf, fp, v))
345 insert_commas (dst, buf, fp);
347 convert_E (dst, fp, v);
353 convert_Z (char *dst, const struct fmt_spec *fp, const union value *v)
355 static int warned = 0;
360 _("Quality of zoned decimal (Z) output format code is suspect. Check your results. Report bugs to %s."),
367 msg (ME, _("The system-missing value cannot be output as a zoned "
377 d = fabs (floor (v->f));
378 if (d >= power10[fp->w])
380 msg (ME, _("Number %g too big to fit in field with format Z%d.%d."),
385 sprintf (buf, "%*.0f", fp->w, v->f);
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 union value *v)
398 memcpy (dst, v->s, fp->w);
403 convert_AHEX (char *dst, const struct fmt_spec *fp, const union value *v)
407 for (i = 0; i < fp->w / 2; i++)
409 ((unsigned char *) dst)[i * 2] = MAKE_HEXIT ((v->s[i]) >> 4);
410 ((unsigned char *) dst)[i * 2 + 1] = MAKE_HEXIT ((v->s[i]) & 0xf);
417 convert_IB (char *dst, const struct fmt_spec *fp, const union value *v)
419 /* Strategy: Basically the same as convert_PIBHEX() but with base
420 256. Then it's necessary to negate the two's-complement result if
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 (v->f), &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 v->f 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 mm_reverse (dst, fp->w);
475 convert_P (char *dst, const struct fmt_spec *fp, const union value *v)
477 /* Buffer for v->f*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 (v->f)));
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, const union value *v)
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 (v->f), &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 mm_reverse (dst, fp->w);
539 convert_PIBHEX (char *dst, const struct fmt_spec *fp, const union value *v)
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 (v->f), &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, const union value *v)
578 /* Buffer for v->f*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 (v->f)));
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, const union value *v)
606 memcpy (dst, u.c, fp->w);
612 convert_RBHEX (char *dst, const struct fmt_spec *fp, const union value *v)
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, const union value *v)
636 if (try_CCx (dst, fp, v->f))
646 return convert_F (dst, &f, v);
651 convert_date (char *dst, const struct fmt_spec *fp, const union value *v)
653 static const char *months[12] =
655 "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
656 "JUL", "AUG", "SEP", "OCT", "NOV", "DEC",
660 int month, day, year;
662 julian_to_calendar (v->f / 86400., &year, &month, &day);
667 sprintf (buf, "%02d-%s-%04d", day, months[month - 1], year);
669 sprintf (buf, "%02d-%s-%02d", day, months[month - 1], year % 100);
673 sprintf (buf, "%02d.%02d.%04d", day, month, year);
675 sprintf (buf, "%02d.%02d.%02d", day, month, year % 100);
679 sprintf (buf, "%04d/%02d/%02d", year, month, day);
681 sprintf (buf, "%02d/%02d/%02d", year % 100, month, day);
685 sprintf (buf, "%02d/%02d/%04d", month, day, year);
687 sprintf (buf, "%02d/%02d/%02d", month, day, year % 100);
691 int yday = (v->f / 86400.) - calendar_to_julian (year, 1, 1) + 1;
696 sprintf (buf, "%04d%03d", year, yday);
699 sprintf (buf, "%02d%03d", year % 100, yday);
704 sprintf (buf, "%d Q% 04d", (month - 1) / 3 + 1, year);
706 sprintf (buf, "%d Q% 02d", (month - 1) / 3 + 1, year % 100);
710 sprintf (buf, "%s% 04d", months[month - 1], year);
712 sprintf (buf, "%s% 02d", months[month - 1], year % 100);
716 int yday = (v->f / 86400.) - calendar_to_julian (year, 1, 1) + 1;
719 sprintf (buf, "%02d WK% 04d", (yday - 1) / 7 + 1, year);
721 sprintf (buf, "%02d WK% 02d", (yday - 1) / 7 + 1, year % 100);
728 cp = spprintf (buf, "%02d-%s-%04d %02d:%02d",
729 day, months[month - 1], year,
730 (int) fmod (floor (v->f / 60. / 60.), 24.),
731 (int) fmod (floor (v->f / 60.), 60.));
736 if (fp->w >= 22 && fp->d > 0)
738 d = min (fp->d, fp->w - 21);
747 cp = spprintf (cp, ":%0*.*f", w, d, fmod (v->f, 60.));
757 st_bare_pad_copy (dst, buf, fp->w);
762 convert_time (char *dst, const struct fmt_spec *fp, const union value *v)
770 if (fabs (v->f) > 1e20)
772 msg (ME, _("Time value %g too large in magnitude to convert to "
773 "alphanumeric time."), v->f);
781 *cp++ = '-', time = -time;
782 if (fp->type == FMT_DTIME)
784 double days = floor (time / 60. / 60. / 24.);
785 cp = spprintf (temp_buf, "%02.0f ", days);
786 time = time - days * 60. * 60. * 24.;
792 cp = spprintf (cp, "%02.0f:%02.0f",
793 fmod (floor (time / 60. / 60.), 24.),
794 fmod (floor (time / 60.), 60.));
800 if (width >= 10 && fp->d >= 0 && fp->d != 0)
801 d = min (fp->d, width - 9), w = 3 + d;
805 cp = spprintf (cp, ":%0*.*f", w, d, fmod (time, 60.));
807 st_bare_pad_copy (dst, temp_buf, fp->w);
813 convert_WKDAY (char *dst, const struct fmt_spec *fp, const union value *v)
815 static const char *weekdays[7] =
817 "SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY",
818 "THURSDAY", "FRIDAY", "SATURDAY",
825 msg (ME, _("Weekday index %d does not lie between 1 and 7."), x);
828 st_bare_pad_copy (dst, weekdays[x - 1], fp->w);
834 convert_MONTH (char *dst, const struct fmt_spec *fp, const union value *v)
836 static const char *months[12] =
838 "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
839 "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER",
846 msg (ME, _("Month index %d does not lie between 1 and 12."), x);
850 st_bare_pad_copy (dst, months[x - 1], fp->w);
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 ? set_grouping : set_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 v)
966 struct set_cust_currency *cc = &set_cc[fp->type - FMT_CCA];
974 /* Determine length available, decimal character for number
976 f.type = cc->decimal == set_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. */
988 /* There's room for all that currency crap. Let's do the F
990 if (!convert_F (buf, &f, (union value *) &v) || *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 ((v >= 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);
1028 /* This routine relies on the underlying implementation of sprintf:
1030 If the number has a magnitude 1e40 or greater, then we needn't
1031 bother with it, since it's guaranteed to need processing in
1032 scientific notation.
1034 Otherwise, do a binary search for the base-10 magnitude of the
1035 thing. log10() is not accurate enough, and the alternatives are
1036 frightful. Besides, we never need as many as 6 (pairs of)
1037 comparisons. The algorithm used for searching is Knuth's Algorithm
1038 6.2.1C (Uniform binary search).
1040 DON'T CHANGE ANYTHING HERE UNLESS YOU'VE THOUGHT ABOUT IT FOR A
1041 LONG TIME! The rest of the program is heavily dependent on
1042 specific properties of this routine's output. LOG ALL CHANGES! */
1044 try_F (char *dst, const struct fmt_spec *fp, const union value *value)
1046 /* This is the DELTA array from Knuth.
1047 DELTA[j] = floor((40+2**(j-1))/(2**j)). */
1048 static const int delta[8] =
1050 0, (40 + 1) / 2, (40 + 2) / 4, (40 + 4) / 8, (40 + 8) / 16,
1051 (40 + 16) / 32, (40 + 32) / 64, (40 + 64) / 128,
1054 /* The number of digits in floor(v), including sign. This is `i'
1056 int n_int = (40 + 1) / 2;
1058 /* Used to step through delta[]. This is `j' from Knuth. */
1062 double v = value->f;
1064 /* Magnitude of v. This is `K' from Knuth. */
1067 /* Number of characters for the fractional part, including the
1071 /* Pointer into buf used for formatting. */
1074 /* Used to count characters formatted by nsprintf(). */
1077 /* Temporary buffer. */
1080 /* First check for infinities and NaNs. 12/13/96. */
1083 n = nsprintf (buf, "%f", v);
1085 memset (buf, '*', fp->w);
1088 memmove (&buf[fp->w - n], buf, n);
1089 memset (buf, ' ', fp->w - n);
1091 memcpy (dst, buf, fp->w);
1095 /* Then check for radically out-of-range values. */
1097 if (mag >= power10[fp->w])
1104 /* Avoid printing `-.000'. 7/6/96. */
1105 if (approx_eq (v, 0.0))
1109 /* Now perform a `uniform binary search' based on the tables
1110 power10[] and delta[]. After this step, nint is the number of
1111 digits in floor(v), including any sign. */
1114 if (mag >= power10[n_int]) /* Should this be approx_ge()? */
1117 n_int += delta[j++];
1119 else if (mag < power10[n_int - 1])
1122 n_int -= delta[j++];
1128 /* If we have any decimal places, then there is a decimal point,
1134 /* 1/10/96: If there aren't any digits at all, add one. This occurs
1135 only when fabs(v) < 1.0. */
1136 if (n_int + n_dec == 0)
1139 /* Give space for a minus sign. Moved 1/10/96. */
1143 /* Normally we only go through the loop once; occasionally twice.
1144 Three times or more indicates a very serious bug somewhere. */
1147 /* Check out the total length of the string. */
1149 if (n_int + n_dec > fp->w)
1151 /* The string is too long. Let's see what can be done. */
1153 /* If we can, just reduce the number of decimal places. */
1154 n_dec = fp->w - n_int;
1158 else if (n_int + n_dec < fp->w)
1160 /* The string is too short. Left-pad with spaces. */
1161 int n_spaces = fp->w - n_int - n_dec;
1162 memset (cp, ' ', n_spaces);
1166 /* Finally, format the number. */
1168 n = nsprintf (cp, "%.*f", n_dec - 1, v);
1170 n = nsprintf (cp, "%.0f", v);
1172 /* If v is positive and its magnitude is less than 1... */
1177 /* The value rounds to `.###'. */
1178 memmove (cp, &cp[1], n - 1);
1183 /* The value rounds to `1.###'. */
1188 /* Else if v is negative and its magnitude is less than 1... */
1189 else if (v < 0 && n_int == 1)
1193 /* The value rounds to `-.###'. */
1194 memmove (&cp[1], &cp[2], n - 2);
1199 /* The value rounds to `-1.###'. */
1205 /* Check for a correct number of digits & decimal places & stuff.
1206 This is just a desperation check. Hopefully it won't fail too
1207 often, because then we have to run through the whole loop again:
1208 sprintf() is not a fast operation with floating-points! */
1209 if (n == n_int + n_dec)
1211 /* Convert periods `.' to commas `,' for our foreign friends. */
1212 if ((set_decimal == ',' && fp->type != FMT_DOT)
1213 || (set_decimal == '.' && fp->type == FMT_DOT))
1215 cp = strchr (cp, '.');
1220 memcpy (dst, buf, fp->w);
1224 n_int = n - n_dec; /* FIXME? Need an idiot check on resulting n_int? */