Apply patch #5225, assertions.
[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
191 /* Converts V into S in F format with width W and D decimal places,
192    then deletes trailing zeros.  S is not null-terminated. */
193 void
194 num_to_string (double v, char *s, int w, int d)
195 {
196   struct fmt_spec f = make_output_format (FMT_F, w, d);
197   convert_F (s, &f, v);
198 }
199 \f
200 /* Main conversion functions. */
201
202 static void insert_commas (char *dst, const char *src,
203                            const struct fmt_spec *fp);
204 static int year4 (int year);
205 static int try_CCx (char *s, const struct fmt_spec *fp, double v);
206
207 #if FLT_RADIX!=2
208 #error Write your own floating-point output routines.
209 #endif
210
211 /* Converts a number between 0 and 15 inclusive to a `hexit'
212    [0-9A-F]. */
213 #define MAKE_HEXIT(X) ("0123456789ABCDEF"[X])
214
215 /* Table of powers of 10. */
216 static const double power10[] =
217   {
218     0,  /* Not used. */
219     1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, 1e09, 1e10,
220     1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20,
221     1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29, 1e30,
222     1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39, 1e40,
223   };
224
225 /* Handles F format. */
226 static int
227 convert_F (char *dst, const struct fmt_spec *fp, double number)
228 {
229   if (!try_F (dst, fp, number))
230     convert_E (dst, fp, number);
231   return 1;
232 }
233
234 /* Handles N format. */
235 static int
236 convert_N (char *dst, const struct fmt_spec *fp, double number)
237 {
238   double d = floor (number);
239
240   if (d < 0 || d == SYSMIS)
241     {
242       msg (ME, _("The N output format cannot be used to output a "
243                  "negative number or the system-missing value."));
244       return 0;
245     }
246   
247   if (d < power10[fp->w])
248     {
249       char buf[128];
250       sprintf (buf, "%0*.0f", fp->w, number);
251       memcpy (dst, buf, fp->w);
252     }
253   else
254     memset (dst, '*', fp->w);
255
256   return 1;
257 }
258
259 /* Handles E format.  Also operates as fallback for some other
260    formats. */
261 static int
262 convert_E (char *dst, const struct fmt_spec *fp, double number)
263 {
264   /* Temporary buffer. */
265   char buf[128];
266   
267   /* Ranged number of decimal places. */
268   int d;
269
270   if (!finite (number))
271     return convert_infinite (dst, fp, number);
272
273   /* Check that the format is wide enough.
274      Although PSPP generally checks this, convert_E() can be called as
275      a fallback from other formats which do not check. */
276   if (fp->w < 6)
277     {
278       memset (dst, '*', fp->w);
279       return 1;
280     }
281
282   /* Put decimal places in usable range. */
283   d = min (fp->d, fp->w - 6);
284   if (number < 0)
285     d--;
286   if (d < 0)
287     d = 0;
288   sprintf (buf, "%*.*E", fp->w, d, number);
289
290   /* What we do here is force the exponent part to have four
291      characters whenever possible.  That is, 1.00E+99 is okay (`E+99')
292      but 1.00E+100 (`E+100') must be coerced to 1.00+100 (`+100').  On
293      the other hand, 1.00E1000 (`E+100') cannot be canonicalized.
294      Note that ANSI C guarantees at least two digits in the
295      exponent. */
296   if (fabs (number) > 1e99)
297     {
298       /* Pointer to the `E' in buf. */
299       char *cp;
300
301       cp = strchr (buf, 'E');
302       if (cp)
303         {
304           /* Exponent better not be bigger than an int. */
305           int exp = atoi (cp + 1); 
306
307           if (abs (exp) > 99 && abs (exp) < 1000)
308             {
309               /* Shift everything left one place: 1.00e+100 -> 1.00+100. */
310               cp[0] = cp[1];
311               cp[1] = cp[2];
312               cp[2] = cp[3];
313               cp[3] = cp[4];
314             }
315           else if (abs (exp) >= 1000)
316             memset (buf, '*', fp->w);
317         }
318     }
319
320   /* The C locale always uses a period `.' as a decimal point.
321      Translate to comma if necessary. */
322   if ((get_decimal() == ',' && fp->type != FMT_DOT)
323       || (get_decimal() == '.' && fp->type == FMT_DOT))
324     {
325       char *cp = strchr (buf, '.');
326       if (cp)
327         *cp = ',';
328     }
329
330   memcpy (dst, buf, fp->w);
331   return 1;
332 }
333
334 /* Handles COMMA, DOT, DOLLAR, and PCT formats. */
335 static int
336 convert_F_plus (char *dst, const struct fmt_spec *fp, double number)
337 {
338   char buf[40];
339   
340   if (try_F (buf, fp, number))
341     insert_commas (dst, buf, fp);
342   else
343     convert_E (dst, fp, number);
344
345   return 1;
346 }
347
348 static int
349 convert_Z (char *dst, const struct fmt_spec *fp, double number)
350 {
351   static int warned = 0;
352
353   if (!warned)
354     {
355       msg (MW, 
356         _("Quality of zoned decimal (Z) output format code is "
357           "suspect.  Check your results. Report bugs to %s."),
358         PACKAGE_BUGREPORT);
359       warned = 1;
360     }
361
362   if (number == SYSMIS)
363     {
364       msg (ME, _("The system-missing value cannot be output as a zoned "
365                  "decimal number."));
366       return 0;
367     }
368   
369   {
370     char buf[41];
371     double d;
372     int i;
373     
374     d = fabs (floor (number));
375     if (d >= power10[fp->w])
376       {
377         msg (ME, _("Number %g too big to fit in field with format Z%d.%d."),
378              number, fp->w, fp->d);
379         return 0;
380       }
381
382     sprintf (buf, "%*.0f", fp->w, number);
383     for (i = 0; i < fp->w; i++)
384       dst[i] = (buf[i] - '0') | 0xf0;
385     if (number < 0)
386       dst[fp->w - 1] &= 0xdf;
387   }
388
389   return 1;
390 }
391
392 static int
393 convert_A (char *dst, const struct fmt_spec *fp, const char *string)
394 {
395   memcpy(dst, string, fp->w);
396   return 1;
397 }
398
399 static int
400 convert_AHEX (char *dst, const struct fmt_spec *fp, const char *string)
401 {
402   int i;
403
404   for (i = 0; i < fp->w / 2; i++)
405     {
406       *dst++ = MAKE_HEXIT ((string[i]) >> 4);
407       *dst++ = MAKE_HEXIT ((string[i]) & 0xf);
408     }
409
410   return 1;
411 }
412
413 static int
414 convert_IB (char *dst, const struct fmt_spec *fp, double number)
415 {
416   /* Strategy: Basically the same as convert_PIBHEX() but with
417      base 256. Then negate the two's-complement result if number
418      is negative. */
419
420   /* Used for constructing the two's-complement result. */
421   unsigned temp[8];
422
423   /* Fraction (mantissa). */
424   double frac;
425
426   /* Exponent. */
427   int exp;
428
429   /* Difference between exponent and (-8*fp->w-1). */
430   int diff;
431
432   /* Counter. */
433   int i;
434
435   /* Make the exponent (-8*fp->w-1). */
436   frac = frexp (fabs (number), &exp);
437   diff = exp - (-8 * fp->w - 1);
438   exp -= diff;
439   frac *= ldexp (1.0, diff);
440
441   /* Extract each base-256 digit. */
442   for (i = 0; i < fp->w; i++)
443     {
444       modf (frac, &frac);
445       frac *= 256.0;
446       temp[i] = floor (frac);
447     }
448
449   /* Perform two's-complement negation if number is negative. */
450   if (number < 0)
451     {
452       /* Perform NOT operation. */
453       for (i = 0; i < fp->w; i++)
454         temp[i] = ~temp[i];
455       /* Add 1 to the whole number. */
456       for (i = fp->w - 1; i >= 0; i--)
457         {
458           temp[i]++;
459           if (temp[i])
460             break;
461         }
462     }
463   memcpy (dst, temp, fp->w);
464 #ifndef WORDS_BIGENDIAN
465   buf_reverse (dst, fp->w);
466 #endif
467
468   return 1;
469 }
470
471 static int
472 convert_P (char *dst, const struct fmt_spec *fp, double number)
473 {
474   /* Buffer for fp->w*2-1 characters + a decimal point if library is
475      not quite compliant + a null. */
476   char buf[17];
477
478   /* Counter. */
479   int i;
480
481   /* Main extraction. */
482   sprintf (buf, "%0*.0f", fp->w * 2 - 1, floor (fabs (number)));
483
484   for (i = 0; i < fp->w; i++)
485     ((unsigned char *) dst)[i]
486       = ((buf[i * 2] - '0') << 4) + buf[i * 2 + 1] - '0';
487
488   /* Set sign. */
489   dst[fp->w - 1] &= 0xf0;
490   if (number >= 0.0)
491     dst[fp->w - 1] |= 0xf;
492   else
493     dst[fp->w - 1] |= 0xd;
494
495   return 1;
496 }
497
498 static int
499 convert_PIB (char *dst, const struct fmt_spec *fp, double number)
500 {
501   /* Strategy: Basically the same as convert_IB(). */
502
503   /* Fraction (mantissa). */
504   double frac;
505
506   /* Exponent. */
507   int exp;
508
509   /* Difference between exponent and (-8*fp->w). */
510   int diff;
511
512   /* Counter. */
513   int i;
514
515   /* Make the exponent (-8*fp->w). */
516   frac = frexp (fabs (number), &exp);
517   diff = exp - (-8 * fp->w);
518   exp -= diff;
519   frac *= ldexp (1.0, diff);
520
521   /* Extract each base-256 digit. */
522   for (i = 0; i < fp->w; i++)
523     {
524       modf (frac, &frac);
525       frac *= 256.0;
526       ((unsigned char *) dst)[i] = floor (frac);
527     }
528 #ifndef WORDS_BIGENDIAN
529   buf_reverse (dst, fp->w);
530 #endif
531
532   return 1;
533 }
534
535 static int
536 convert_PIBHEX (char *dst, const struct fmt_spec *fp, double number)
537 {
538   /* Strategy: Use frexp() to create a normalized result (but mostly
539      to find the base-2 exponent), then change the base-2 exponent to
540      (-4*fp->w) using multiplication and division by powers of two.
541      Extract each hexit by multiplying by 16. */
542
543   /* Fraction (mantissa). */
544   double frac;
545
546   /* Exponent. */
547   int exp;
548
549   /* Difference between exponent and (-4*fp->w). */
550   int diff;
551
552   /* Counter. */
553   int i;
554
555   /* Make the exponent (-4*fp->w). */
556   frac = frexp (fabs (number), &exp);
557   diff = exp - (-4 * fp->w);
558   exp -= diff;
559   frac *= ldexp (1.0, diff);
560
561   /* Extract each hexit. */
562   for (i = 0; i < fp->w; i++)
563     {
564       modf (frac, &frac);
565       frac *= 16.0;
566       *dst++ = MAKE_HEXIT ((int) floor (frac));
567     }
568
569   return 1;
570 }
571
572 static int
573 convert_PK (char *dst, const struct fmt_spec *fp, double number)
574 {
575   /* Buffer for fp->w*2 characters + a decimal point if library is not
576      quite compliant + a null. */
577   char buf[18];
578
579   /* Counter. */
580   int i;
581
582   /* Main extraction. */
583   sprintf (buf, "%0*.0f", fp->w * 2, floor (fabs (number)));
584
585   for (i = 0; i < fp->w; i++)
586     ((unsigned char *) dst)[i]
587       = ((buf[i * 2] - '0') << 4) + buf[i * 2 + 1] - '0';
588
589   return 1;
590 }
591
592 static int
593 convert_RB (char *dst, const struct fmt_spec *fp, double number)
594 {
595   union
596     {
597       double d;
598       char c[8];
599     }
600   u;
601
602   u.d = number;
603   memcpy (dst, u.c, fp->w);
604
605   return 1;
606 }
607
608 static int
609 convert_RBHEX (char *dst, const struct fmt_spec *fp, double number)
610 {
611   union
612   {
613     double d;
614     char c[8];
615   }
616   u;
617
618   int i;
619
620   u.d = number;
621   for (i = 0; i < fp->w / 2; i++)
622     {
623       *dst++ = MAKE_HEXIT (u.c[i] >> 4);
624       *dst++ = MAKE_HEXIT (u.c[i] & 15);
625     }
626
627   return 1;
628 }
629
630 static int
631 convert_CCx (char *dst, const struct fmt_spec *fp, double number)
632 {
633   if (try_CCx (dst, fp, number))
634     return 1;
635   else
636     {
637       struct fmt_spec f;
638       
639       f.type = FMT_COMMA;
640       f.w = fp->w;
641       f.d = fp->d;
642   
643       return convert_F_plus (dst, &f, number);
644     }
645 }
646
647 static int
648 convert_date (char *dst, const struct fmt_spec *fp, double number)
649 {
650   static const char *months[12] =
651     {
652       "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
653       "JUL", "AUG", "SEP", "OCT", "NOV", "DEC",
654     };
655
656   char buf[64] = {0};
657   int ofs = number / 86400.;
658   int month, day, year;
659
660   if (ofs < 1)
661     return 0;
662
663   calendar_offset_to_gregorian (ofs, &year, &month, &day);
664   switch (fp->type)
665     {
666     case FMT_DATE:
667       if (fp->w >= 11)
668         sprintf (buf, "%02d-%s-%04d", day, months[month - 1], year);
669       else
670         sprintf (buf, "%02d-%s-%02d", day, months[month - 1], year % 100);
671       break;
672     case FMT_EDATE:
673       if (fp->w >= 10)
674         sprintf (buf, "%02d.%02d.%04d", day, month, year);
675       else
676         sprintf (buf, "%02d.%02d.%02d", day, month, year % 100);
677       break;
678     case FMT_SDATE:
679       if (fp->w >= 10)
680         sprintf (buf, "%04d/%02d/%02d", year, month, day);
681       else
682         sprintf (buf, "%02d/%02d/%02d", year % 100, month, day);
683       break;
684     case FMT_ADATE:
685       if (fp->w >= 10)
686         sprintf (buf, "%02d/%02d/%04d", month, day, year);
687       else
688         sprintf (buf, "%02d/%02d/%02d", month, day, year % 100);
689       break;
690     case FMT_JDATE:
691       {
692         int yday = calendar_offset_to_yday (ofs);
693         
694         if (fp->w < 7)
695           sprintf (buf, "%02d%03d", year % 100, yday); 
696         else if (year4 (year))
697           sprintf (buf, "%04d%03d", year, yday);
698         else
699         break;
700       }
701     case FMT_QYR:
702       if (fp->w >= 8)
703         sprintf (buf, "%d Q% 04d", (month - 1) / 3 + 1, year);
704       else
705         sprintf (buf, "%d Q% 02d", (month - 1) / 3 + 1, year % 100);
706       break;
707     case FMT_MOYR:
708       if (fp->w >= 8)
709         sprintf (buf, "%s% 04d", months[month - 1], year);
710       else
711         sprintf (buf, "%s% 02d", months[month - 1], year % 100);
712       break;
713     case FMT_WKYR:
714       {
715         int yday = calendar_offset_to_yday (ofs);
716         
717         if (fp->w >= 10)
718           sprintf (buf, "%02d WK% 04d", (yday - 1) / 7 + 1, year);
719         else
720           sprintf (buf, "%02d WK% 02d", (yday - 1) / 7 + 1, year % 100);
721       }
722       break;
723     case FMT_DATETIME:
724       {
725         char *cp;
726
727         cp = spprintf (buf, "%02d-%s-%04d %02d:%02d",
728                        day, months[month - 1], year,
729                        (int) fmod (floor (number / 60. / 60.), 24.),
730                        (int) fmod (floor (number / 60.), 60.));
731         if (fp->w >= 20)
732           {
733             int w, d;
734
735             if (fp->w >= 22 && fp->d > 0)
736               {
737                 d = min (fp->d, fp->w - 21);
738                 w = 3 + d;
739               }
740             else
741               {
742                 w = 2;
743                 d = 0;
744               }
745
746             cp = spprintf (cp, ":%0*.*f", w, d, fmod (number, 60.));
747           }
748       }
749       break;
750     default:
751       NOT_REACHED ();
752     }
753
754   if (buf[0] == 0)
755     return 0;
756   buf_copy_str_rpad (dst, fp->w, buf);
757   return 1;
758 }
759
760 static int
761 convert_time (char *dst, const struct fmt_spec *fp, double number)
762 {
763   char temp_buf[40];
764   char *cp;
765
766   double time;
767   int width;
768
769   if (fabs (number) > 1e20)
770     {
771       msg (ME, _("Time value %g too large in magnitude to convert to "
772            "alphanumeric time."), number);
773       return 0;
774     }
775
776   time = number;
777   width = fp->w;
778   cp = temp_buf;
779   if (time < 0)
780     *cp++ = '-', time = -time;
781   if (fp->type == FMT_DTIME)
782     {
783       double days = floor (time / 60. / 60. / 24.);
784       cp = spprintf (temp_buf, "%02.0f ", days);
785       time = time - days * 60. * 60. * 24.;
786       width -= 3;
787     }
788   else
789     cp = temp_buf;
790
791   cp = spprintf (cp, "%02.0f:%02.0f",
792                  fmod (floor (time / 60. / 60.), 24.),
793                  fmod (floor (time / 60.), 60.));
794
795   if (width >= 8)
796     {
797       int w, d;
798
799       if (width >= 10 && fp->d >= 0 && fp->d != 0)
800         d = min (fp->d, width - 9), w = 3 + d;
801       else
802         w = 2, d = 0;
803
804       cp = spprintf (cp, ":%0*.*f", w, d, fmod (time, 60.));
805     }
806   buf_copy_str_rpad (dst, fp->w, temp_buf);
807
808   return 1;
809 }
810
811 static int
812 convert_WKDAY (char *dst, const struct fmt_spec *fp, double wkday)
813 {
814   static const char *weekdays[7] =
815     {
816       "SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY",
817       "THURSDAY", "FRIDAY", "SATURDAY",
818     };
819
820   if (wkday < 1 || wkday > 7)
821     {
822       msg (ME, _("Weekday index %f does not lie between 1 and 7."),
823            (double) wkday);
824       return 0;
825     }
826   buf_copy_str_rpad (dst, fp->w, weekdays[(int) wkday - 1]);
827
828   return 1;
829 }
830
831 static int
832 convert_MONTH (char *dst, const struct fmt_spec *fp, double month)
833 {
834   static const char *months[12] =
835     {
836       "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
837       "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER",
838     };
839
840   if (month < 1 || month > 12)
841     {
842       msg (ME, _("Month index %f does not lie between 1 and 12."),
843            month);
844       return 0;
845     }
846   
847   buf_copy_str_rpad (dst, fp->w, months[(int) month - 1]);
848
849   return 1;
850 }
851 \f
852 /* Helper functions. */
853
854 /* Copies SRC to DST, inserting commas and dollar signs as appropriate
855    for format spec *FP.  */
856 static void
857 insert_commas (char *dst, const char *src, const struct fmt_spec *fp)
858 {
859   /* Number of leading spaces in the number.  This is the amount of
860      room we have for inserting commas and dollar signs. */
861   int n_spaces;
862
863   /* Number of digits before the decimal point.  This is used to
864      determine the Number of commas to insert. */
865   int n_digits;
866
867   /* Number of commas to insert. */
868   int n_commas;
869
870   /* Number of items ,%$ to insert. */
871   int n_items;
872
873   /* Number of n_items items not to use for commas. */
874   int n_reserved;
875
876   /* Digit iterator. */
877   int i;
878
879   /* Source pointer. */
880   const char *sp;
881
882   /* Count spaces and digits. */
883   sp = src;
884   while (sp < src + fp->w && *sp == ' ')
885     sp++;
886   n_spaces = sp - src;
887   sp = src + n_spaces;
888   if (*sp == '-')
889     sp++;
890   n_digits = 0;
891   while (sp + n_digits < src + fp->w && isdigit ((unsigned char) sp[n_digits]))
892     n_digits++;
893   n_commas = (n_digits - 1) / 3;
894   n_items = n_commas + (fp->type == FMT_DOLLAR || fp->type == FMT_PCT);
895
896   /* Check whether we have enough space to do insertions. */
897   if (!n_spaces || !n_items)
898     {
899       memcpy (dst, src, fp->w);
900       return;
901     }
902   if (n_items > n_spaces)
903     {
904       n_items -= n_commas;
905       if (!n_items)
906         {
907           memcpy (dst, src, fp->w);
908           return;
909         }
910     }
911
912   /* Put spaces at the beginning if there's extra room. */
913   if (n_spaces > n_items)
914     {
915       memset (dst, ' ', n_spaces - n_items);
916       dst += n_spaces - n_items;
917     }
918
919   /* Insert $ and reserve space for %. */
920   n_reserved = 0;
921   if (fp->type == FMT_DOLLAR)
922     {
923       *dst++ = '$';
924       n_items--;
925     }
926   else if (fp->type == FMT_PCT)
927     n_reserved = 1;
928
929   /* Copy negative sign and digits, inserting commas. */
930   if (sp - src > n_spaces)
931     *dst++ = '-';
932   for (i = n_digits; i; i--)
933     {
934       if (i % 3 == 0 && n_digits > i && n_items > n_reserved)
935         {
936           n_items--;
937           *dst++ = fp->type == FMT_COMMA ? get_grouping() : get_decimal();
938         }
939       *dst++ = *sp++;
940     }
941
942   /* Copy decimal places and insert % if necessary. */
943   memcpy (dst, sp, fp->w - (sp - src));
944   if (fp->type == FMT_PCT && n_items > 0)
945     dst[fp->w - (sp - src)] = '%';
946 }
947
948 /* Returns 1 if YEAR (i.e., 1987) can be represented in four digits, 0
949    otherwise. */
950 static int
951 year4 (int year)
952 {
953   if (year >= 1 && year <= 9999)
954     return 1;
955   msg (ME, _("Year %d cannot be represented in four digits for "
956              "output formatting purposes."), year);
957   return 0;
958 }
959
960 static int
961 try_CCx (char *dst, const struct fmt_spec *fp, double number)
962 {
963   const struct custom_currency *cc = get_cc(fp->type - FMT_CCA);
964
965   struct fmt_spec f;
966
967   char buf[64];
968   char buf2[64];
969   char *cp;
970
971   /* Determine length available, decimal character for number
972      proper. */
973   f.type = cc->decimal == get_decimal () ? FMT_COMMA : FMT_DOT;
974   f.w = fp->w - strlen (cc->prefix) - strlen (cc->suffix);
975   if (number < 0)
976     f.w -= strlen (cc->neg_prefix) + strlen (cc->neg_suffix) - 1;
977   else
978     /* Convert -0 to +0. */
979     number = fabs (number);
980   f.d = fp->d;
981
982   if (f.w <= 0)
983     return 0;
984
985   /* There's room for all that currency crap.  Let's do the F
986      conversion first. */
987   if (!convert_F (buf, &f, number) || *buf == '*')
988     return 0;
989   insert_commas (buf2, buf, &f);
990
991   /* Postprocess back into buf. */
992   cp = buf;
993   if (number < 0)
994     cp = stpcpy (cp, cc->neg_prefix);
995   cp = stpcpy (cp, cc->prefix);
996   {
997     char *bp = buf2;
998     while (*bp == ' ')
999       bp++;
1000
1001     assert ((number >= 0) ^ (*bp == '-'));
1002     if (number < 0)
1003       bp++;
1004
1005     memcpy (cp, bp, f.w - (bp - buf2));
1006     cp += f.w - (bp - buf2);
1007   }
1008   cp = stpcpy (cp, cc->suffix);
1009   if (number < 0)
1010     cp = stpcpy (cp, cc->neg_suffix);
1011
1012   /* Copy into dst. */
1013   assert (cp - buf <= fp->w);
1014   if (cp - buf < fp->w)
1015     {
1016       memcpy (&dst[fp->w - (cp - buf)], buf, cp - buf);
1017       memset (dst, ' ', fp->w - (cp - buf));
1018     }
1019   else
1020     memcpy (dst, buf, fp->w);
1021
1022   return 1;
1023 }
1024
1025 static int
1026 format_and_round (char *dst, double number, const struct fmt_spec *fp,
1027                   int decimals);
1028
1029 /* Tries to format NUMBER into DST as the F format specified in
1030    *FP.  Return true if successful, false on failure. */
1031 static int
1032 try_F (char *dst, const struct fmt_spec *fp, double number)
1033 {
1034   assert (fp->w <= 40);
1035   if (finite (number)) 
1036     {
1037       if (fabs (number) < power10[fp->w])
1038         {
1039           /* The value may fit in the field. */
1040           if (fp->d == 0) 
1041             {
1042               /* There are no decimal places, so there's no way
1043                  that the value can be shortened.  Either it fits
1044                  or it doesn't. */
1045               char buf[41];
1046               sprintf (buf, "%*.0f", fp->w, number);
1047               if (strlen (buf) <= fp->w) 
1048                 {
1049                   buf_copy_str_lpad (dst, fp->w, buf);
1050                   return true; 
1051                 }
1052               else 
1053                 return false;
1054             }
1055           else 
1056             {
1057               /* First try to format it with 2 extra decimal
1058                  places.  This gives us a good chance of not
1059                  needing even more decimal places, but it also
1060                  avoids wasting too much time formatting more
1061                  decimal places on the first try. */
1062               int result = format_and_round (dst, number, fp, fp->d + 2);
1063
1064               if (result >= 0)
1065                 return result;
1066
1067               /* 2 extra decimal places weren't enough to
1068                  correctly round.  Try again with the maximum
1069                  number of places. */
1070               return format_and_round (dst, number, fp, LDBL_DIG + 1);
1071             }
1072         }
1073       else 
1074         {
1075           /* The value is too big to fit in the field. */
1076           return false;
1077         }
1078     }
1079   else
1080     return convert_infinite (dst, fp, number);
1081 }
1082
1083 /* Tries to compose NUMBER into DST in format FP by first
1084    formatting it with DECIMALS decimal places, then rounding off
1085    to as many decimal places will fit or the number specified in
1086    FP, whichever is fewer.
1087
1088    Returns 1 if conversion succeeds, 0 if this try at conversion
1089    failed and so will any other tries (because the integer part
1090    of the number is too long), or -1 if this try failed but
1091    another with higher DECIMALS might succeed (because we'd be
1092    able to properly round). */
1093 static int
1094 format_and_round (char *dst, double number, const struct fmt_spec *fp,
1095                   int decimals)
1096 {
1097   /* Number of characters before the decimal point,
1098      which includes digits and possibly a minus sign. */
1099   int predot_chars;
1100
1101   /* Number of digits in the output fraction,
1102      which may be smaller than fp->d if there's not enough room. */
1103   int fraction_digits;
1104
1105   /* Points to last digit that will remain in the fraction after
1106      rounding. */
1107   char *final_frac_dig;
1108
1109   /* Round up? */
1110   bool round_up;
1111   
1112   char buf[128];
1113   
1114   assert (decimals > fp->d);
1115   if (decimals > LDBL_DIG)
1116     decimals = LDBL_DIG + 1;
1117
1118   sprintf (buf, "%.*f", decimals, number);
1119
1120   /* Omit integer part if it's 0. */
1121   if (!memcmp (buf, "0.", 2))
1122     memmove (buf, buf + 1, strlen (buf));
1123   else if (!memcmp (buf, "-0.", 3))
1124     memmove (buf + 1, buf + 2, strlen (buf + 1));
1125
1126   predot_chars = strcspn (buf, ".");
1127   if (predot_chars > fp->w) 
1128     {
1129       /* Can't possibly fit. */
1130       return 0; 
1131     }
1132   else if (predot_chars == fp->w)
1133     {
1134       /* Exact fit for integer part and sign. */
1135       memcpy (dst, buf, fp->w);
1136       return 1;
1137     }
1138   else if (predot_chars + 1 == fp->w) 
1139     {
1140       /* There's room for the decimal point, but not for any
1141          digits of the fraction.
1142          Right-justify the integer part and sign. */
1143       dst[0] = ' ';
1144       memcpy (dst + 1, buf, fp->w - 1);
1145       return 1;
1146     }
1147
1148   /* It looks like we have room for at least one digit of the
1149      fraction.  Figure out how many. */
1150   fraction_digits = fp->w - predot_chars - 1;
1151   if (fraction_digits > fp->d)
1152     fraction_digits = fp->d;
1153   final_frac_dig = buf + predot_chars + fraction_digits;
1154
1155   /* Decide rounding direction and truncate string. */
1156   if (final_frac_dig[1] == '5'
1157       && strspn (final_frac_dig + 2, "0") == strlen (final_frac_dig + 2)) 
1158     {
1159       /* Exactly 1/2. */
1160       if (decimals <= LDBL_DIG)
1161         {
1162           /* Don't have enough fractional digits to know which way to
1163              round.  We can format with more decimal places, so go
1164              around again. */
1165           return -1;
1166         }
1167       else 
1168         {
1169           /* We used up all our fractional digits and still don't
1170              know.  Round to even. */
1171           round_up = (final_frac_dig[0] - '0') % 2 != 0;
1172         }
1173     }
1174   else
1175     round_up = final_frac_dig[1] >= '5';
1176   final_frac_dig[1] = '\0';
1177
1178   /* Do rounding. */
1179   if (round_up) 
1180     {
1181       char *cp = final_frac_dig;
1182       for (;;) 
1183         {
1184           if (*cp >= '0' && *cp <= '8')
1185             {
1186               (*cp)++;
1187               break; 
1188             }
1189           else if (*cp == '9') 
1190             *cp = '0';
1191           else
1192             assert (*cp == '.');
1193
1194           if (cp == buf || *--cp == '-')
1195             {
1196               size_t length;
1197               
1198               /* Tried to go past the leftmost digit.  Insert a 1. */
1199               memmove (cp + 1, cp, strlen (cp) + 1);
1200               *cp = '1';
1201
1202               length = strlen (buf);
1203               if (length > fp->w) 
1204                 {
1205                   /* Inserting the `1' overflowed our space.
1206                      Drop a decimal place. */
1207                   buf[--length] = '\0';
1208
1209                   /* If that was the last decimal place, drop the
1210                      decimal point too. */
1211                   if (buf[length - 1] == '.')
1212                     buf[length - 1] = '\0';
1213                 }
1214               
1215               break;
1216             }
1217         }
1218     }
1219
1220   /* Omit `-' if value output is zero. */
1221   if (buf[0] == '-' && buf[strspn (buf, "-.0")] == '\0')
1222     memmove (buf, buf + 1, strlen (buf));
1223
1224   buf_copy_str_lpad (dst, fp->w, buf);
1225   return 1;
1226 }
1227
1228 /* Formats non-finite NUMBER into DST according to the width
1229    given in FP. */
1230 static int
1231 convert_infinite (char *dst, const struct fmt_spec *fp, double number)
1232 {
1233   assert (!finite (number));
1234   
1235   if (fp->w >= 3)
1236     {
1237       const char *s;
1238
1239       if (isnan (number))
1240         s = "NaN";
1241       else if (isinf (number))
1242         s = number > 0 ? "+Infinity" : "-Infinity";
1243       else
1244         s = "Unknown";
1245
1246       buf_copy_str_lpad (dst, fp->w, s);
1247     }
1248   else 
1249     memset (dst, '*', fp->w);
1250
1251   return true;
1252 }