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