Adopt use of gnulib for portability.
[pspp-builds.git] / src / pfm-read.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    Code for parsing floating-point numbers adapted from GNU C
5    library.
6
7    This program is free software; you can redistribute it and/or
8    modify it under the terms of the GNU General Public License as
9    published by the Free Software Foundation; either version 2 of the
10    License, or (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20    02110-1301, USA. */
21
22 #include <config.h>
23 #include "pfm-read.h"
24 #include "error.h"
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <ctype.h>
29 #include <errno.h>
30 #include <math.h>
31 #include <setjmp.h>
32 #include "alloc.h"
33 #include <stdbool.h>
34 #include "case.h"
35 #include "dictionary.h"
36 #include "file-handle.h"
37 #include "format.h"
38 #include "getl.h"
39 #include "hash.h"
40 #include "magic.h"
41 #include "misc.h"
42 #include "pool.h"
43 #include "str.h"
44 #include "value-labels.h"
45 #include "var.h"
46
47 #include "gettext.h"
48 #define _(msgid) gettext (msgid)
49
50 #include "debug-print.h"
51
52 /* Portable file reader. */
53 struct pfm_reader
54   {
55     struct pool *pool;          /* All the portable file state. */
56
57     jmp_buf bail_out;           /* longjmp() target for error handling. */
58
59     struct file_handle *fh;     /* File handle. */
60     FILE *file;                 /* File stream. */
61     char cc;                    /* Current character. */
62     unsigned char *trans;       /* 256-byte character set translation table. */
63
64     int var_cnt;                /* Number of variables. */
65     int weight_index;           /* 0-based index of weight variable, or -1. */
66     int *widths;                /* Variable widths, 0 for numeric. */
67     int value_cnt;              /* Number of `value's per case. */
68   };
69
70 static void
71 error (struct pfm_reader *r, const char *msg,...)
72      PRINTF_FORMAT (2, 3);
73
74 /* Displays MSG as an error message and aborts reading the
75    portable file via longjmp(). */
76 static void
77 error (struct pfm_reader *r, const char *msg, ...)
78 {
79   struct error e;
80   const char *filename;
81   char *title;
82   va_list args;
83
84   e.class = ME;
85   getl_location (&e.where.filename, &e.where.line_number);
86   filename = handle_get_filename (r->fh);
87   e.title = title = pool_alloc (r->pool, strlen (filename) + 80);
88   sprintf (title, _("portable file %s corrupt at offset %ld: "),
89            filename, ftell (r->file));
90
91   va_start (args, msg);
92   err_vmsg (&e, msg, args);
93   va_end (args);
94
95   longjmp (r->bail_out, 1);
96 }
97
98 /* Closes portable file reader R, after we're done with it. */
99 void
100 pfm_close_reader (struct pfm_reader *r)
101 {
102   if (r != NULL)
103     pool_destroy (r->pool);
104 }
105
106 /* Read a single character into cur_char.  */
107 static void
108 advance (struct pfm_reader *r)
109 {
110   int c;
111
112   while ((c = getc (r->file)) == '\r' || c == '\n')
113     continue;
114   if (c == EOF)
115     error (r, _("unexpected end of file")); 
116
117   if (r->trans != NULL)
118     c = r->trans[c]; 
119   r->cc = c;
120 }
121
122 /* Skip a single character if present, and return whether it was
123    skipped. */
124 static inline bool
125 match (struct pfm_reader *r, int c)
126 {
127   if (r->cc == c)
128     {
129       advance (r);
130       return true;
131     }
132   else
133     return false;
134 }
135
136 static void read_header (struct pfm_reader *);
137 static void read_version_data (struct pfm_reader *, struct pfm_read_info *);
138 static void read_variables (struct pfm_reader *, struct dictionary *);
139 static void read_value_label (struct pfm_reader *, struct dictionary *);
140 void dump_dictionary (struct dictionary *);
141
142 /* Reads the dictionary from file with handle H, and returns it in a
143    dictionary structure.  This dictionary may be modified in order to
144    rename, reorder, and delete variables, etc. */
145 struct pfm_reader *
146 pfm_open_reader (struct file_handle *fh, struct dictionary **dict,
147                  struct pfm_read_info *info)
148 {
149   struct pool *volatile pool = NULL;
150   struct pfm_reader *volatile r = NULL;
151
152   *dict = dict_create ();
153   if (!fh_open (fh, "portable file", "rs"))
154     goto error;
155
156   /* Create and initialize reader. */
157   pool = pool_create ();
158   r = pool_alloc (pool, sizeof *r);
159   r->pool = pool;
160   if (setjmp (r->bail_out))
161     goto error;
162   r->fh = fh;
163   r->file = pool_fopen (r->pool, handle_get_filename (r->fh), "rb");
164   r->weight_index = -1;
165   r->trans = NULL;
166   r->var_cnt = 0;
167   r->widths = NULL;
168   r->value_cnt = 0;
169
170   /* Check that file open succeeded, prime reading. */
171   if (r->file == NULL)
172     {
173       msg (ME, _("An error occurred while opening \"%s\" for reading "
174                  "as a portable file: %s."),
175            handle_get_filename (r->fh), strerror (errno));
176       err_cond_fail ();
177       goto error;
178     }
179   
180   /* Read header, version, date info, product id, variables. */
181   read_header (r);
182   read_version_data (r, info);
183   read_variables (r, *dict);
184
185   /* Read value labels. */
186   while (match (r, 'D'))
187     read_value_label (r, *dict);
188
189   /* Check that we've made it to the data. */
190   if (!match (r, 'F'))
191     error (r, _("Data record expected."));
192
193   return r;
194
195  error:
196   pfm_close_reader (r);
197   dict_destroy (*dict);
198   *dict = NULL;
199   return NULL;
200 }
201 \f
202 /* Returns the value of base-30 digit C,
203    or -1 if C is not a base-30 digit. */
204 static int
205 base_30_value (unsigned char c) 
206 {
207   static const char base_30_digits[] = "0123456789ABCDEFGHIJKLMNOPQRST";
208   const char *p = strchr (base_30_digits, c);
209   return p != NULL ? p - base_30_digits : -1;
210 }
211
212 /* Read a floating point value and return its value. */
213 static double
214 read_float (struct pfm_reader *r)
215 {
216   double num = 0.;
217   int exponent = 0;
218   bool got_dot = false;         /* Seen a decimal point? */
219   bool got_digit = false;       /* Seen any digits? */
220   bool negative = false;        /* Number is negative? */
221
222   /* Skip leading spaces. */
223   while (match (r, ' '))
224     continue;
225
226   /* `*' indicates system-missing. */
227   if (match (r, '*'))
228     {
229       advance (r);      /* Probably a dot (.) but doesn't appear to matter. */
230       return SYSMIS;
231     }
232
233   negative = match (r, '-');
234   for (;;)
235     {
236       int digit = base_30_value (r->cc);
237       if (digit != -1)
238         {
239           got_digit = true;
240
241           /* Make sure that multiplication by 30 will not overflow.  */
242           if (num > DBL_MAX * (1. / 30.))
243             /* The value of the digit doesn't matter, since we have already
244                gotten as many digits as can be represented in a `double'.
245                This doesn't necessarily mean the result will overflow.
246                The exponent may reduce it to within range.
247
248                We just need to record that there was another
249                digit so that we can multiply by 10 later.  */
250             ++exponent;
251           else
252             num = (num * 30.0) + digit;
253
254           /* Keep track of the number of digits after the decimal point.
255              If we just divided by 30 here, we would lose precision.  */
256           if (got_dot)
257             --exponent;
258         }
259       else if (!got_dot && r->cc == '.')
260         /* Record that we have found the decimal point.  */
261         got_dot = 1;
262       else
263         /* Any other character terminates the number.  */
264         break;
265
266       advance (r);
267     }
268
269   /* Check that we had some digits. */
270   if (!got_digit)
271     error (r, "Number expected.");
272
273   /* Get exponent if any. */
274   if (r->cc == '+' || r->cc == '-')
275     {
276       long int exp = 0;
277       bool negative_exponent = r->cc == '-';
278       int digit;
279
280       for (advance (r); (digit = base_30_value (r->cc)) != -1; advance (r))
281         {
282           if (exp > LONG_MAX / 30)
283             {
284               exp = LONG_MAX;
285               break;
286             }
287           exp = exp * 30 + digit;
288         }
289
290       /* We don't check whether there were actually any digits, but we
291          probably should. */
292       if (negative_exponent)
293         exp = -exp;
294       exponent += exp;
295     }
296
297   /* Numbers must end with `/'. */
298   if (!match (r, '/'))
299     error (r, _("Missing numeric terminator."));
300
301   /* Multiply `num' by 30 to the `exponent' power, checking for
302      overflow.  */
303   if (exponent < 0)
304     num *= pow (30.0, (double) exponent);
305   else if (exponent > 0)
306     {
307       if (num > DBL_MAX * pow (30.0, (double) -exponent))
308         num = DBL_MAX;
309       else
310         num *= pow (30.0, (double) exponent);
311     }
312
313   return negative ? -num : num;
314 }
315   
316 /* Read an integer and return its value. */
317 static int
318 read_int (struct pfm_reader *r)
319 {
320   double f = read_float (r);
321   if (floor (f) != f || f >= INT_MAX || f <= INT_MIN)
322     error (r, _("Invalid integer."));
323   return f;
324 }
325
326 /* Reads a string into BUF, which must have room for 256
327    characters. */
328 static void
329 read_string (struct pfm_reader *r, char *buf)
330 {
331   int n = read_int (r);
332   if (n < 0 || n > 255)
333     error (r, _("Bad string length %d."), n);
334   
335   while (n-- > 0)
336     {
337       *buf++ = r->cc;
338       advance (r);
339     }
340   *buf = '\0';
341 }
342
343 /* Reads a string and returns a copy of it allocated from R's
344    pool. */
345 static unsigned char *
346 read_pool_string (struct pfm_reader *r) 
347 {
348   char string[256];
349   read_string (r, string);
350   return pool_strdup (r->pool, string);
351 }
352 \f
353 /* Reads the 464-byte file header. */
354 static void
355 read_header (struct pfm_reader *r)
356 {
357   /* portable_to_local[PORTABLE] translates the given portable
358      character into the local character set. */
359   static const unsigned char portable_to_local[256] =
360     {
361       "                                                                "
362       "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ."
363       "<(+|&[]!$*);^-/|,%_>?`:$@'=\"      ~-   0123456789   -() {}\\     "
364       "                                                                "
365     };
366
367   unsigned char *trans;
368   int i;
369
370   /* Read and ignore vanity splash strings. */
371   for (i = 0; i < 200; i++)
372     advance (r);
373   
374   /* Skip the first 64 characters of the translation table.
375      We don't care about these.  They are probably all set to
376      '0', marking them as untranslatable, and that would screw
377      up our actual translation of the real '0'. */
378   for (i = 0; i < 64; i++)
379     advance (r);
380
381   /* Read the rest of the translation table. */
382   trans = pool_malloc (r->pool, 256);
383   memset (trans, 0, 256);
384   for (; i < 256; i++) 
385     {
386       unsigned char c;
387
388       advance (r);
389
390       c = r->cc;
391       if (trans[c] == 0)
392         trans[c] = portable_to_local[i];
393     }
394
395   /* Set up the translation table, then read the first
396      translated character. */
397   r->trans = trans;
398   advance (r); 
399
400   /* Skip and verify signature. */
401   for (i = 0; i < 8; i++) 
402     if (!match (r, "SPSSPORT"[i])) 
403       {
404         msg (SE, _("%s: Not a portable file."), handle_get_filename (r->fh));
405         longjmp (r->bail_out, 1);
406       }
407 }
408
409 /* Reads the version and date info record, as well as product and
410    subproduct identification records if present. */
411 static void
412 read_version_data (struct pfm_reader *r, struct pfm_read_info *info)
413 {
414   char *date, *time, *product, *author, *subproduct;
415   int i;
416
417   /* Read file. */
418   if (!match (r, 'A'))
419     error (r, "Unrecognized version code `%c'.", r->cc);
420   date = read_pool_string (r);
421   time = read_pool_string (r);
422   product = match (r, '1') ? read_pool_string (r) : (unsigned char *) "";
423   author = match (r, '2') ? read_pool_string (r) : (unsigned char *) "";
424   subproduct
425     = match (r, '3') ? read_pool_string (r) : (unsigned char *) "";
426
427   /* Validate file. */
428   if (strlen (date) != 8)
429     error (r, _("Bad date string length %d."), strlen (date));
430   if (strlen (time) != 6)
431     error (r, _("Bad time string length %d."), strlen (time));
432
433   /* Save file info. */
434   if (info != NULL) 
435     {
436       /* Date. */
437       for (i = 0; i < 8; i++) 
438         {
439           static const int map[] = {6, 7, 8, 9, 3, 4, 0, 1};
440           info->creation_date[map[i]] = date[i]; 
441         }
442       info->creation_date[2] = info->creation_date[5] = ' ';
443       info->creation_date[10] = 0;
444
445       /* Time. */
446       for (i = 0; i < 6; i++)
447         {
448           static const int map[] = {0, 1, 3, 4, 6, 7};
449           info->creation_time[map[i]] = time[i];
450         }
451       info->creation_time[2] = info->creation_time[5] = ' ';
452       info->creation_time[8] = 0;
453
454       /* Product. */
455       str_copy_trunc (info->product, sizeof info->product, product);
456       str_copy_trunc (info->subproduct, sizeof info->subproduct, subproduct);
457     }
458 }
459
460 /* Translates a format specification read from portable file R as
461    the three integers INTS into a normal format specifier FORMAT,
462    checking that the format is appropriate for variable V. */
463 static void
464 convert_format (struct pfm_reader *r, const int portable_format[3],
465                 struct fmt_spec *format, struct variable *v)
466 {
467   format->type = translate_fmt (portable_format[0]);
468   if (format->type == -1)
469     error (r, _("%s: Bad format specifier byte (%d)."),
470            v->name, portable_format[0]);
471   format->w = portable_format[1];
472   format->d = portable_format[2];
473
474   if (!check_output_specifier (format, false)
475       || !check_specifier_width (format, v->width, false))
476     error (r, _("%s variable %s has invalid format specifier %s."),
477            v->type == NUMERIC ? _("Numeric") : _("String"),
478            v->name, fmt_to_string (format));
479 }
480
481 static union value parse_value (struct pfm_reader *, struct variable *);
482
483 /* Read information on all the variables.  */
484 static void
485 read_variables (struct pfm_reader *r, struct dictionary *dict)
486 {
487   char *weight_name = NULL;
488   int i;
489   
490   if (!match (r, '4'))
491     error (r, _("Expected variable count record."));
492   
493   r->var_cnt = read_int (r);
494   if (r->var_cnt <= 0 || r->var_cnt == NOT_INT)
495     error (r, _("Invalid number of variables %d."), r->var_cnt);
496   r->widths = pool_alloc (r->pool, sizeof *r->widths * r->var_cnt);
497
498   /* Purpose of this value is unknown.  It is typically 161. */
499   read_int (r);
500
501   if (match (r, '6'))
502     {
503       weight_name = read_pool_string (r);
504       if (strlen (weight_name) > SHORT_NAME_LEN) 
505         error (r, _("Weight variable name (%s) truncated."), weight_name);
506     }
507   
508   for (i = 0; i < r->var_cnt; i++)
509     {
510       int width;
511       char name[256];
512       int fmt[6];
513       struct variable *v;
514       int j;
515
516       if (!match (r, '7'))
517         error (r, _("Expected variable record."));
518
519       width = read_int (r);
520       if (width < 0)
521         error (r, _("Invalid variable width %d."), width);
522       r->widths[i] = width;
523
524       read_string (r, name);
525       for (j = 0; j < 6; j++)
526         fmt[j] = read_int (r);
527
528       if (!var_is_valid_name (name, false) || *name == '#' || *name == '$')
529         error (r, _("position %d: Invalid variable name `%s'."), i, name);
530       str_uppercase (name);
531
532       if (width < 0 || width > 255)
533         error (r, "Bad width %d for variable %s.", width, name);
534
535       v = dict_create_var (dict, name, width);
536       if (v == NULL)
537         error (r, _("Duplicate variable name %s."), name);
538
539       convert_format (r, &fmt[0], &v->print, v);
540       convert_format (r, &fmt[3], &v->write, v);
541
542       /* Range missing values. */
543       if (match (r, 'B'))
544         {
545           v->miss_type = MISSING_RANGE;
546           v->missing[0] = parse_value (r, v);
547           v->missing[1] = parse_value (r, v);
548         }
549       else if (match (r, 'A'))
550         {
551           v->miss_type = MISSING_HIGH;
552           v->missing[0] = parse_value (r, v);
553         }
554       else if (match (r, '9'))
555         {
556           v->miss_type = MISSING_LOW;
557           v->missing[0] = parse_value (r, v);
558         }
559
560       /* Single missing values. */
561       while (match (r, '8'))
562         {
563           static const int map_next[MISSING_COUNT] =
564             {
565               MISSING_1, MISSING_2, MISSING_3, -1,
566               MISSING_RANGE_1, MISSING_LOW_1, MISSING_HIGH_1,
567               -1, -1, -1,
568             };
569
570           static const int map_ofs[MISSING_COUNT] = 
571             {
572               -1, 0, 1, 2, -1, -1, -1, 2, 1, 1,
573             };
574
575           v->miss_type = map_next[v->miss_type];
576           if (v->miss_type == -1)
577             error (r, _("Bad missing values for %s."), v->name);
578           
579           assert (map_ofs[v->miss_type] != -1);
580           v->missing[map_ofs[v->miss_type]] = parse_value (r, v);
581         }
582
583       if (match (r, 'C')) 
584         {
585           char label[256];
586           read_string (r, label);
587           v->label = xstrdup (label); 
588         }
589     }
590
591   if (weight_name != NULL) 
592     {
593       struct variable *weight_var = dict_lookup_var (dict, weight_name);
594       if (weight_var == NULL)
595         error (r, _("Weighting variable %s not present in dictionary."),
596                weight_name);
597
598       dict_set_weight (dict, weight_var);
599     }
600 }
601
602 /* Parse a value for variable VV into value V. */
603 static union value
604 parse_value (struct pfm_reader *r, struct variable *vv)
605 {
606   union value v;
607   
608   if (vv->type == ALPHA) 
609     {
610       char string[256];
611       read_string (r, string);
612       buf_copy_str_rpad (v.s, 8, string); 
613     }
614   else
615     v.f = read_float (r);
616
617   return v;
618 }
619
620 /* Parse a value label record and return success. */
621 static void
622 read_value_label (struct pfm_reader *r, struct dictionary *dict)
623 {
624   /* Variables. */
625   int nv;
626   struct variable **v;
627
628   /* Labels. */
629   int n_labels;
630
631   int i;
632
633   nv = read_int (r);
634   v = pool_alloc (r->pool, sizeof *v * nv);
635   for (i = 0; i < nv; i++)
636     {
637       char name[256];
638       read_string (r, name);
639
640       v[i] = dict_lookup_var (dict, name);
641       if (v[i] == NULL)
642         error (r, _("Unknown variable %s while parsing value labels."), name);
643
644       if (v[0]->width != v[i]->width)
645         error (r, _("Cannot assign value labels to %s and %s, which "
646                     "have different variable types or widths."),
647                v[0]->name, v[i]->name);
648     }
649
650   n_labels = read_int (r);
651   for (i = 0; i < n_labels; i++)
652     {
653       union value val;
654       char label[256];
655       int j;
656
657       val = parse_value (r, v[0]);
658       read_string (r, label);
659
660       /* Assign the value_label's to each variable. */
661       for (j = 0; j < nv; j++)
662         {
663           struct variable *var = v[j];
664
665           if (!val_labs_replace (var->val_labs, val, label))
666             continue;
667
668           if (var->type == NUMERIC)
669             error (r, _("Duplicate label for value %g for variable %s."),
670                    val.f, var->name);
671           else
672             error (r, _("Duplicate label for value `%.*s' for variable %s."),
673                    var->width, val.s, var->name);
674         }
675     }
676 }
677
678 /* Reads one case from portable file R into C. */
679 bool
680 pfm_read_case (struct pfm_reader *r, struct ccase *c)
681 {
682   size_t i;
683   size_t idx;
684
685   if (setjmp (r->bail_out)) 
686     return false;
687   
688   /* Check for end of file. */
689   if (r->cc == 'Z')
690     return false;
691
692   idx = 0;
693   for (i = 0; i < r->var_cnt; i++) 
694     {
695       int width = r->widths[i];
696       
697       if (width == 0)
698         {
699           case_data_rw (c, idx)->f = read_float (r);
700           idx++;
701         }
702       else
703         {
704           char string[256];
705           read_string (r, string);
706           buf_copy_str_rpad (case_data_rw (c, idx)->s, width, string);
707           idx += DIV_RND_UP (width, MAX_SHORT_STRING);
708         }
709     }
710   
711   return true;
712 }