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