Remove num_to_string() function, because it is not used anywhere.
[pspp-builds.git] / src / data / data-out.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3    Written by Ben Pfaff <blp@gnu.org>.
4
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.
9
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.
14
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
18    02110-1301, USA. */
19
20 #include <config.h>
21 #include <libpspp/message.h>
22 #include <ctype.h>
23 #include <math.h>
24 #include <float.h>
25 #include <stdlib.h>
26 #include <time.h>
27 #include "calendar.h"
28 #include <libpspp/assertion.h>
29 #include <libpspp/message.h>
30 #include "format.h"
31 #include <libpspp/magic.h>
32 #include <libpspp/misc.h>
33 #include <libpspp/misc.h>
34 #include "settings.h"
35 #include <libpspp/str.h>
36 #include "variable.h"
37
38 #include "gettext.h"
39 #define _(msgid) gettext (msgid)
40 \f
41 /* Public functions. */
42
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;
49
50 static numeric_converter try_F, convert_infinite;
51
52 typedef int string_converter (char *, const struct fmt_spec *, const char *);
53 static string_converter convert_A, convert_AHEX;
54
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.  */
58 bool
59 data_out (char *s, const struct fmt_spec *fp, const union value *v)
60 {
61   int cat = formats[fp->type].cat;
62   int ok;
63
64   assert (check_output_specifier (fp, 0));
65   if (!(cat & FCAT_STRING)) 
66     {
67       /* Numeric formatting. */
68       double number = v->f;
69
70       /* Handle SYSMIS turning into blanks. */
71       if ((cat & FCAT_BLANKS_SYSMIS) && number == SYSMIS)
72         {
73           memset (s, ' ', fp->w);
74           s[fp->w - fp->d - 1] = '.';
75           return true;
76         }
77
78       /* Handle decimal shift. */
79       if ((cat & FCAT_SHIFT_DECIMAL) && number != SYSMIS && fp->d)
80         number *= pow (10.0, fp->d);
81
82       switch (fp->type) 
83         {
84         case FMT_F:
85           ok = convert_F (s, fp, number);
86           break;
87
88         case FMT_N:
89           ok = convert_N (s, fp, number);
90           break;
91
92         case FMT_E:
93           ok = convert_E (s, fp, number);
94           break;
95
96         case FMT_COMMA: case FMT_DOT: case FMT_DOLLAR: case FMT_PCT:
97           ok = convert_F_plus (s, fp, number);
98           break;
99
100         case FMT_Z:
101           ok = convert_Z (s, fp, number);
102           break;
103
104         case FMT_A:
105           NOT_REACHED ();
106
107         case FMT_AHEX:
108           NOT_REACHED ();
109
110         case FMT_IB:
111           ok = convert_IB (s, fp, number);
112           break;
113
114         case FMT_P:
115           ok = convert_P (s, fp, number);
116           break;
117
118         case FMT_PIB:
119           ok = convert_PIB (s, fp, number);
120           break;
121
122         case FMT_PIBHEX:
123           ok = convert_PIBHEX (s, fp, number);
124           break;
125
126         case FMT_PK:
127           ok = convert_PK (s, fp, number);
128           break;
129
130         case FMT_RB:
131           ok = convert_RB (s, fp, number);
132           break;
133
134         case FMT_RBHEX:
135           ok = convert_RBHEX (s, fp, number);
136           break;
137
138         case FMT_CCA: case FMT_CCB: case FMT_CCC: case FMT_CCD: case FMT_CCE:
139           ok = convert_CCx (s, fp, number);
140           break;
141
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:
144         case FMT_DATETIME: 
145           ok = convert_date (s, fp, number);
146           break;
147
148         case FMT_TIME: case FMT_DTIME:
149           ok = convert_time (s, fp, number);
150           break;
151
152         case FMT_WKDAY:
153           ok = convert_WKDAY (s, fp, number);
154           break;
155
156         case FMT_MONTH:
157           ok = convert_MONTH (s, fp, number);
158           break;
159
160         default:
161           NOT_REACHED ();
162         }
163     }
164   else 
165     {
166       /* String formatting. */
167       const char *string = v->s;
168
169       switch (fp->type) 
170         {
171         case FMT_A:
172           ok = convert_A (s, fp, string);
173           break;
174
175         case FMT_AHEX:
176           ok = convert_AHEX (s, fp, string);
177           break;
178
179         default:
180           NOT_REACHED ();
181         }
182     }
183
184   /* Error handling. */
185   if (!ok)
186     strncpy (s, "ERROR", fp->w);
187   
188   return ok;
189 }
190 \f
191 /* Main conversion functions. */
192
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);
197
198 #if FLT_RADIX!=2
199 #error Write your own floating-point output routines.
200 #endif
201
202 /* Converts a number between 0 and 15 inclusive to a `hexit'
203    [0-9A-F]. */
204 #define MAKE_HEXIT(X) ("0123456789ABCDEF"[X])
205
206 /* Table of powers of 10. */
207 static const double power10[] =
208   {
209     0,  /* Not used. */
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,
214   };
215
216 /* Handles F format. */
217 static int
218 convert_F (char *dst, const struct fmt_spec *fp, double number)
219 {
220   if (!try_F (dst, fp, number))
221     convert_E (dst, fp, number);
222   return 1;
223 }
224
225 /* Handles N format. */
226 static int
227 convert_N (char *dst, const struct fmt_spec *fp, double number)
228 {
229   double d = floor (number);
230
231   if (d < 0 || d == SYSMIS)
232     {
233       msg (ME, _("The N output format cannot be used to output a "
234                  "negative number or the system-missing value."));
235       return 0;
236     }
237   
238   if (d < power10[fp->w])
239     {
240       char buf[128];
241       sprintf (buf, "%0*.0f", fp->w, number);
242       memcpy (dst, buf, fp->w);
243     }
244   else
245     memset (dst, '*', fp->w);
246
247   return 1;
248 }
249
250 /* Handles E format.  Also operates as fallback for some other
251    formats. */
252 static int
253 convert_E (char *dst, const struct fmt_spec *fp, double number)
254 {
255   /* Temporary buffer. */
256   char buf[128];
257   
258   /* Ranged number of decimal places. */
259   int d;
260
261   if (!finite (number))
262     return convert_infinite (dst, fp, number);
263
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. */
267   if (fp->w < 6)
268     {
269       memset (dst, '*', fp->w);
270       return 1;
271     }
272
273   /* Put decimal places in usable range. */
274   d = min (fp->d, fp->w - 6);
275   if (number < 0)
276     d--;
277   if (d < 0)
278     d = 0;
279   sprintf (buf, "%*.*E", fp->w, d, number);
280
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
286      exponent. */
287   if (fabs (number) > 1e99)
288     {
289       /* Pointer to the `E' in buf. */
290       char *cp;
291
292       cp = strchr (buf, 'E');
293       if (cp)
294         {
295           /* Exponent better not be bigger than an int. */
296           int exp = atoi (cp + 1); 
297
298           if (abs (exp) > 99 && abs (exp) < 1000)
299             {
300               /* Shift everything left one place: 1.00e+100 -> 1.00+100. */
301               cp[0] = cp[1];
302               cp[1] = cp[2];
303               cp[2] = cp[3];
304               cp[3] = cp[4];
305             }
306           else if (abs (exp) >= 1000)
307             memset (buf, '*', fp->w);
308         }
309     }
310
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))
315     {
316       char *cp = strchr (buf, '.');
317       if (cp)
318         *cp = ',';
319     }
320
321   memcpy (dst, buf, fp->w);
322   return 1;
323 }
324
325 /* Handles COMMA, DOT, DOLLAR, and PCT formats. */
326 static int
327 convert_F_plus (char *dst, const struct fmt_spec *fp, double number)
328 {
329   char buf[40];
330   
331   if (try_F (buf, fp, number))
332     insert_commas (dst, buf, fp);
333   else
334     convert_E (dst, fp, number);
335
336   return 1;
337 }
338
339 static int
340 convert_Z (char *dst, const struct fmt_spec *fp, double number)
341 {
342   static bool warned = false;
343
344   if (!warned)
345     {
346       msg (MW, 
347         _("Quality of zoned decimal (Z) output format code is "
348           "suspect.  Check your results. Report bugs to %s."),
349         PACKAGE_BUGREPORT);
350       warned = 1;
351     }
352
353   if (number == SYSMIS)
354     {
355       msg (ME, _("The system-missing value cannot be output as a zoned "
356                  "decimal number."));
357       return 0;
358     }
359   
360   {
361     char buf[41];
362     double d;
363     int i;
364     
365     d = fabs (floor (number));
366     if (d >= power10[fp->w])
367       {
368         msg (ME, _("Number %g too big to fit in field with format Z%d.%d."),
369              number, fp->w, fp->d);
370         return 0;
371       }
372
373     sprintf (buf, "%*.0f", fp->w, number);
374     for (i = 0; i < fp->w; i++)
375       dst[i] = (buf[i] - '0') | 0xf0;
376     if (number < 0)
377       dst[fp->w - 1] &= 0xdf;
378   }
379
380   return 1;
381 }
382
383 static int
384 convert_A (char *dst, const struct fmt_spec *fp, const char *string)
385 {
386   memcpy(dst, string, fp->w);
387   return 1;
388 }
389
390 static int
391 convert_AHEX (char *dst, const struct fmt_spec *fp, const char *string)
392 {
393   int i;
394
395   for (i = 0; i < fp->w / 2; i++)
396     {
397       *dst++ = MAKE_HEXIT ((string[i]) >> 4);
398       *dst++ = MAKE_HEXIT ((string[i]) & 0xf);
399     }
400
401   return 1;
402 }
403
404 static int
405 convert_IB (char *dst, const struct fmt_spec *fp, double number)
406 {
407   /* Strategy: Basically the same as convert_PIBHEX() but with
408      base 256. Then negate the two's-complement result if number
409      is negative. */
410
411   /* Used for constructing the two's-complement result. */
412   unsigned temp[8];
413
414   /* Fraction (mantissa). */
415   double frac;
416
417   /* Exponent. */
418   int exp;
419
420   /* Difference between exponent and (-8*fp->w-1). */
421   int diff;
422
423   /* Counter. */
424   int i;
425
426   /* Make the exponent (-8*fp->w-1). */
427   frac = frexp (fabs (number), &exp);
428   diff = exp - (-8 * fp->w - 1);
429   exp -= diff;
430   frac *= ldexp (1.0, diff);
431
432   /* Extract each base-256 digit. */
433   for (i = 0; i < fp->w; i++)
434     {
435       modf (frac, &frac);
436       frac *= 256.0;
437       temp[i] = floor (frac);
438     }
439
440   /* Perform two's-complement negation if number is negative. */
441   if (number < 0)
442     {
443       /* Perform NOT operation. */
444       for (i = 0; i < fp->w; i++)
445         temp[i] = ~temp[i];
446       /* Add 1 to the whole number. */
447       for (i = fp->w - 1; i >= 0; i--)
448         {
449           temp[i]++;
450           if (temp[i])
451             break;
452         }
453     }
454   memcpy (dst, temp, fp->w);
455 #ifndef WORDS_BIGENDIAN
456   buf_reverse (dst, fp->w);
457 #endif
458
459   return 1;
460 }
461
462 static int
463 convert_P (char *dst, const struct fmt_spec *fp, double number)
464 {
465   /* Buffer for fp->w*2-1 characters + a decimal point if library is
466      not quite compliant + a null. */
467   char buf[17];
468
469   /* Counter. */
470   int i;
471
472   /* Main extraction. */
473   sprintf (buf, "%0*.0f", fp->w * 2 - 1, floor (fabs (number)));
474
475   for (i = 0; i < fp->w; i++)
476     ((unsigned char *) dst)[i]
477       = ((buf[i * 2] - '0') << 4) + buf[i * 2 + 1] - '0';
478
479   /* Set sign. */
480   dst[fp->w - 1] &= 0xf0;
481   if (number >= 0.0)
482     dst[fp->w - 1] |= 0xf;
483   else
484     dst[fp->w - 1] |= 0xd;
485
486   return 1;
487 }
488
489 static int
490 convert_PIB (char *dst, const struct fmt_spec *fp, double number)
491 {
492   /* Strategy: Basically the same as convert_IB(). */
493
494   /* Fraction (mantissa). */
495   double frac;
496
497   /* Exponent. */
498   int exp;
499
500   /* Difference between exponent and (-8*fp->w). */
501   int diff;
502
503   /* Counter. */
504   int i;
505
506   /* Make the exponent (-8*fp->w). */
507   frac = frexp (fabs (number), &exp);
508   diff = exp - (-8 * fp->w);
509   exp -= diff;
510   frac *= ldexp (1.0, diff);
511
512   /* Extract each base-256 digit. */
513   for (i = 0; i < fp->w; i++)
514     {
515       modf (frac, &frac);
516       frac *= 256.0;
517       ((unsigned char *) dst)[i] = floor (frac);
518     }
519 #ifndef WORDS_BIGENDIAN
520   buf_reverse (dst, fp->w);
521 #endif
522
523   return 1;
524 }
525
526 static int
527 convert_PIBHEX (char *dst, const struct fmt_spec *fp, double number)
528 {
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. */
533
534   /* Fraction (mantissa). */
535   double frac;
536
537   /* Exponent. */
538   int exp;
539
540   /* Difference between exponent and (-4*fp->w). */
541   int diff;
542
543   /* Counter. */
544   int i;
545
546   /* Make the exponent (-4*fp->w). */
547   frac = frexp (fabs (number), &exp);
548   diff = exp - (-4 * fp->w);
549   exp -= diff;
550   frac *= ldexp (1.0, diff);
551
552   /* Extract each hexit. */
553   for (i = 0; i < fp->w; i++)
554     {
555       modf (frac, &frac);
556       frac *= 16.0;
557       *dst++ = MAKE_HEXIT ((int) floor (frac));
558     }
559
560   return 1;
561 }
562
563 static int
564 convert_PK (char *dst, const struct fmt_spec *fp, double number)
565 {
566   /* Buffer for fp->w*2 characters + a decimal point if library is not
567      quite compliant + a null. */
568   char buf[18];
569
570   /* Counter. */
571   int i;
572
573   /* Main extraction. */
574   sprintf (buf, "%0*.0f", fp->w * 2, floor (fabs (number)));
575
576   for (i = 0; i < fp->w; i++)
577     ((unsigned char *) dst)[i]
578       = ((buf[i * 2] - '0') << 4) + buf[i * 2 + 1] - '0';
579
580   return 1;
581 }
582
583 static int
584 convert_RB (char *dst, const struct fmt_spec *fp, double number)
585 {
586   union
587     {
588       double d;
589       char c[8];
590     }
591   u;
592
593   u.d = number;
594   memcpy (dst, u.c, fp->w);
595
596   return 1;
597 }
598
599 static int
600 convert_RBHEX (char *dst, const struct fmt_spec *fp, double number)
601 {
602   union
603   {
604     double d;
605     char c[8];
606   }
607   u;
608
609   int i;
610
611   u.d = number;
612   for (i = 0; i < fp->w / 2; i++)
613     {
614       *dst++ = MAKE_HEXIT (u.c[i] >> 4);
615       *dst++ = MAKE_HEXIT (u.c[i] & 15);
616     }
617
618   return 1;
619 }
620
621 static int
622 convert_CCx (char *dst, const struct fmt_spec *fp, double number)
623 {
624   if (try_CCx (dst, fp, number))
625     return 1;
626   else
627     {
628       struct fmt_spec f;
629       
630       f.type = FMT_COMMA;
631       f.w = fp->w;
632       f.d = fp->d;
633   
634       return convert_F_plus (dst, &f, number);
635     }
636 }
637
638 static int
639 convert_date (char *dst, const struct fmt_spec *fp, double number)
640 {
641   static const char *months[12] =
642     {
643       "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
644       "JUL", "AUG", "SEP", "OCT", "NOV", "DEC",
645     };
646
647   char buf[64] = {0};
648   int ofs = number / 86400.;
649   int month, day, year;
650
651   if (ofs < 1)
652     return 0;
653
654   calendar_offset_to_gregorian (ofs, &year, &month, &day);
655   switch (fp->type)
656     {
657     case FMT_DATE:
658       if (fp->w >= 11)
659         sprintf (buf, "%02d-%s-%04d", day, months[month - 1], year);
660       else
661         sprintf (buf, "%02d-%s-%02d", day, months[month - 1], year % 100);
662       break;
663     case FMT_EDATE:
664       if (fp->w >= 10)
665         sprintf (buf, "%02d.%02d.%04d", day, month, year);
666       else
667         sprintf (buf, "%02d.%02d.%02d", day, month, year % 100);
668       break;
669     case FMT_SDATE:
670       if (fp->w >= 10)
671         sprintf (buf, "%04d/%02d/%02d", year, month, day);
672       else
673         sprintf (buf, "%02d/%02d/%02d", year % 100, month, day);
674       break;
675     case FMT_ADATE:
676       if (fp->w >= 10)
677         sprintf (buf, "%02d/%02d/%04d", month, day, year);
678       else
679         sprintf (buf, "%02d/%02d/%02d", month, day, year % 100);
680       break;
681     case FMT_JDATE:
682       {
683         int yday = calendar_offset_to_yday (ofs);
684         
685         if (fp->w < 7)
686           sprintf (buf, "%02d%03d", year % 100, yday); 
687         else if (year4 (year))
688           sprintf (buf, "%04d%03d", year, yday);
689         else
690         break;
691       }
692     case FMT_QYR:
693       if (fp->w >= 8)
694         sprintf (buf, "%d Q% 04d", (month - 1) / 3 + 1, year);
695       else
696         sprintf (buf, "%d Q% 02d", (month - 1) / 3 + 1, year % 100);
697       break;
698     case FMT_MOYR:
699       if (fp->w >= 8)
700         sprintf (buf, "%s% 04d", months[month - 1], year);
701       else
702         sprintf (buf, "%s% 02d", months[month - 1], year % 100);
703       break;
704     case FMT_WKYR:
705       {
706         int yday = calendar_offset_to_yday (ofs);
707         
708         if (fp->w >= 10)
709           sprintf (buf, "%02d WK% 04d", (yday - 1) / 7 + 1, year);
710         else
711           sprintf (buf, "%02d WK% 02d", (yday - 1) / 7 + 1, year % 100);
712       }
713       break;
714     case FMT_DATETIME:
715       {
716         char *cp;
717
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.));
722         if (fp->w >= 20)
723           {
724             int w, d;
725
726             if (fp->w >= 22 && fp->d > 0)
727               {
728                 d = min (fp->d, fp->w - 21);
729                 w = 3 + d;
730               }
731             else
732               {
733                 w = 2;
734                 d = 0;
735               }
736
737             cp = spprintf (cp, ":%0*.*f", w, d, fmod (number, 60.));
738           }
739       }
740       break;
741     default:
742       NOT_REACHED ();
743     }
744
745   if (buf[0] == 0)
746     return 0;
747   buf_copy_str_rpad (dst, fp->w, buf);
748   return 1;
749 }
750
751 static int
752 convert_time (char *dst, const struct fmt_spec *fp, double number)
753 {
754   char temp_buf[40];
755   char *cp;
756
757   double time;
758   int width;
759
760   if (fabs (number) > 1e20)
761     {
762       msg (ME, _("Time value %g too large in magnitude to convert to "
763            "alphanumeric time."), number);
764       return 0;
765     }
766
767   time = number;
768   width = fp->w;
769   cp = temp_buf;
770   if (time < 0)
771     *cp++ = '-', time = -time;
772   if (fp->type == FMT_DTIME)
773     {
774       double days = floor (time / 60. / 60. / 24.);
775       cp = spprintf (temp_buf, "%02.0f ", days);
776       time = time - days * 60. * 60. * 24.;
777       width -= 3;
778     }
779   else
780     cp = temp_buf;
781
782   cp = spprintf (cp, "%02.0f:%02.0f",
783                  fmod (floor (time / 60. / 60.), 24.),
784                  fmod (floor (time / 60.), 60.));
785
786   if (width >= 8)
787     {
788       int w, d;
789
790       if (width >= 10 && fp->d >= 0 && fp->d != 0)
791         d = min (fp->d, width - 9), w = 3 + d;
792       else
793         w = 2, d = 0;
794
795       cp = spprintf (cp, ":%0*.*f", w, d, fmod (time, 60.));
796     }
797   buf_copy_str_rpad (dst, fp->w, temp_buf);
798
799   return 1;
800 }
801
802 static int
803 convert_WKDAY (char *dst, const struct fmt_spec *fp, double wkday)
804 {
805   static const char *weekdays[7] =
806     {
807       "SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY",
808       "THURSDAY", "FRIDAY", "SATURDAY",
809     };
810
811   if (wkday < 1 || wkday > 7)
812     {
813       msg (ME, _("Weekday index %f does not lie between 1 and 7."),
814            (double) wkday);
815       return 0;
816     }
817   buf_copy_str_rpad (dst, fp->w, weekdays[(int) wkday - 1]);
818
819   return 1;
820 }
821
822 static int
823 convert_MONTH (char *dst, const struct fmt_spec *fp, double month)
824 {
825   static const char *months[12] =
826     {
827       "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
828       "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER",
829     };
830
831   if (month < 1 || month > 12)
832     {
833       msg (ME, _("Month index %f does not lie between 1 and 12."),
834            month);
835       return 0;
836     }
837   
838   buf_copy_str_rpad (dst, fp->w, months[(int) month - 1]);
839
840   return 1;
841 }
842 \f
843 /* Helper functions. */
844
845 /* Copies SRC to DST, inserting commas and dollar signs as appropriate
846    for format spec *FP.  */
847 static void
848 insert_commas (char *dst, const char *src, const struct fmt_spec *fp)
849 {
850   /* Number of leading spaces in the number.  This is the amount of
851      room we have for inserting commas and dollar signs. */
852   int n_spaces;
853
854   /* Number of digits before the decimal point.  This is used to
855      determine the Number of commas to insert. */
856   int n_digits;
857
858   /* Number of commas to insert. */
859   int n_commas;
860
861   /* Number of items ,%$ to insert. */
862   int n_items;
863
864   /* Number of n_items items not to use for commas. */
865   int n_reserved;
866
867   /* Digit iterator. */
868   int i;
869
870   /* Source pointer. */
871   const char *sp;
872
873   /* Count spaces and digits. */
874   sp = src;
875   while (sp < src + fp->w && *sp == ' ')
876     sp++;
877   n_spaces = sp - src;
878   sp = src + n_spaces;
879   if (*sp == '-')
880     sp++;
881   n_digits = 0;
882   while (sp + n_digits < src + fp->w && isdigit ((unsigned char) sp[n_digits]))
883     n_digits++;
884   n_commas = (n_digits - 1) / 3;
885   n_items = n_commas + (fp->type == FMT_DOLLAR || fp->type == FMT_PCT);
886
887   /* Check whether we have enough space to do insertions. */
888   if (!n_spaces || !n_items)
889     {
890       memcpy (dst, src, fp->w);
891       return;
892     }
893   if (n_items > n_spaces)
894     {
895       n_items -= n_commas;
896       if (!n_items)
897         {
898           memcpy (dst, src, fp->w);
899           return;
900         }
901     }
902
903   /* Put spaces at the beginning if there's extra room. */
904   if (n_spaces > n_items)
905     {
906       memset (dst, ' ', n_spaces - n_items);
907       dst += n_spaces - n_items;
908     }
909
910   /* Insert $ and reserve space for %. */
911   n_reserved = 0;
912   if (fp->type == FMT_DOLLAR)
913     {
914       *dst++ = '$';
915       n_items--;
916     }
917   else if (fp->type == FMT_PCT)
918     n_reserved = 1;
919
920   /* Copy negative sign and digits, inserting commas. */
921   if (sp - src > n_spaces)
922     *dst++ = '-';
923   for (i = n_digits; i; i--)
924     {
925       if (i % 3 == 0 && n_digits > i && n_items > n_reserved)
926         {
927           n_items--;
928           *dst++ = fp->type == FMT_COMMA ? get_grouping() : get_decimal();
929         }
930       *dst++ = *sp++;
931     }
932
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)] = '%';
937 }
938
939 /* Returns 1 if YEAR (i.e., 1987) can be represented in four digits, 0
940    otherwise. */
941 static int
942 year4 (int year)
943 {
944   if (year >= 1 && year <= 9999)
945     return 1;
946   msg (ME, _("Year %d cannot be represented in four digits for "
947              "output formatting purposes."), year);
948   return 0;
949 }
950
951 static int
952 try_CCx (char *dst, const struct fmt_spec *fp, double number)
953 {
954   const struct custom_currency *cc = get_cc(fp->type - FMT_CCA);
955
956   struct fmt_spec f;
957
958   char buf[64];
959   char buf2[64];
960   char *cp;
961
962   /* Determine length available, decimal character for number
963      proper. */
964   f.type = cc->decimal == get_decimal () ? FMT_COMMA : FMT_DOT;
965   f.w = fp->w - strlen (cc->prefix) - strlen (cc->suffix);
966   if (number < 0)
967     f.w -= strlen (cc->neg_prefix) + strlen (cc->neg_suffix) - 1;
968   else
969     /* Convert -0 to +0. */
970     number = fabs (number);
971   f.d = fp->d;
972
973   if (f.w <= 0)
974     return 0;
975
976   /* There's room for all that currency crap.  Let's do the F
977      conversion first. */
978   if (!convert_F (buf, &f, number) || *buf == '*')
979     return 0;
980   insert_commas (buf2, buf, &f);
981
982   /* Postprocess back into buf. */
983   cp = buf;
984   if (number < 0)
985     cp = stpcpy (cp, cc->neg_prefix);
986   cp = stpcpy (cp, cc->prefix);
987   {
988     char *bp = buf2;
989     while (*bp == ' ')
990       bp++;
991
992     assert ((number >= 0) ^ (*bp == '-'));
993     if (number < 0)
994       bp++;
995
996     memcpy (cp, bp, f.w - (bp - buf2));
997     cp += f.w - (bp - buf2);
998   }
999   cp = stpcpy (cp, cc->suffix);
1000   if (number < 0)
1001     cp = stpcpy (cp, cc->neg_suffix);
1002
1003   /* Copy into dst. */
1004   assert (cp - buf <= fp->w);
1005   if (cp - buf < fp->w)
1006     {
1007       memcpy (&dst[fp->w - (cp - buf)], buf, cp - buf);
1008       memset (dst, ' ', fp->w - (cp - buf));
1009     }
1010   else
1011     memcpy (dst, buf, fp->w);
1012
1013   return 1;
1014 }
1015
1016 static int
1017 format_and_round (char *dst, double number, const struct fmt_spec *fp,
1018                   int decimals);
1019
1020 /* Tries to format NUMBER into DST as the F format specified in
1021    *FP.  Return true if successful, false on failure. */
1022 static int
1023 try_F (char *dst, const struct fmt_spec *fp, double number)
1024 {
1025   assert (fp->w <= 40);
1026   if (finite (number)) 
1027     {
1028       if (fabs (number) < power10[fp->w])
1029         {
1030           /* The value may fit in the field. */
1031           if (fp->d == 0) 
1032             {
1033               /* There are no decimal places, so there's no way
1034                  that the value can be shortened.  Either it fits
1035                  or it doesn't. */
1036               char buf[41];
1037               sprintf (buf, "%*.0f", fp->w, number);
1038               if (strlen (buf) <= fp->w) 
1039                 {
1040                   buf_copy_str_lpad (dst, fp->w, buf);
1041                   return true; 
1042                 }
1043               else 
1044                 return false;
1045             }
1046           else 
1047             {
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);
1054
1055               if (result >= 0)
1056                 return result;
1057
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);
1062             }
1063         }
1064       else 
1065         {
1066           /* The value is too big to fit in the field. */
1067           return false;
1068         }
1069     }
1070   else
1071     return convert_infinite (dst, fp, number);
1072 }
1073
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.
1078
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). */
1084 static int
1085 format_and_round (char *dst, double number, const struct fmt_spec *fp,
1086                   int decimals)
1087 {
1088   /* Number of characters before the decimal point,
1089      which includes digits and possibly a minus sign. */
1090   int predot_chars;
1091
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;
1095
1096   /* Points to last digit that will remain in the fraction after
1097      rounding. */
1098   char *final_frac_dig;
1099
1100   /* Round up? */
1101   bool round_up;
1102   
1103   char buf[128];
1104   
1105   assert (decimals > fp->d);
1106   if (decimals > LDBL_DIG)
1107     decimals = LDBL_DIG + 1;
1108
1109   sprintf (buf, "%.*f", decimals, number);
1110
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));
1116
1117   predot_chars = strcspn (buf, ".");
1118   if (predot_chars > fp->w) 
1119     {
1120       /* Can't possibly fit. */
1121       return 0; 
1122     }
1123   else if (predot_chars == fp->w)
1124     {
1125       /* Exact fit for integer part and sign. */
1126       memcpy (dst, buf, fp->w);
1127       return 1;
1128     }
1129   else if (predot_chars + 1 == fp->w) 
1130     {
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. */
1134       dst[0] = ' ';
1135       memcpy (dst + 1, buf, fp->w - 1);
1136       return 1;
1137     }
1138
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;
1145
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)) 
1149     {
1150       /* Exactly 1/2. */
1151       if (decimals <= LDBL_DIG)
1152         {
1153           /* Don't have enough fractional digits to know which way to
1154              round.  We can format with more decimal places, so go
1155              around again. */
1156           return -1;
1157         }
1158       else 
1159         {
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;
1163         }
1164     }
1165   else
1166     round_up = final_frac_dig[1] >= '5';
1167   final_frac_dig[1] = '\0';
1168
1169   /* Do rounding. */
1170   if (round_up) 
1171     {
1172       char *cp = final_frac_dig;
1173       for (;;) 
1174         {
1175           if (*cp >= '0' && *cp <= '8')
1176             {
1177               (*cp)++;
1178               break; 
1179             }
1180           else if (*cp == '9') 
1181             *cp = '0';
1182           else
1183             assert (*cp == '.');
1184
1185           if (cp == buf || *--cp == '-')
1186             {
1187               size_t length;
1188               
1189               /* Tried to go past the leftmost digit.  Insert a 1. */
1190               memmove (cp + 1, cp, strlen (cp) + 1);
1191               *cp = '1';
1192
1193               length = strlen (buf);
1194               if (length > fp->w) 
1195                 {
1196                   /* Inserting the `1' overflowed our space.
1197                      Drop a decimal place. */
1198                   buf[--length] = '\0';
1199
1200                   /* If that was the last decimal place, drop the
1201                      decimal point too. */
1202                   if (buf[length - 1] == '.')
1203                     buf[length - 1] = '\0';
1204                 }
1205               
1206               break;
1207             }
1208         }
1209     }
1210
1211   /* Omit `-' if value output is zero. */
1212   if (buf[0] == '-' && buf[strspn (buf, "-.0")] == '\0')
1213     memmove (buf, buf + 1, strlen (buf));
1214
1215   buf_copy_str_lpad (dst, fp->w, buf);
1216   return 1;
1217 }
1218
1219 /* Formats non-finite NUMBER into DST according to the width
1220    given in FP. */
1221 static int
1222 convert_infinite (char *dst, const struct fmt_spec *fp, double number)
1223 {
1224   assert (!finite (number));
1225   
1226   if (fp->w >= 3)
1227     {
1228       const char *s;
1229
1230       if (isnan (number))
1231         s = "NaN";
1232       else if (isinf (number))
1233         s = number > 0 ? "+Infinity" : "-Infinity";
1234       else
1235         s = "Unknown";
1236
1237       buf_copy_str_lpad (dst, fp->w, s);
1238     }
1239   else 
1240     memset (dst, '*', fp->w);
1241
1242   return true;
1243 }