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