24428c6ac69c241a3fcb936f34614ff1045c1518
[pspp-builds.git] / src / 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., 59 Temple Place - Suite 330, Boston, MA
18    02111-1307, USA. */
19
20 #include <config.h>
21 #include <assert.h>
22 #include <ctype.h>
23 #include <math.h>
24 #include <float.h>
25 #include <stdlib.h>
26 #include <time.h>
27 #include "approx.h"
28 #include "error.h"
29 #include "format.h"
30 #include "julcal/julcal.h"
31 #include "magic.h"
32 #include "misc.h"
33 #include "misc.h"
34 #include "settings.h"
35 #include "str.h"
36 #include "var.h"
37
38 #undef DEBUGGING
39 /*#define DEBUGGING 1*/
40 #include "debug-print.h"
41
42 /* In older versions, numbers got their trailing zeros stripped.
43    Newer versions leave them on when there's room.  Comment this next
44    line out for retro styling. */
45 #define NEW_STYLE 1
46 \f
47 /* Public functions. */
48
49 typedef int convert_func (char *, const struct fmt_spec *,
50                           const union value *);
51
52 static convert_func convert_F, convert_N, convert_E, convert_F_plus;
53 static convert_func convert_Z, convert_A, convert_AHEX, convert_IB;
54 static convert_func convert_P, convert_PIB, convert_PIBHEX, convert_PK;
55 static convert_func convert_RB, convert_RBHEX, convert_CCx, convert_date;
56 static convert_func convert_time, convert_WKDAY, convert_MONTH;
57 static convert_func try_F;
58
59 /* Converts binary value V into printable form in string S according
60    to format specification FP.  The string as written has exactly
61    FP->W characters.  It is not null-terminated.  Returns 1 on
62    success, 0 on failure. */
63 int
64 data_out (char *s, const struct fmt_spec *fp, const union value *v)
65 {
66   union value tmp_val;
67   
68   {
69     int cat = formats[fp->type].cat;
70     if ((cat & FCAT_BLANKS_SYSMIS) && v->f == SYSMIS)
71       {
72         memset (s, ' ', fp->w);
73         s[fp->w - fp->d - 1] = '.';
74         return 1;
75       }
76     if ((cat & FCAT_SHIFT_DECIMAL) && v->f != SYSMIS && fp->d)
77       {
78         tmp_val.f = v->f * pow (10.0, fp->d);
79         v = &tmp_val;
80       }
81   }
82   
83   {
84     static convert_func *const handlers[FMT_NUMBER_OF_FORMATS] =
85       {
86         convert_F, convert_N, convert_E, convert_F_plus,
87         convert_F_plus, convert_F_plus, convert_F_plus,
88         convert_Z, convert_A, convert_AHEX, convert_IB, convert_P, convert_PIB,
89         convert_PIBHEX, convert_PK, convert_RB, convert_RBHEX,
90         convert_CCx, convert_CCx, convert_CCx, convert_CCx, convert_CCx,
91         convert_date, convert_date, convert_date, convert_date, convert_date,
92         convert_date, convert_date, convert_date, convert_date,
93         convert_time, convert_time,
94         convert_WKDAY, convert_MONTH,
95       };
96
97     return handlers[fp->type] (s, fp, v);
98   }
99 }
100
101 /* Converts V into S in F format with width W and D decimal places,
102    then deletes trailing zeros.  S is not null-terminated. */
103 void
104 num_to_string (double v, char *s, int w, int d)
105 {
106   /* Dummies to pass to convert_F. */
107   union value val;
108   struct fmt_spec f;
109
110 #if !NEW_STYLE
111   /* Pointer to `.' in S. */
112   char *decp;
113
114   /* Pointer to `E' in S. */
115   char *expp;
116
117   /* Number of characters to delete. */
118   int n = 0;
119 #endif
120
121   f.w = w;
122   f.d = d;
123   val.f = v;
124
125   /* Cut out the jokers. */
126   if (!finite (v))
127     {
128       char temp[9];
129       int len;
130
131       if (isnan (v))
132         {
133           memcpy (temp, "NaN", 3);
134           len = 3;
135         }
136       else if (isinf (v))
137         {
138           memcpy (temp, "+Infinity", 9);
139           if (v < 0)
140             temp[0] = '-';
141           len = 9;
142         }
143       else
144         {
145           memcpy (temp, _("Unknown"), 7);
146           len = 7;
147         }
148       if (w > len)
149         {
150           int pad = w - len;
151           memset (s, ' ', pad);
152           s += pad;
153           w -= pad;
154         }
155       memcpy (s, temp, w);
156       return;
157     }
158
159   try_F (s, &f, &val);
160
161 #if !NEW_STYLE
162   decp = memchr (s, set_decimal, w);
163   if (!decp)
164     return;
165
166   /* If there's an `E' we can only delete 0s before the E. */
167   expp = memchr (s, 'E', w);
168   if (expp)
169     {
170       while (expp[-n - 1] == '0')
171         n++;
172       if (expp[-n - 1] == set_decimal)
173         n++;
174       memmove (&s[n], s, expp - s - n);
175       memset (s, ' ', n);
176       return;
177     }
178
179   /* Otherwise delete all trailing 0s. */
180   n++;
181   while (s[w - n] == '0')
182     n++;
183   if (s[w - n] != set_decimal)
184     {
185       /* Avoid stripping `.0' to `'. */
186       if (w == n || !isdigit ((unsigned char) s[w - n - 1]))
187         n -= 2;
188     }
189   else
190     n--;
191   memmove (&s[n], s, w - n);
192   memset (s, ' ', n);
193 #endif
194 }
195 \f
196 /* Main conversion functions. */
197
198 static void insert_commas (char *dst, const char *src,
199                            const struct fmt_spec *fp);
200 static int year4 (int year);
201 static int try_CCx (char *s, const struct fmt_spec *fp, double v);
202
203 #if FLT_RADIX!=2
204 #error Write your own floating-point output routines.
205 #endif
206
207 /* PORTME:
208
209    Some of the routines in this file are likely very specific to
210    base-2 representation of floating-point numbers, most notably the
211    routines that use frexp() or ldexp().  These attempt to extract
212    individual digits by setting the base-2 exponent and
213    multiplying/dividing by powers of 2.  In base-2 numeration systems,
214    this just nudges the exponent up or down, but in base-10 floating
215    point, such multiplications/division can cause catastrophic loss of
216    precision.
217
218    The author has never personally used a machine that didn't use
219    binary floating point formats, so he is unwilling, and perhaps
220    unable, to code around this "problem".  */
221
222 /* Converts a number between 0 and 15 inclusive to a `hexit'
223    [0-9A-F]. */
224 #define MAKE_HEXIT(X) ("0123456789ABCDEF"[X])
225
226 /* Table of powers of 10. */
227 static const double power10[] =
228   {
229     0,  /* Not used. */
230     1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, 1e09, 1e10,
231     1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20,
232     1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29, 1e30,
233     1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39, 1e40,
234   };
235
236 /* Handles F format. */
237 static int
238 convert_F (char *dst, const struct fmt_spec *fp, const union value *v)
239 {
240   if (!try_F (dst, fp, v))
241     convert_E (dst, fp, v);
242   return 1;
243 }
244
245 /* Handles N format. */
246 static int
247 convert_N (char *dst, const struct fmt_spec *fp, const union value *v)
248 {
249   double d = floor (v->f);
250
251   if (d < 0 || d == SYSMIS)
252     {
253       msg (ME, _("The N output format cannot be used to output a "
254                  "negative number or the system-missing value."));
255       return 0;
256     }
257   
258   if (d < power10[fp->w])
259     {
260       char buf[128];
261       sprintf (buf, "%0*.0f", fp->w, v->f);
262       memcpy (dst, buf, fp->w);
263     }
264   else
265     memset (dst, '*', fp->w);
266
267   return 1;
268 }
269
270 /* Handles E format.  Also operates as fallback for some other
271    formats. */
272 static int
273 convert_E (char *dst, const struct fmt_spec *fp, const union value *v)
274 {
275   /* Temporary buffer. */
276   char buf[128];
277   
278   /* Ranged number of decimal places. */
279   int d;
280
281   /* Check that the format is width enough.
282      Although PSPP generally checks this, convert_E() can be called as
283      a fallback from other formats which do not check. */
284   if (fp->w < 6)
285     {
286       memset (dst, '*', fp->w);
287       return 1;
288     }
289
290   /* Put decimal places in usable range. */
291   d = min (fp->d, fp->w - 6);
292   if (v->f < 0)
293     d--;
294   if (d < 0)
295     d = 0;
296   sprintf (buf, "%*.*E", fp->w, d, v->f);
297
298   /* What we do here is force the exponent part to have four
299      characters whenever possible.  That is, 1.00E+99 is okay (`E+99')
300      but 1.00E+100 (`E+100') must be coerced to 1.00+100 (`+100').  On
301      the other hand, 1.00E1000 (`E+100') cannot be canonicalized.
302      Note that ANSI C guarantees at least two digits in the
303      exponent. */
304   if (fabs (v->f) > 1e99)
305     {
306       /* Pointer to the `E' in buf. */
307       char *cp;
308
309       cp = strchr (buf, 'E');
310       if (cp)
311         {
312           /* Exponent better not be bigger than an int. */
313           int exp = atoi (cp + 1); 
314
315           if (abs (exp) > 99 && abs (exp) < 1000)
316             {
317               /* Shift everything left one place: 1.00e+100 -> 1.00+100. */
318               cp[0] = cp[1];
319               cp[1] = cp[2];
320               cp[2] = cp[3];
321               cp[3] = cp[4];
322             }
323           else if (abs (exp) >= 1000)
324             memset (buf, '*', fp->w);
325         }
326     }
327
328   /* The C locale always uses a period `.' as a decimal point.
329      Translate to comma if necessary. */
330   if ((set_decimal == ',' && fp->type != FMT_DOT)
331       || (set_decimal == '.' && fp->type == FMT_DOT))
332     {
333       char *cp = strchr (buf, '.');
334       if (cp)
335         *cp = ',';
336     }
337
338   memcpy (dst, buf, fp->w);
339   return 1;
340 }
341
342 /* Handles COMMA, DOT, DOLLAR, and PCT formats. */
343 static int
344 convert_F_plus (char *dst, const struct fmt_spec *fp, const union value *v)
345 {
346   char buf[40];
347   
348   if (try_F (buf, fp, v))
349     insert_commas (dst, buf, fp);
350   else
351     convert_E (dst, fp, v);
352
353   return 1;
354 }
355
356 static int
357 convert_Z (char *dst, const struct fmt_spec *fp, const union value *v)
358 {
359   static int warned = 0;
360
361   if (!warned)
362     {
363       msg (MW, _("Quality of zoned decimal (Z) output format code is "
364                  "suspect.  Check your results, report bugs to author."));
365       warned = 1;
366     }
367
368   if (v->f == SYSMIS)
369     {
370       msg (ME, _("The system-missing value cannot be output as a zoned "
371                  "decimal number."));
372       return 0;
373     }
374   
375   {
376     char buf[41];
377     double d;
378     int i;
379     
380     d = fabs (floor (v->f));
381     if (d >= power10[fp->w])
382       {
383         msg (ME, _("Number %g too big to fit in field with format Z%d.%d."),
384              v->f, fp->w, fp->d);
385         return 0;
386       }
387
388     sprintf (buf, "%*.0f", fp->w, v->f);
389     for (i = 0; i < fp->w; i++)
390       dst[i] = (buf[i] - '0') | 0xf0;
391     if (v->f < 0)
392       dst[fp->w - 1] &= 0xdf;
393   }
394
395   return 1;
396 }
397
398 static int
399 convert_A (char *dst, const struct fmt_spec *fp, const union value *v)
400 {
401   memcpy (dst, v->c, fp->w);
402   return 1;
403 }
404
405 static int
406 convert_AHEX (char *dst, const struct fmt_spec *fp, const union value *v)
407 {
408   int i;
409
410   for (i = 0; i < fp->w / 2; i++)
411     {
412       ((unsigned char *) dst)[i * 2] = MAKE_HEXIT ((v->c[i]) >> 4);
413       ((unsigned char *) dst)[i * 2 + 1] = MAKE_HEXIT ((v->c[i]) & 0xf);
414     }
415
416   return 1;
417 }
418
419 static int
420 convert_IB (char *dst, const struct fmt_spec *fp, const union value *v)
421 {
422   /* Strategy: Basically the same as convert_PIBHEX() but with base
423      256. Then it's necessary to negate the two's-complement result if
424      v->f is negative. */
425
426   /* Used for constructing the two's-complement result. */
427   unsigned temp[8];
428
429   /* Fraction (mantissa). */
430   double frac;
431
432   /* Exponent. */
433   int exp;
434
435   /* Difference between exponent and (-8*fp->w-1). */
436   int diff;
437
438   /* Counter. */
439   int i;
440
441   /* Make the exponent (-8*fp->w-1). */
442   frac = frexp (fabs (v->f), &exp);
443   diff = exp - (-8 * fp->w - 1);
444   exp -= diff;
445   frac *= ldexp (1.0, diff);
446
447   /* Extract each base-256 digit. */
448   for (i = 0; i < fp->w; i++)
449     {
450       modf (frac, &frac);
451       frac *= 256.0;
452       temp[i] = floor (frac);
453     }
454
455   /* Perform two's-complement negation if v->f is negative. */
456   if (v->f < 0)
457     {
458       /* Perform NOT operation. */
459       for (i = 0; i < fp->w; i++)
460         temp[i] = ~temp[i];
461       /* Add 1 to the whole number. */
462       for (i = fp->w - 1; i >= 0; i--)
463         {
464           temp[i]++;
465           if (temp[i])
466             break;
467         }
468     }
469   memcpy (dst, temp, fp->w);
470   if (endian == LITTLE)
471     mm_reverse (dst, fp->w);
472
473   return 1;
474 }
475
476 static int
477 convert_P (char *dst, const struct fmt_spec *fp, const union value *v)
478 {
479   /* Buffer for v->f*2-1 characters + a decimal point if library is
480      not quite compliant + a null. */
481   char buf[17];
482
483   /* Counter. */
484   int i;
485
486   /* Main extraction. */
487   sprintf (buf, "%0*.0f", fp->w * 2 - 1, floor (fabs (v->f)));
488
489   for (i = 0; i < fp->w; i++)
490     ((unsigned char *) dst)[i]
491       = ((buf[i * 2] - '0') << 4) + buf[i * 2 + 1] - '0';
492
493   /* Set sign. */
494   dst[fp->w - 1] &= 0xf0;
495   if (v->f >= 0.0)
496     dst[fp->w - 1] |= 0xf;
497   else
498     dst[fp->w - 1] |= 0xd;
499
500   return 1;
501 }
502
503 static int
504 convert_PIB (char *dst, const struct fmt_spec *fp, const union value *v)
505 {
506   /* Strategy: Basically the same as convert_IB(). */
507
508   /* Fraction (mantissa). */
509   double frac;
510
511   /* Exponent. */
512   int exp;
513
514   /* Difference between exponent and (-8*fp->w). */
515   int diff;
516
517   /* Counter. */
518   int i;
519
520   /* Make the exponent (-8*fp->w). */
521   frac = frexp (fabs (v->f), &exp);
522   diff = exp - (-8 * fp->w);
523   exp -= diff;
524   frac *= ldexp (1.0, diff);
525
526   /* Extract each base-256 digit. */
527   for (i = 0; i < fp->w; i++)
528     {
529       modf (frac, &frac);
530       frac *= 256.0;
531       ((unsigned char *) dst)[i] = floor (frac);
532     }
533   if (endian == LITTLE)
534     mm_reverse (dst, fp->w);
535
536   return 1;
537 }
538
539 static int
540 convert_PIBHEX (char *dst, const struct fmt_spec *fp, const union value *v)
541 {
542   /* Strategy: Use frexp() to create a normalized result (but mostly
543      to find the base-2 exponent), then change the base-2 exponent to
544      (-4*fp->w) using multiplication and division by powers of two.
545      Extract each hexit by multiplying by 16. */
546
547   /* Fraction (mantissa). */
548   double frac;
549
550   /* Exponent. */
551   int exp;
552
553   /* Difference between exponent and (-4*fp->w). */
554   int diff;
555
556   /* Counter. */
557   int i;
558
559   /* Make the exponent (-4*fp->w). */
560   frac = frexp (fabs (v->f), &exp);
561   diff = exp - (-4 * fp->w);
562   exp -= diff;
563   frac *= ldexp (1.0, diff);
564
565   /* Extract each hexit. */
566   for (i = 0; i < fp->w; i++)
567     {
568       modf (frac, &frac);
569       frac *= 16.0;
570       *dst++ = MAKE_HEXIT ((int) floor (frac));
571     }
572
573   return 1;
574 }
575
576 static int
577 convert_PK (char *dst, const struct fmt_spec *fp, const union value *v)
578 {
579   /* Buffer for v->f*2 characters + a decimal point if library is not
580      quite compliant + a null. */
581   char buf[18];
582
583   /* Counter. */
584   int i;
585
586   /* Main extraction. */
587   sprintf (buf, "%0*.0f", fp->w * 2, floor (fabs (v->f)));
588
589   for (i = 0; i < fp->w; i++)
590     ((unsigned char *) dst)[i]
591       = ((buf[i * 2] - '0') << 4) + buf[i * 2 + 1] - '0';
592
593   return 1;
594 }
595
596 static int
597 convert_RB (char *dst, const struct fmt_spec *fp, const union value *v)
598 {
599   union
600     {
601       double d;
602       char c[8];
603     }
604   u;
605
606   u.d = v->f;
607   memcpy (dst, u.c, fp->w);
608
609   return 1;
610 }
611
612 static int
613 convert_RBHEX (char *dst, const struct fmt_spec *fp, const union value *v)
614 {
615   union
616   {
617     double d;
618     char c[8];
619   }
620   u;
621
622   int i;
623
624   u.d = v->f;
625   for (i = 0; i < fp->w / 2; i++)
626     {
627       *dst++ = MAKE_HEXIT (u.c[i] >> 4);
628       *dst++ = MAKE_HEXIT (u.c[i] & 15);
629     }
630
631   return 1;
632 }
633
634 static int
635 convert_CCx (char *dst, const struct fmt_spec *fp, const union value *v)
636 {
637   if (try_CCx (dst, fp, v->f))
638     return 1;
639   else
640     {
641       struct fmt_spec f;
642       
643       f.type = FMT_COMMA;
644       f.w = fp->w;
645       f.d = fp->d;
646   
647       return convert_F (dst, &f, v);
648     }
649 }
650
651 static int
652 convert_date (char *dst, const struct fmt_spec *fp, const union value *v)
653 {
654   static const char *months[12] =
655     {
656       "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
657       "JUL", "AUG", "SEP", "OCT", "NOV", "DEC",
658     };
659
660   char buf[64] = {0};
661   int month, day, year;
662
663   julian_to_calendar (v->f / 86400., &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 = (v->f / 86400.) - calendar_to_julian (year, 1, 1) + 1;
693         
694         if (fp->w >= 7)
695           {
696             if (year4 (year))
697               sprintf (buf, "%04d%03d", year, yday);
698           }
699         else
700           sprintf (buf, "%02d%03d", year % 100, yday);
701         break;
702       }
703     case FMT_QYR:
704       if (fp->w >= 8)
705         sprintf (buf, "%d Q% 04d", (month - 1) / 3 + 1, year);
706       else
707         sprintf (buf, "%d Q% 02d", (month - 1) / 3 + 1, year % 100);
708       break;
709     case FMT_MOYR:
710       if (fp->w >= 8)
711         sprintf (buf, "%s% 04d", months[month - 1], year);
712       else
713         sprintf (buf, "%s% 02d", months[month - 1], year % 100);
714       break;
715     case FMT_WKYR:
716       {
717         int yday = (v->f / 86400.) - calendar_to_julian (year, 1, 1) + 1;
718         
719         if (fp->w >= 10)
720           sprintf (buf, "%02d WK% 04d", (yday - 1) / 7 + 1, year);
721         else
722           sprintf (buf, "%02d WK% 02d", (yday - 1) / 7 + 1, year % 100);
723       }
724       break;
725     case FMT_DATETIME:
726       {
727         char *cp;
728
729         cp = spprintf (buf, "%02d-%s-%04d %02d:%02d",
730                        day, months[month - 1], year,
731                        (int) fmod (floor (v->f / 60. / 60.), 24.),
732                        (int) fmod (floor (v->f / 60.), 60.));
733         if (fp->w >= 20)
734           {
735             int w, d;
736
737             if (fp->w >= 22 && fp->d > 0)
738               {
739                 d = min (fp->d, fp->w - 21);
740                 w = 3 + d;
741               }
742             else
743               {
744                 w = 2;
745                 d = 0;
746               }
747
748             cp = spprintf (cp, ":%0*.*f", w, d, fmod (v->f, 60.));
749           }
750       }
751       break;
752 #if __CHECKER__
753     case 42000:
754       assert (0);
755 #endif
756     default:
757       assert (0);
758     }
759
760   if (buf[0] == 0)
761     return 0;
762   st_bare_pad_copy (dst, buf, fp->w);
763   return 1;
764 }
765
766 static int
767 convert_time (char *dst, const struct fmt_spec *fp, const union value *v)
768 {
769   char temp_buf[40];
770   char *cp;
771
772   double time;
773   int width;
774
775   if (fabs (v->f) > 1e20)
776     {
777       msg (ME, _("Time value %g too large in magnitude to convert to "
778            "alphanumeric time."), v->f);
779       return 0;
780     }
781
782   time = v->f;
783   width = fp->w;
784   cp = temp_buf;
785   if (time < 0)
786     *cp++ = '-', time = -time;
787   if (fp->type == FMT_DTIME)
788     {
789       double days = floor (time / 60. / 60. / 24.);
790       cp = spprintf (temp_buf, "%02.0f ", days);
791       time = time - days * 60. * 60. * 24.;
792       width -= 3;
793     }
794   else
795     cp = temp_buf;
796
797   cp = spprintf (cp, "%02.0f:%02.0f",
798                  fmod (floor (time / 60. / 60.), 24.),
799                  fmod (floor (time / 60.), 60.));
800
801   if (width >= 8)
802     {
803       int w, d;
804
805       if (width >= 10 && fp->d >= 0 && fp->d != 0)
806         d = min (fp->d, width - 9), w = 3 + d;
807       else
808         w = 2, d = 0;
809
810       cp = spprintf (cp, ":%0*.*f", w, d, fmod (time, 60.));
811     }
812   st_bare_pad_copy (dst, temp_buf, fp->w);
813
814   return 1;
815 }
816
817 static int
818 convert_WKDAY (char *dst, const struct fmt_spec *fp, const union value *v)
819 {
820   static const char *weekdays[7] =
821     {
822       "SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY",
823       "THURSDAY", "FRIDAY", "SATURDAY",
824     };
825
826   int x = v->f;
827
828   if (x < 1 || x > 7)
829     {
830       msg (ME, _("Weekday index %d does not lie between 1 and 7."), x);
831       return 0;
832     }
833   st_bare_pad_copy (dst, weekdays[x - 1], fp->w);
834
835   return 1;
836 }
837
838 static int
839 convert_MONTH (char *dst, const struct fmt_spec *fp, const union value *v)
840 {
841   static const char *months[12] =
842     {
843       "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
844       "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER",
845     };
846
847   int x = v->f;
848
849   if (x < 1 || x > 12)
850     {
851       msg (ME, _("Month index %d does not lie between 1 and 12."), x);
852       return 0;
853     }
854   
855   st_bare_pad_copy (dst, months[x - 1], fp->w);
856
857   return 1;
858 }
859 \f
860 /* Helper functions. */
861
862 /* Copies SRC to DST, inserting commas and dollar signs as appropriate
863    for format spec *FP.  */
864 static void
865 insert_commas (char *dst, const char *src, const struct fmt_spec *fp)
866 {
867   /* Number of leading spaces in the number.  This is the amount of
868      room we have for inserting commas and dollar signs. */
869   int n_spaces;
870
871   /* Number of digits before the decimal point.  This is used to
872      determine the Number of commas to insert. */
873   int n_digits;
874
875   /* Number of commas to insert. */
876   int n_commas;
877
878   /* Number of items ,%$ to insert. */
879   int n_items;
880
881   /* Number of n_items items not to use for commas. */
882   int n_reserved;
883
884   /* Digit iterator. */
885   int i;
886
887   /* Source pointer. */
888   const char *sp;
889
890   /* Count spaces and digits. */
891   sp = src;
892   while (sp < src + fp->w && *sp == ' ')
893     sp++;
894   n_spaces = sp - src;
895   sp = src + n_spaces;
896   if (*sp == '-')
897     sp++;
898   n_digits = 0;
899   while (sp + n_digits < src + fp->w && isdigit ((unsigned char) sp[n_digits]))
900     n_digits++;
901   n_commas = (n_digits - 1) / 3;
902   n_items = n_commas + (fp->type == FMT_DOLLAR || fp->type == FMT_PCT);
903
904   /* Check whether we have enough space to do insertions. */
905   if (!n_spaces || !n_items)
906     {
907       memcpy (dst, src, fp->w);
908       return;
909     }
910   if (n_items > n_spaces)
911     {
912       n_items -= n_commas;
913       if (!n_items)
914         {
915           memcpy (dst, src, fp->w);
916           return;
917         }
918     }
919
920   /* Put spaces at the beginning if there's extra room. */
921   if (n_spaces > n_items)
922     {
923       memset (dst, ' ', n_spaces - n_items);
924       dst += n_spaces - n_items;
925     }
926
927   /* Insert $ and reserve space for %. */
928   n_reserved = 0;
929   if (fp->type == FMT_DOLLAR)
930     {
931       *dst++ = '$';
932       n_items--;
933     }
934   else if (fp->type == FMT_PCT)
935     n_reserved = 1;
936
937   /* Copy negative sign and digits, inserting commas. */
938   if (sp - src > n_spaces)
939     *dst++ = '-';
940   for (i = n_digits; i; i--)
941     {
942       if (i % 3 == 0 && n_digits > i && n_items > n_reserved)
943         {
944           n_items--;
945           *dst++ = fp->type == FMT_COMMA ? set_grouping : set_decimal;
946         }
947       *dst++ = *sp++;
948     }
949
950   /* Copy decimal places and insert % if necessary. */
951   memcpy (dst, sp, fp->w - (sp - src));
952   if (fp->type == FMT_PCT && n_items > 0)
953     dst[fp->w - (sp - src)] = '%';
954 }
955
956 /* Returns 1 if YEAR (i.e., 1987) can be represented in four digits, 0
957    otherwise. */
958 static int
959 year4 (int year)
960 {
961   if (year >= 1 && year <= 9999)
962     return 1;
963   msg (ME, _("Year %d cannot be represented in four digits for "
964              "output formatting purposes."), year);
965   return 0;
966 }
967
968 static int
969 try_CCx (char *dst, const struct fmt_spec *fp, double v)
970 {
971   struct set_cust_currency *cc = &set_cc[fp->type - FMT_CCA];
972
973   struct fmt_spec f;
974
975   char buf[64];
976   char buf2[64];
977   char *cp;
978
979   /* Determine length available, decimal character for number
980      proper. */
981   f.type = cc->decimal == set_decimal ? FMT_COMMA : FMT_DOT;
982   f.w = fp->w - strlen (cc->prefix) - strlen (cc->suffix);
983   if (v < 0)
984     f.w -= strlen (cc->neg_prefix) + strlen (cc->neg_suffix) - 1;
985   else
986     /* Convert -0 to +0. */
987     v = fabs (v);
988   f.d = fp->d;
989
990   if (f.w <= 0)
991     return 0;
992
993   /* There's room for all that currency crap.  Let's do the F
994      conversion first. */
995   if (!convert_F (buf, &f, (union value *) &v) || *buf == '*')
996     return 0;
997   insert_commas (buf2, buf, &f);
998
999   /* Postprocess back into buf. */
1000   cp = buf;
1001   if (v < 0)
1002     cp = stpcpy (cp, cc->neg_prefix);
1003   cp = stpcpy (cp, cc->prefix);
1004   {
1005     char *bp = buf2;
1006     while (*bp == ' ')
1007       bp++;
1008
1009     assert ((v >= 0) ^ (*bp == '-'));
1010     if (v < 0)
1011       bp++;
1012
1013     memcpy (cp, bp, f.w - (bp - buf2));
1014     cp += f.w - (bp - buf2);
1015   }
1016   cp = stpcpy (cp, cc->suffix);
1017   if (v < 0)
1018     cp = stpcpy (cp, cc->neg_suffix);
1019
1020   /* Copy into dst. */
1021   assert (cp - buf <= fp->w);
1022   if (cp - buf < fp->w)
1023     {
1024       memcpy (&dst[fp->w - (cp - buf)], buf, cp - buf);
1025       memset (dst, ' ', fp->w - (cp - buf));
1026     }
1027   else
1028     memcpy (dst, buf, fp->w);
1029
1030   return 1;
1031 }
1032
1033 /* This routine relies on the underlying implementation of sprintf:
1034
1035    If the number has a magnitude 1e40 or greater, then we needn't
1036    bother with it, since it's guaranteed to need processing in
1037    scientific notation.
1038
1039    Otherwise, do a binary search for the base-10 magnitude of the
1040    thing.  log10() is not accurate enough, and the alternatives are
1041    frightful.  Besides, we never need as many as 6 (pairs of)
1042    comparisons.  The algorithm used for searching is Knuth's Algorithm
1043    6.2.1C (Uniform binary search).
1044
1045    DON'T CHANGE ANYTHING HERE UNLESS YOU'VE THOUGHT ABOUT IT FOR A
1046    LONG TIME!  The rest of the program is heavily dependent on
1047    specific properties of this routine's output.  LOG ALL CHANGES! */
1048 static int
1049 try_F (char *dst, const struct fmt_spec *fp, const union value *value)
1050 {
1051   /* This is the DELTA array from Knuth.
1052      DELTA[j] = floor((40+2**(j-1))/(2**j)). */
1053   static const int delta[8] =
1054   {
1055     0, (40 + 1) / 2, (40 + 2) / 4, (40 + 4) / 8, (40 + 8) / 16,
1056     (40 + 16) / 32, (40 + 32) / 64, (40 + 64) / 128,
1057   };
1058
1059   /* The number of digits in floor(v), including sign.  This is `i'
1060      from Knuth. */
1061   int n_int = (40 + 1) / 2;
1062
1063   /* Used to step through delta[].  This is `j' from Knuth. */
1064   int j = 2;
1065
1066   /* Value. */
1067   double v = value->f;
1068
1069   /* Magnitude of v.  This is `K' from Knuth. */
1070   double mag;
1071
1072   /* Number of characters for the fractional part, including the
1073      decimal point. */
1074   int n_dec;
1075
1076   /* Pointer into buf used for formatting. */
1077   char *cp;
1078
1079   /* Used to count characters formatted by nsprintf(). */
1080   int n;
1081
1082   /* Temporary buffer. */
1083   char buf[128];
1084
1085   /* First check for infinities and NaNs.  12/13/96. */
1086   if (!finite (v))
1087     {
1088       n = nsprintf (buf, "%f", v);
1089       if (n > fp->w)
1090         memset (buf, '*', fp->w);
1091       else if (n < fp->w)
1092         {
1093           memmove (&buf[fp->w - n], buf, n);
1094           memset (buf, ' ', fp->w - n);
1095         }
1096       memcpy (dst, buf, fp->w);
1097       return 1;
1098     }
1099
1100   /* Then check for radically out-of-range values. */
1101   mag = fabs (v);
1102   if (mag >= power10[fp->w])
1103     return 0;
1104
1105   if (mag < 1.0)
1106     {
1107       n_int = 0;
1108
1109       /* Avoid printing `-.000'. 7/6/96. */
1110       if (approx_eq (v, 0.0))
1111         v = 0.0;
1112     }
1113   else
1114     /* Now perform a `uniform binary search' based on the tables
1115        power10[] and delta[].  After this step, nint is the number of
1116        digits in floor(v), including any sign.  */
1117     for (;;)
1118       {
1119         if (mag >= power10[n_int])      /* Should this be approx_ge()? */
1120           {
1121             assert (delta[j]);
1122             n_int += delta[j++];
1123           }
1124         else if (mag < power10[n_int - 1])
1125           {
1126             assert (delta[j]);
1127             n_int -= delta[j++];
1128           }
1129         else
1130           break;
1131       }
1132
1133   /* If we have any decimal places, then there is a decimal point,
1134      too. */
1135   n_dec = fp->d;
1136   if (n_dec)
1137     n_dec++;
1138
1139   /* 1/10/96: If there aren't any digits at all, add one.  This occurs
1140      only when fabs(v) < 1.0. */
1141   if (n_int + n_dec == 0)
1142     n_int++;
1143
1144   /* Give space for a minus sign.  Moved 1/10/96. */
1145   if (v < 0)
1146     n_int++;
1147
1148   /* Normally we only go through the loop once; occasionally twice.
1149      Three times or more indicates a very serious bug somewhere. */
1150   for (;;)
1151     {
1152       /* Check out the total length of the string. */
1153       cp = buf;
1154       if (n_int + n_dec > fp->w)
1155         {
1156           /* The string is too long.  Let's see what can be done. */
1157           if (n_int <= fp->w)
1158             /* If we can, just reduce the number of decimal places. */
1159             n_dec = fp->w - n_int;
1160           else
1161             return 0;
1162         }
1163       else if (n_int + n_dec < fp->w)
1164         {
1165           /* The string is too short.  Left-pad with spaces. */
1166           int n_spaces = fp->w - n_int - n_dec;
1167           memset (cp, ' ', n_spaces);
1168           cp += n_spaces;
1169         }
1170
1171       /* Finally, format the number. */
1172       if (n_dec)
1173         n = nsprintf (cp, "%.*f", n_dec - 1, v);
1174       else
1175         n = nsprintf (cp, "%.0f", v);
1176
1177       /* If v is positive and its magnitude is less than 1...  */
1178       if (n_int == 0)
1179         {
1180           if (*cp == '0')
1181             {
1182               /* The value rounds to `.###'. */
1183               memmove (cp, &cp[1], n - 1);
1184               n--;
1185             }
1186           else
1187             {
1188               /* The value rounds to `1.###'. */
1189               n_int = 1;
1190               continue;
1191             }
1192         }
1193       /* Else if v is negative and its magnitude is less than 1...  */
1194       else if (v < 0 && n_int == 1)
1195         {
1196           if (cp[1] == '0')
1197             {
1198               /* The value rounds to `-.###'. */
1199               memmove (&cp[1], &cp[2], n - 2);
1200               n--;
1201             }
1202           else
1203             {
1204               /* The value rounds to `-1.###'. */
1205               n_int = 2;
1206               continue;
1207             }
1208         }
1209
1210       /* Check for a correct number of digits & decimal places & stuff.
1211          This is just a desperation check.  Hopefully it won't fail too
1212          often, because then we have to run through the whole loop again:
1213          sprintf() is not a fast operation with floating-points! */
1214       if (n == n_int + n_dec)
1215         {
1216           /* Convert periods `.' to commas `,' for our foreign friends. */
1217           if ((set_decimal == ',' && fp->type != FMT_DOT)
1218               || (set_decimal == '.' && fp->type == FMT_DOT))
1219             {
1220               cp = strchr (cp, '.');
1221               if (cp)
1222                 *cp = ',';
1223             }
1224
1225           memcpy (dst, buf, fp->w);
1226           return 1;
1227         }
1228
1229       n_int = n - n_dec; /* FIXME?  Need an idiot check on resulting n_int? */
1230     }
1231 }