Changed all the licence notices in all the files.
[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, *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) > SHORT_NAME_LEN) 
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 #if 0 
524          /* Weirdly enough, there is no # character in the SPSS portable
525          character set, so we can't check for it. */
526       if (strlen (name) > SHORT_NAME_LEN)
527         lose ((r, _("position %d: Variable name has %u characters."),
528                i, strlen (name)));
529       if ((name[0] < 74 /* A */ || name[0] > 125 /* Z */)
530           && name[0] != 152 /* @ */)
531         lose ((r, _("position %d: Variable name begins with invalid "
532                     "character."), i));
533       if (name[0] >= 100 /* a */ && name[0] <= 125 /* z */)
534         {
535           corrupt_msg (r, _("position %d: Variable name begins with "
536                             "lowercase letter %c."),
537                        i, name[0] - 100 + 'a');
538           name[0] -= 26 /* a - A */;
539         }
540
541       /* Verify remaining characters of variable name. */
542       for (j = 1; j < (int) strlen (name); j++)
543         {
544           int c = name[j];
545 #endif
546       if (!var_is_valid_name (name, false) || *name == '#') 
547         error (r, _("position %d: Invalid variable name `%s'."), name);
548       st_uppercase (name);
549
550       if (width < 0 || width > 255)
551         error (r, "Bad width %d for variable %s.", width, name);
552
553       v = dict_create_var (dict, name, width);
554       if (v == NULL)
555         error (r, _("Duplicate variable name %s."), name);
556
557       convert_format (r, &fmt[0], &v->print, v);
558       convert_format (r, &fmt[3], &v->write, v);
559
560       /* Range missing values. */
561       if (match (r, 'B'))
562         {
563           v->miss_type = MISSING_RANGE;
564           v->missing[0] = parse_value (r, v);
565           v->missing[1] = parse_value (r, v);
566         }
567       else if (match (r, 'A'))
568         {
569           v->miss_type = MISSING_HIGH;
570           v->missing[0] = parse_value (r, v);
571         }
572       else if (match (r, '9'))
573         {
574           v->miss_type = MISSING_LOW;
575           v->missing[0] = parse_value (r, v);
576         }
577
578       /* Single missing values. */
579       while (match (r, '8'))
580         {
581           static const int map_next[MISSING_COUNT] =
582             {
583               MISSING_1, MISSING_2, MISSING_3, -1,
584               MISSING_RANGE_1, MISSING_LOW_1, MISSING_HIGH_1,
585               -1, -1, -1,
586             };
587
588           static const int map_ofs[MISSING_COUNT] = 
589             {
590               -1, 0, 1, 2, -1, -1, -1, 2, 1, 1,
591             };
592
593           v->miss_type = map_next[v->miss_type];
594           if (v->miss_type == -1)
595             error (r, _("Bad missing values for %s."), v->name);
596           
597           assert (map_ofs[v->miss_type] != -1);
598           v->missing[map_ofs[v->miss_type]] = parse_value (r, v);
599         }
600
601       if (match (r, 'C')) 
602         {
603           char label[256];
604           read_string (r, label);
605           v->label = xstrdup (label); 
606         }
607     }
608
609   if (weight_name != NULL) 
610     {
611       struct variable *weight_var = dict_lookup_var (dict, weight_name);
612       if (weight_var == NULL)
613         error (r, _("Weighting variable %s not present in dictionary."),
614                weight_name);
615
616       dict_set_weight (dict, weight_var);
617     }
618 }
619
620 /* Parse a value for variable VV into value V. */
621 static union value
622 parse_value (struct pfm_reader *r, struct variable *vv)
623 {
624   union value v;
625   
626   if (vv->type == ALPHA) 
627     {
628       char string[256];
629       read_string (r, string);
630       st_bare_pad_copy (v.s, string, 8); 
631     }
632   else
633     v.f = read_float (r);
634
635   return v;
636 }
637
638 /* Parse a value label record and return success. */
639 static void
640 read_value_label (struct pfm_reader *r, struct dictionary *dict)
641 {
642   /* Variables. */
643   int nv;
644   struct variable **v;
645
646   /* Labels. */
647   int n_labels;
648
649   int i;
650
651   nv = read_int (r);
652   v = pool_alloc (r->pool, sizeof *v * nv);
653   for (i = 0; i < nv; i++)
654     {
655       char name[256];
656       read_string (r, name);
657
658       v[i] = dict_lookup_var (dict, name);
659       if (v[i] == NULL)
660         error (r, _("Unknown variable %s while parsing value labels."), name);
661
662       if (v[0]->width != v[i]->width)
663         error (r, _("Cannot assign value labels to %s and %s, which "
664                     "have different variable types or widths."),
665                v[0]->name, v[i]->name);
666     }
667
668   n_labels = read_int (r);
669   for (i = 0; i < n_labels; i++)
670     {
671       union value val;
672       char label[256];
673       int j;
674
675       val = parse_value (r, v[0]);
676       read_string (r, label);
677
678       /* Assign the value_label's to each variable. */
679       for (j = 0; j < nv; j++)
680         {
681           struct variable *var = v[j];
682
683           if (!val_labs_replace (var->val_labs, val, label))
684             continue;
685
686           if (var->type == NUMERIC)
687             error (r, _("Duplicate label for value %g for variable %s."),
688                    val.f, var->name);
689           else
690             error (r, _("Duplicate label for value `%.*s' for variable %s."),
691                    var->width, val.s, var->name);
692         }
693     }
694 }
695
696 /* Reads one case from portable file R into C. */
697 bool
698 pfm_read_case (struct pfm_reader *r, struct ccase *c)
699 {
700   size_t i;
701   size_t idx;
702
703   if (setjmp (r->bail_out)) 
704     return false;
705   
706   /* Check for end of file. */
707   if (r->cc == 'Z')
708     return false;
709
710   idx = 0;
711   for (i = 0; i < r->var_cnt; i++) 
712     {
713       int width = r->widths[i];
714       
715       if (width == 0)
716         {
717           case_data_rw (c, idx)->f = read_float (r);
718           idx++;
719         }
720       else
721         {
722           char string[256];
723           read_string (r, string);
724           st_bare_pad_copy (case_data_rw (c, idx)->s, string, width);
725           idx += DIV_RND_UP (width, MAX_SHORT_STRING);
726         }
727     }
728   
729   return true;
730 }