4d95eba22ae3a05b7ff716c3d7dfb96c9fcb2025
[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 "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 (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       {
401         msg (SE, _("%s: Not a portable file."), handle_get_filename (r->fh));
402         longjmp (r->bail_out, 1);
403       }
404 }
405
406 /* Reads the version and date info record, as well as product and
407    subproduct identification records if present. */
408 static void
409 read_version_data (struct pfm_reader *r, struct pfm_read_info *info)
410 {
411   char *date, *time, *product, *author, *subproduct;
412   int i;
413
414   /* Read file. */
415   if (!match (r, 'A'))
416     error (r, "Unrecognized version code `%c'.", r->cc);
417   date = read_pool_string (r);
418   time = read_pool_string (r);
419   product = match (r, '1') ? read_pool_string (r) : (unsigned char *) "";
420   author = match (r, '2') ? read_pool_string (r) : (unsigned char *) "";
421   subproduct
422     = match (r, '3') ? read_pool_string (r) : (unsigned char *) "";
423
424   /* Validate file. */
425   if (strlen (date) != 8)
426     error (r, _("Bad date string length %d."), strlen (date));
427   if (strlen (time) != 6)
428     error (r, _("Bad time string length %d."), strlen (time));
429
430   /* Save file info. */
431   if (info != NULL) 
432     {
433       /* Date. */
434       for (i = 0; i < 8; i++) 
435         {
436           static const int map[] = {6, 7, 8, 9, 3, 4, 0, 1};
437           info->creation_date[map[i]] = date[i]; 
438         }
439       info->creation_date[2] = info->creation_date[5] = ' ';
440       info->creation_date[10] = 0;
441
442       /* Time. */
443       for (i = 0; i < 6; i++)
444         {
445           static const int map[] = {0, 1, 3, 4, 6, 7};
446           info->creation_time[map[i]] = time[i];
447         }
448       info->creation_time[2] = info->creation_time[5] = ' ';
449       info->creation_time[8] = 0;
450
451       /* Product. */
452       str_copy_trunc (info->product, sizeof info->product, product);
453       str_copy_trunc (info->subproduct, sizeof info->subproduct, subproduct);
454     }
455 }
456
457 /* Translates a format specification read from portable file R as
458    the three integers INTS into a normal format specifier FORMAT,
459    checking that the format is appropriate for variable V. */
460 static void
461 convert_format (struct pfm_reader *r, const int portable_format[3],
462                 struct fmt_spec *format, struct variable *v)
463 {
464   format->type = translate_fmt (portable_format[0]);
465   if (format->type == -1)
466     error (r, _("%s: Bad format specifier byte (%d)."),
467            v->name, portable_format[0]);
468   format->w = portable_format[1];
469   format->d = portable_format[2];
470
471   if (!check_output_specifier (format, false)
472       || !check_specifier_width (format, v->width, false))
473     error (r, _("%s variable %s has invalid format specifier %s."),
474            v->type == NUMERIC ? _("Numeric") : _("String"),
475            v->name, fmt_to_string (format));
476 }
477
478 static union value parse_value (struct pfm_reader *, struct variable *);
479
480 /* Read information on all the variables.  */
481 static void
482 read_variables (struct pfm_reader *r, struct dictionary *dict)
483 {
484   char *weight_name = NULL;
485   int i;
486   
487   if (!match (r, '4'))
488     error (r, _("Expected variable count record."));
489   
490   r->var_cnt = read_int (r);
491   if (r->var_cnt <= 0 || r->var_cnt == NOT_INT)
492     error (r, _("Invalid number of variables %d."), r->var_cnt);
493   r->widths = pool_alloc (r->pool, sizeof *r->widths * r->var_cnt);
494
495   /* Purpose of this value is unknown.  It is typically 161. */
496   read_int (r);
497
498   if (match (r, '6'))
499     {
500       weight_name = read_pool_string (r);
501       if (strlen (weight_name) > SHORT_NAME_LEN) 
502         error (r, _("Weight variable name (%s) truncated."), weight_name);
503     }
504   
505   for (i = 0; i < r->var_cnt; i++)
506     {
507       int width;
508       char name[256];
509       int fmt[6];
510       struct variable *v;
511       int j;
512
513       if (!match (r, '7'))
514         error (r, _("Expected variable record."));
515
516       width = read_int (r);
517       if (width < 0)
518         error (r, _("Invalid variable width %d."), width);
519       r->widths[i] = width;
520
521       read_string (r, name);
522       for (j = 0; j < 6; j++)
523         fmt[j] = read_int (r);
524
525       if (!var_is_valid_name (name, false) || *name == '#' || *name == '$')
526         error (r, _("position %d: Invalid variable name `%s'."), i, name);
527       str_uppercase (name);
528
529       if (width < 0 || width > 255)
530         error (r, "Bad width %d for variable %s.", width, name);
531
532       v = dict_create_var (dict, name, width);
533       if (v == NULL)
534         error (r, _("Duplicate variable name %s."), name);
535
536       convert_format (r, &fmt[0], &v->print, v);
537       convert_format (r, &fmt[3], &v->write, v);
538
539       /* Range missing values. */
540       if (match (r, 'B'))
541         {
542           v->miss_type = MISSING_RANGE;
543           v->missing[0] = parse_value (r, v);
544           v->missing[1] = parse_value (r, v);
545         }
546       else if (match (r, 'A'))
547         {
548           v->miss_type = MISSING_HIGH;
549           v->missing[0] = parse_value (r, v);
550         }
551       else if (match (r, '9'))
552         {
553           v->miss_type = MISSING_LOW;
554           v->missing[0] = parse_value (r, v);
555         }
556
557       /* Single missing values. */
558       while (match (r, '8'))
559         {
560           static const int map_next[MISSING_COUNT] =
561             {
562               MISSING_1, MISSING_2, MISSING_3, -1,
563               MISSING_RANGE_1, MISSING_LOW_1, MISSING_HIGH_1,
564               -1, -1, -1,
565             };
566
567           static const int map_ofs[MISSING_COUNT] = 
568             {
569               -1, 0, 1, 2, -1, -1, -1, 2, 1, 1,
570             };
571
572           v->miss_type = map_next[v->miss_type];
573           if (v->miss_type == -1)
574             error (r, _("Bad missing values for %s."), v->name);
575           
576           assert (map_ofs[v->miss_type] != -1);
577           v->missing[map_ofs[v->miss_type]] = parse_value (r, v);
578         }
579
580       if (match (r, 'C')) 
581         {
582           char label[256];
583           read_string (r, label);
584           v->label = xstrdup (label); 
585         }
586     }
587
588   if (weight_name != NULL) 
589     {
590       struct variable *weight_var = dict_lookup_var (dict, weight_name);
591       if (weight_var == NULL)
592         error (r, _("Weighting variable %s not present in dictionary."),
593                weight_name);
594
595       dict_set_weight (dict, weight_var);
596     }
597 }
598
599 /* Parse a value for variable VV into value V. */
600 static union value
601 parse_value (struct pfm_reader *r, struct variable *vv)
602 {
603   union value v;
604   
605   if (vv->type == ALPHA) 
606     {
607       char string[256];
608       read_string (r, string);
609       buf_copy_str_rpad (v.s, 8, string); 
610     }
611   else
612     v.f = read_float (r);
613
614   return v;
615 }
616
617 /* Parse a value label record and return success. */
618 static void
619 read_value_label (struct pfm_reader *r, struct dictionary *dict)
620 {
621   /* Variables. */
622   int nv;
623   struct variable **v;
624
625   /* Labels. */
626   int n_labels;
627
628   int i;
629
630   nv = read_int (r);
631   v = pool_alloc (r->pool, sizeof *v * nv);
632   for (i = 0; i < nv; i++)
633     {
634       char name[256];
635       read_string (r, name);
636
637       v[i] = dict_lookup_var (dict, name);
638       if (v[i] == NULL)
639         error (r, _("Unknown variable %s while parsing value labels."), name);
640
641       if (v[0]->width != v[i]->width)
642         error (r, _("Cannot assign value labels to %s and %s, which "
643                     "have different variable types or widths."),
644                v[0]->name, v[i]->name);
645     }
646
647   n_labels = read_int (r);
648   for (i = 0; i < n_labels; i++)
649     {
650       union value val;
651       char label[256];
652       int j;
653
654       val = parse_value (r, v[0]);
655       read_string (r, label);
656
657       /* Assign the value_label's to each variable. */
658       for (j = 0; j < nv; j++)
659         {
660           struct variable *var = v[j];
661
662           if (!val_labs_replace (var->val_labs, val, label))
663             continue;
664
665           if (var->type == NUMERIC)
666             error (r, _("Duplicate label for value %g for variable %s."),
667                    val.f, var->name);
668           else
669             error (r, _("Duplicate label for value `%.*s' for variable %s."),
670                    var->width, val.s, var->name);
671         }
672     }
673 }
674
675 /* Reads one case from portable file R into C. */
676 bool
677 pfm_read_case (struct pfm_reader *r, struct ccase *c)
678 {
679   size_t i;
680   size_t idx;
681
682   if (setjmp (r->bail_out)) 
683     return false;
684   
685   /* Check for end of file. */
686   if (r->cc == 'Z')
687     return false;
688
689   idx = 0;
690   for (i = 0; i < r->var_cnt; i++) 
691     {
692       int width = r->widths[i];
693       
694       if (width == 0)
695         {
696           case_data_rw (c, idx)->f = read_float (r);
697           idx++;
698         }
699       else
700         {
701           char string[256];
702           read_string (r, string);
703           buf_copy_str_rpad (case_data_rw (c, idx)->s, width, string);
704           idx += DIV_RND_UP (width, MAX_SHORT_STRING);
705         }
706     }
707   
708   return true;
709 }