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