Remove "Written by Ben Pfaff <blp@gnu.org>" lines everywhere.
[pspp-builds.git] / src / data / sys-file-reader.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or
5    modify it under the terms of the GNU General Public License as
6    published by the Free Software Foundation; either version 2 of the
7    License, or (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful, but
10    WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17    02110-1301, USA. */
18
19 #include <config.h>
20
21 #include "sys-file-reader.h"
22 #include "sys-file-private.h"
23
24 #include <errno.h>
25 #include <float.h>
26 #include <inttypes.h>
27 #include <setjmp.h>
28 #include <stdlib.h>
29
30 #include <libpspp/alloc.h>
31 #include <libpspp/assertion.h>
32 #include <libpspp/message.h>
33 #include <libpspp/compiler.h>
34 #include <libpspp/magic.h>
35 #include <libpspp/misc.h>
36 #include <libpspp/pool.h>
37 #include <libpspp/str.h>
38 #include <libpspp/hash.h>
39 #include <libpspp/array.h>
40
41 #include "case.h"
42 #include "dictionary.h"
43 #include "file-handle-def.h"
44 #include "file-name.h"
45 #include "format.h"
46 #include "missing-values.h"
47 #include "value-labels.h"
48 #include "variable.h"
49 #include "value.h"
50
51 #include "c-ctype.h"
52 #include "inttostr.h"
53 #include "minmax.h"
54 #include "unlocked-io.h"
55 #include "xsize.h"
56
57 #include "gettext.h"
58 #define _(msgid) gettext (msgid)
59 #define N_(msgid) (msgid)
60
61 /* System file reader. */
62 struct sfm_reader
63   {
64     /* Resource tracking. */
65     struct pool *pool;          /* All system file state. */
66     jmp_buf bail_out;           /* longjmp() target for error handling. */
67
68     /* File state. */
69     struct file_handle *fh;     /* File handle. */
70     FILE *file;                 /* File stream. */
71     bool error;                 /* I/O or corruption error? */
72
73     /* File format. */
74     enum integer_format integer_format; /* On-disk integer format. */
75     enum float_format float_format; /* On-disk floating point format. */
76     int value_cnt;              /* Number of 8-byte units per case. */
77     struct sfm_var *vars;       /* Variables. */
78     size_t var_cnt;             /* Number of variables. */
79     bool has_vls;               /* File has one or more very long strings? */
80
81     /* Decompression. */
82     bool compressed;            /* File is compressed? */
83     double bias;                /* Compression bias, usually 100.0. */
84     uint8_t opcodes[8];         /* Current block of opcodes. */
85     size_t opcode_idx;          /* Next opcode to interpret, 8 if none left. */
86   };
87
88 /* A variable in a system file. */
89 struct sfm_var 
90   {
91     int width;                  /* 0=numeric, otherwise string width. */
92     int case_index;             /* Index into case. */
93   };
94
95 static struct variable **make_var_by_value_idx (struct sfm_reader *,
96                                                 struct dictionary *);
97 static struct variable *lookup_var_by_value_idx (struct sfm_reader *,
98                                                  struct variable **,
99                                                  int value_idx);
100
101 static void sys_warn (struct sfm_reader *, const char *, ...)
102      PRINTF_FORMAT (2, 3);
103
104 static void sys_error (struct sfm_reader *, const char *, ...)
105      PRINTF_FORMAT (2, 3)
106      NO_RETURN;
107
108 static void read_bytes (struct sfm_reader *, void *, size_t);
109 static bool try_read_bytes (struct sfm_reader *, void *, size_t);
110 static int32_t read_int32 (struct sfm_reader *);
111 static double read_flt64 (struct sfm_reader *);
112 static void read_string (struct sfm_reader *, char *, size_t);
113 static void skip_bytes (struct sfm_reader *, size_t);
114
115 static int32_t int32_to_native (const struct sfm_reader *, const uint8_t[4]);
116 static double flt64_to_double (const struct sfm_reader *, const uint8_t[8]);
117
118 static struct variable_to_value_map *open_variable_to_value_map (
119   struct sfm_reader *, size_t size);
120 static void close_variable_to_value_map (struct sfm_reader *r,
121                                          struct variable_to_value_map *);
122 static bool read_variable_to_value_map (struct sfm_reader *,
123                                         struct dictionary *,
124                                         struct variable_to_value_map *,
125                                         struct variable **var, char **value,
126                                         int *warning_cnt);
127 \f
128 /* Dictionary reader. */
129
130 enum which_format 
131   {
132     PRINT_FORMAT,
133     WRITE_FORMAT
134   };
135
136 static void read_header (struct sfm_reader *, struct dictionary *,
137                          int *weight_idx, int *claimed_value_cnt,
138                          struct sfm_read_info *);
139 static void read_variable_record (struct sfm_reader *, struct dictionary *,
140                                   int *format_warning_cnt);
141 static void parse_format_spec (struct sfm_reader *, uint32_t,
142                                enum which_format, struct variable *,
143                                int *format_warning_cnt);
144 static void setup_weight (struct sfm_reader *, int weight_idx,
145                           struct variable **var_by_value_idx,
146                           struct dictionary *);
147 static void read_documents (struct sfm_reader *, struct dictionary *);
148 static void read_value_labels (struct sfm_reader *, struct dictionary *,
149                                struct variable **var_by_value_idx);
150
151 static void read_extension_record (struct sfm_reader *, struct dictionary *);
152 static void read_machine_int32_info (struct sfm_reader *,
153                                      size_t size, size_t count);
154 static void read_machine_flt64_info (struct sfm_reader *,
155                                      size_t size, size_t count);
156 static void read_display_parameters (struct sfm_reader *,
157                                      size_t size, size_t count,
158                                      struct dictionary *);
159 static void read_long_var_name_map (struct sfm_reader *,
160                                     size_t size, size_t count,
161                                     struct dictionary *);
162 static void read_long_string_map (struct sfm_reader *,
163                                   size_t size, size_t count,
164                                   struct dictionary *);
165
166
167 /* Opens the system file designated by file handle FH for
168    reading.  Reads the system file's dictionary into *DICT.
169    If INFO is non-null, then it receives additional info about the
170    system file. */
171 struct sfm_reader *
172 sfm_open_reader (struct file_handle *fh, struct dictionary **dict,
173                  struct sfm_read_info *info)
174 {
175   struct sfm_reader *volatile r = NULL;
176   struct variable **var_by_value_idx;
177   int format_warning_cnt = 0;
178   int weight_idx;
179   int claimed_value_cnt;
180   int rec_type;
181   size_t i;
182
183   if (!fh_open (fh, FH_REF_FILE, "system file", "rs"))
184     return NULL;
185
186   *dict = dict_create ();
187
188   /* Create and initialize reader. */
189   r = pool_create_container (struct sfm_reader, pool);
190   r->fh = fh;
191   r->file = fn_open (fh_get_file_name (fh), "rb");
192   r->error = false;
193   r->value_cnt = 0;
194   r->has_vls = false;
195   r->opcode_idx = sizeof r->opcodes;
196
197   if (setjmp (r->bail_out)) 
198     {
199       sfm_close_reader (r);
200       dict_destroy (*dict);
201       *dict = NULL;
202       return NULL;
203     }
204
205   if (r->file == NULL)
206     {
207       msg (ME, _("Error opening \"%s\" for reading as a system file: %s."),
208            fh_get_file_name (r->fh), strerror (errno));
209       longjmp (r->bail_out, 1);
210     }
211
212   /* Read header. */
213   read_header (r, *dict, &weight_idx, &claimed_value_cnt, info);
214
215   /* Read all the variable definition records. */
216   rec_type = read_int32 (r);
217   while (rec_type == 2)
218     {
219       read_variable_record (r, *dict, &format_warning_cnt); 
220       rec_type = read_int32 (r);
221     }
222
223   /* Figure out the case format. */
224   var_by_value_idx = make_var_by_value_idx (r, *dict);
225   setup_weight (r, weight_idx, var_by_value_idx, *dict);
226
227   /* Read all the rest of the dictionary records. */
228   while (rec_type != 999) 
229     {
230       switch (rec_type)
231         {
232         case 3:
233           read_value_labels (r, *dict, var_by_value_idx);
234           break;
235
236         case 4:
237           sys_error (r, _("Misplaced type 4 record."));
238
239         case 6:
240           read_documents (r, *dict);
241           break;
242
243         case 7:
244           read_extension_record (r, *dict);
245           break;
246
247         default:
248           sys_error (r, _("Unrecognized record type %d."), rec_type);
249         }
250       rec_type = read_int32 (r);
251     }
252
253   /* Read record 999 data, which is just filler. */
254   read_int32 (r);
255
256   if (claimed_value_cnt != -1 && claimed_value_cnt != r->value_cnt)
257     sys_warn (r, _("File header claims %d variable positions but "
258                    "%d were read from file."),
259               claimed_value_cnt, r->value_cnt);
260
261   /* Create an index of dictionary variable widths for
262      sfm_read_case to use.  We cannot use the `struct variable's
263      from the dictionary we created, because the caller owns the
264      dictionary and may destroy or modify its variables. */
265   r->var_cnt = dict_get_var_cnt (*dict);
266   r->vars = pool_nalloc (r->pool, r->var_cnt, sizeof *r->vars);
267   for (i = 0; i < r->var_cnt; i++) 
268     {
269       struct variable *v = dict_get_var (*dict, i);
270       struct sfm_var *sv = &r->vars[i];
271       sv->width = var_get_width (v);
272       sv->case_index = var_get_case_index (v); 
273     }
274
275   pool_free (r->pool, var_by_value_idx);
276   return r;
277 }
278
279 /* Closes a system file after we're done with it. */
280 void
281 sfm_close_reader (struct sfm_reader *r)
282 {
283   if (r == NULL)
284     return;
285
286   if (r->file)
287     {
288       if (fn_close (fh_get_file_name (r->fh), r->file) == EOF)
289         msg (ME, _("Error closing system file \"%s\": %s."),
290              fh_get_file_name (r->fh), strerror (errno));
291       r->file = NULL;
292     }
293
294   if (r->fh != NULL)
295     fh_close (r->fh, "system file", "rs");
296
297   pool_destroy (r->pool);
298 }
299
300 /* Returns true if an I/O error has occurred on READER, false
301    otherwise. */
302 bool
303 sfm_read_error (const struct sfm_reader *reader) 
304 {
305   return reader->error;
306 }
307
308 /* Returns true if FILE is an SPSS system file,
309    false otherwise. */
310 bool
311 sfm_detect (FILE *file) 
312 {
313   char rec_type[5];
314
315   if (fread (rec_type, 4, 1, file) != 1)
316     return false;
317   rec_type[4] = '\0';
318   
319   return !strcmp ("$FL2", rec_type);
320 }
321 \f
322 /* Reads the global header of the system file.
323    Sets DICT's file label to the system file's label.
324    Sets *WEIGHT_IDX to 0 if the system file is unweighted,
325    or to the value index of the weight variable otherwise.
326    Sets *CLAIMED_VALUE_CNT to the number of values that the file
327    claims to have (although it is not always correct).
328    If INFO is non-null, initializes *INFO with header
329    information. */   
330 static void
331 read_header (struct sfm_reader *r, struct dictionary *dict,
332              int *weight_idx, int *claimed_value_cnt,
333              struct sfm_read_info *info)
334 {
335   char rec_type[5];
336   char eye_catcher[61];
337   uint8_t raw_layout_code[4];
338   int case_cnt;
339   uint8_t raw_bias[8];
340   char creation_date[10];
341   char creation_time[9];
342   char file_label[65];
343   struct substring file_label_ss;
344
345   read_string (r, rec_type, sizeof rec_type);
346   read_string (r, eye_catcher, sizeof eye_catcher);
347   
348   if (strcmp ("$FL2", rec_type) != 0)
349     sys_error (r, _("This is not an SPSS system file."));
350
351   /* Identify integer format. */
352   read_bytes (r, raw_layout_code, sizeof raw_layout_code);
353   if ((!integer_identify (2, raw_layout_code, sizeof raw_layout_code,
354                           &r->integer_format)
355        && !integer_identify (3, raw_layout_code, sizeof raw_layout_code,
356                              &r->integer_format))
357       || (r->integer_format != INTEGER_MSB_FIRST
358           && r->integer_format != INTEGER_LSB_FIRST))
359     sys_error (r, _("This is not an SPSS system file."));
360
361   *claimed_value_cnt = read_int32 (r);
362   if (*claimed_value_cnt < 0 || *claimed_value_cnt > INT_MAX / 16)
363     *claimed_value_cnt = -1;
364
365   r->compressed = read_int32 (r) != 0;
366
367   *weight_idx = read_int32 (r);
368
369   case_cnt = read_int32 (r);
370   if (case_cnt < -1 || case_cnt > INT_MAX / 2)
371     case_cnt = -1;
372
373   /* Identify floating-point format and obtain compression bias. */
374   read_bytes (r, raw_bias, sizeof raw_bias);
375   if (float_identify (100.0, raw_bias, sizeof raw_bias, &r->float_format) == 0)
376     {
377       sys_warn (r, _("Compression bias (%g) is not the usual "
378                      "value of 100, or system file uses unrecognized "
379                      "floating-point format."),
380                 r->bias);
381       if (r->integer_format == INTEGER_MSB_FIRST)
382         r->float_format = FLOAT_IEEE_DOUBLE_BE;
383       else
384         r->float_format = FLOAT_IEEE_DOUBLE_LE;
385     }
386   float_convert (r->float_format, raw_bias, FLOAT_NATIVE_DOUBLE, &r->bias);
387
388   read_string (r, creation_date, sizeof creation_date);
389   read_string (r, creation_time, sizeof creation_time);
390   read_string (r, file_label, sizeof file_label);
391   skip_bytes (r, 3);
392   
393   file_label_ss = ss_cstr (file_label);
394   ss_trim (&file_label_ss, ss_cstr (" "));
395   if (!ss_is_empty (file_label_ss)) 
396     {
397       ss_data (file_label_ss)[ss_length (file_label_ss)] = '\0';
398       dict_set_label (dict, ss_data (file_label_ss));
399     }
400
401   if (info)
402     {
403       struct substring product;
404
405       strcpy (info->creation_date, creation_date);
406       strcpy (info->creation_time, creation_time);
407       info->integer_format = r->integer_format;
408       info->float_format = r->float_format;
409       info->compressed = r->compressed;
410       info->case_cnt = case_cnt;
411
412       product = ss_cstr (eye_catcher);
413       ss_match_string (&product, ss_cstr ("@(#) SPSS DATA FILE"));
414       ss_trim (&product, ss_cstr (" "));
415       str_copy_buf_trunc (info->product, sizeof info->product,
416                           ss_data (product), ss_length (product));
417     }
418 }
419
420 /* Reads a variable (type 2) record from R and adds the
421    corresponding variable to DICT.
422    Also skips past additional variable records for long string
423    variables. */
424 static void
425 read_variable_record (struct sfm_reader *r, struct dictionary *dict,
426                       int *format_warning_cnt)
427 {
428   int width;
429   int has_variable_label;
430   int missing_value_code;
431   int print_format;
432   int write_format;
433   char name[9];
434
435   struct variable *var;
436   int nv;
437
438   width = read_int32 (r);
439   has_variable_label = read_int32 (r);
440   missing_value_code = read_int32 (r);
441   print_format = read_int32 (r);
442   write_format = read_int32 (r);
443   read_string (r, name, sizeof name);
444   name[strcspn (name, " ")] = '\0';
445
446   /* Check variable name. */
447   if (name[0] == '$' || name[0] == '#')
448     sys_error (r, "Variable name begins with invalid character `%c'.",
449                name[0]);
450   if (!var_is_plausible_name (name, false))
451     sys_error (r, _("Invalid variable name `%s'."), name);
452
453   /* Create variable. */
454   if (width < 0 || width > 255)
455     sys_error (r, _("Bad variable width %d."), width);
456   var = dict_create_var (dict, name, width);
457   if (var == NULL) 
458     sys_error (r,
459                _("Duplicate variable name `%s' within system file."),
460                name);
461
462   /* Set the short name the same as the long name */
463   var_set_short_name (var, var_get_name (var));
464
465   /* Get variable label, if any. */
466   if (has_variable_label != 0 && has_variable_label != 1)
467     sys_error (r, _("Variable label indicator field is not 0 or 1."));
468   if (has_variable_label == 1)
469     {
470       size_t len;
471       char label[255 + 1];
472
473       len = read_int32 (r);
474       if (len >= sizeof label)
475         sys_error (r, _("Variable %s has label of invalid length %d."),
476                    name, len);
477       read_string (r, label, len + 1);
478       var_set_label (var, label);
479       
480       skip_bytes (r, ROUND_UP (len, 4) - len);
481     }
482
483   /* Set missing values. */
484   if (missing_value_code < -3 || missing_value_code > 3
485       || missing_value_code == -1)
486     sys_error (r, _("Missing value indicator field is not "
487                     "-3, -2, 0, 1, 2, or 3."));
488   if (missing_value_code != 0)
489     {
490       struct missing_values mv;
491       mv_init (&mv, var_get_width (var));
492       if (var_is_numeric (var)) 
493         {
494           if (missing_value_code > 0)
495             {
496               int i;
497               for (i = 0; i < missing_value_code; i++)
498                 mv_add_num (&mv, read_flt64 (r));
499             }
500           else
501             {
502               double low = read_flt64 (r);
503               double high = read_flt64 (r);
504               mv_add_num_range (&mv, low, high);
505               if (missing_value_code == -3)
506                 mv_add_num (&mv, read_flt64 (r));
507             }
508         }
509       else if (var_get_width (var) <= MAX_SHORT_STRING)
510         {
511           if (missing_value_code > 0)
512             {
513               int i;
514               for (i = 0; i < missing_value_code; i++)
515                 {
516                   char string[9];
517                   read_string (r, string, sizeof string);
518                   mv_add_str (&mv, string); 
519                 }
520             }
521           else 
522             sys_error (r, _("String variable %s may not have missing "
523                             "values specified as a range."),
524                        name);
525         }
526       else /* var->width > MAX_SHORT_STRING */
527         sys_error (r, _("Long string variable %s may not have missing "
528                         "values."),
529                    name);
530       var_set_missing_values (var, &mv);
531     }
532
533   /* Set formats. */
534   parse_format_spec (r, print_format, PRINT_FORMAT, var, format_warning_cnt);
535   parse_format_spec (r, write_format, WRITE_FORMAT, var, format_warning_cnt);
536
537   /* Account for values.
538      Skip long string continuation records, if any. */
539   nv = width == 0 ? 1 : DIV_RND_UP (width, 8);
540   r->value_cnt += nv;
541   if (width > 8)
542     {
543       int i;
544
545       for (i = 1; i < nv; i++)
546         {
547           /* Check for record type 2 and width -1. */
548           if (read_int32 (r) != 2 || read_int32 (r) != -1)
549             sys_error (r, _("Missing string continuation record."));
550
551           /* Skip and ignore remaining continuation data. */
552           has_variable_label = read_int32 (r);
553           missing_value_code = read_int32 (r);
554           print_format = read_int32 (r);
555           write_format = read_int32 (r);
556           read_string (r, name, sizeof name);
557
558           /* Variable label fields on continuation records have
559              been spotted in system files created by "SPSS Power
560              Macintosh Release 6.1". */
561           if (has_variable_label) 
562             skip_bytes (r, ROUND_UP (read_int32 (r), 4));
563         }
564     }
565 }
566
567 /* Translates the format spec from sysfile format to internal
568    format. */
569 static void
570 parse_format_spec (struct sfm_reader *r, uint32_t s,
571                    enum which_format which, struct variable *v,
572                    int *format_warning_cnt)
573 {
574   const int max_format_warnings = 8;
575   struct fmt_spec f;
576   uint8_t raw_type = s >> 16;
577   uint8_t w = s >> 8;
578   uint8_t d = s;
579   
580   bool ok;
581   
582   if (!fmt_from_io (raw_type, &f.type))
583     sys_error (r, _("Unknown variable format %d."), (int) raw_type);
584   f.w = w;
585   f.d = d;
586
587   msg_disable ();
588   ok = fmt_check_output (&f) && fmt_check_width_compat (&f, var_get_width (v));
589   msg_enable ();
590   
591   if (ok) 
592     {
593       if (which == PRINT_FORMAT)
594         var_set_print_format (v, &f);
595       else
596         var_set_write_format (v, &f);
597     }
598   else if (*++format_warning_cnt <= max_format_warnings)
599     {
600       char fmt_string[FMT_STRING_LEN_MAX + 1];
601       sys_warn (r, _("%s variable %s has invalid %s format %s."),
602                 var_is_numeric (v) ? _("Numeric") : _("String"),
603                 var_get_name (v),
604                 which == PRINT_FORMAT ? _("print") : _("write"),
605                 fmt_to_string (&f, fmt_string));
606
607       if (*format_warning_cnt == max_format_warnings)
608         sys_warn (r, _("Suppressing further invalid format warnings."));
609     }
610 }
611
612 /* Sets the weighting variable in DICT to the variable
613    corresponding to the given 1-based VALUE_IDX, if VALUE_IDX is
614    nonzero. */
615 static void
616 setup_weight (struct sfm_reader *r, int weight_idx,
617               struct variable **var_by_value_idx, struct dictionary *dict) 
618 {
619   if (weight_idx != 0)
620     {
621       struct variable *weight_var
622         = lookup_var_by_value_idx (r, var_by_value_idx, weight_idx);
623       if (var_is_numeric (weight_var))
624         dict_set_weight (dict, weight_var);
625       else
626         sys_error (r, _("Weighting variable must be numeric."));
627     }
628 }
629
630 /* Reads a document record, type 6, from system file R, and sets up
631    the documents and n_documents fields in the associated
632    dictionary. */
633 static void
634 read_documents (struct sfm_reader *r, struct dictionary *dict)
635 {
636   int line_cnt;
637   char *documents;
638
639   if (dict_get_documents (dict) != NULL)
640     sys_error (r, _("Multiple type 6 (document) records."));
641
642   line_cnt = read_int32 (r);
643   if (line_cnt <= 0)
644     sys_error (r, _("Number of document lines (%d) "
645                     "must be greater than 0."), line_cnt);
646
647   documents = pool_nmalloc (r->pool, line_cnt + 1, 80);
648   read_string (r, documents, 80 * line_cnt + 1);
649   dict_set_documents (dict, documents);
650   pool_free (r->pool, documents);
651 }
652
653 /* Read a type 7 extension record. */
654 static void
655 read_extension_record (struct sfm_reader *r, struct dictionary *dict)
656 {
657   int subtype = read_int32 (r);
658   size_t size = read_int32 (r);
659   size_t count = read_int32 (r);
660   size_t bytes = size * count;
661
662   /* Check that SIZE * COUNT + 1 doesn't overflow.  Adding 1
663      allows an extra byte for a null terminator, used by some
664      extension processing routines. */
665   if (size != 0 && size_overflow_p (xsum (1, xtimes (count, size))))
666     sys_error (r, "Record type 7 subtype %d too large.", subtype);
667
668   switch (subtype)
669     {
670     case 3:
671       read_machine_int32_info (r, size, count);
672       return;
673
674     case 4:
675       read_machine_flt64_info (r, size, count);
676       return;
677
678     case 5:
679       /* Variable sets information.  We don't use these yet.
680          They only apply to GUIs; see VARSETS on the APPLY
681          DICTIONARY command in SPSS documentation. */
682       break;
683
684     case 6:
685       /* DATE variable information.  We don't use it yet, but we
686          should. */
687       break;
688                 
689     case 7:
690       /* Unknown purpose. */
691       break;
692       
693     case 11:
694       read_display_parameters (r, size, count, dict);
695       return;
696
697     case 13:
698       read_long_var_name_map (r, size, count, dict);
699       return;
700
701     case 14:
702       read_long_string_map (r, size, count, dict);
703       return;
704
705     case 16:
706       /* New in SPSS v14?  Unknown purpose.  */
707       break;
708
709     case 17:
710       /* Text field that defines variable attributes.  New in
711          SPSS 14. */
712       break;
713       
714     default:
715       sys_warn (r, _("Unrecognized record type 7, subtype %d."), subtype);
716       break;
717     }
718
719   skip_bytes (r, bytes);
720 }
721
722 /* Read record type 7, subtype 3. */
723 static void
724 read_machine_int32_info (struct sfm_reader *r, size_t size, size_t count)
725 {
726   int version_major UNUSED = read_int32 (r);
727   int version_minor UNUSED = read_int32 (r);
728   int version_revision UNUSED = read_int32 (r);
729   int machine_code UNUSED = read_int32 (r);
730   int float_representation = read_int32 (r);
731   int compression_code UNUSED = read_int32 (r);
732   int integer_representation = read_int32 (r);
733   int character_code UNUSED = read_int32 (r);
734
735   int expected_float_format;
736   int expected_integer_format;
737
738   if (size != 4 || count != 8)
739     sys_error (r, _("Bad size (%d) or count (%d) field on record type 7, "
740                     "subtype 3."),
741                size, count);
742
743   /* Check floating point format. */
744   if (r->float_format == FLOAT_IEEE_DOUBLE_BE
745       || r->float_format == FLOAT_IEEE_DOUBLE_LE)
746     expected_float_format = 1;
747   else if (r->float_format == FLOAT_Z_LONG)
748     expected_float_format = 2;
749   else if (r->float_format == FLOAT_VAX_G || r->float_format == FLOAT_VAX_D)
750     expected_float_format = 3;
751   else
752     NOT_REACHED ();
753   if (float_representation != expected_float_format)
754     sys_error (r, _("Floating-point representation indicated by "
755                     "system file (%d) differs from expected (%d)."),
756                r->float_format, expected_float_format);
757
758   /* Check integer format. */
759   if (r->integer_format == INTEGER_MSB_FIRST)
760     expected_integer_format = 1;
761   else if (r->integer_format == INTEGER_LSB_FIRST)
762     expected_integer_format = 2;
763   else
764     NOT_REACHED ();
765   if (integer_representation != expected_integer_format)
766     {
767       static const char *endian[] = {N_("little-endian"), N_("big-endian")};
768       sys_warn (r, _("Integer format indicated by system file (%s) "
769                      "differs from expected (%s)."),
770                 gettext (endian[integer_representation == 1]),
771                 gettext (endian[expected_integer_format == 1]));
772     }
773 }
774
775 /* Read record type 7, subtype 4. */
776 static void
777 read_machine_flt64_info (struct sfm_reader *r, size_t size, size_t count)
778 {
779   double sysmis = read_flt64 (r);
780   double highest = read_flt64 (r);
781   double lowest = read_flt64 (r);
782
783   if (size != 8 || count != 3)
784     sys_error (r, _("Bad size (%d) or count (%d) on extension 4."),
785                size, count);
786
787   if (sysmis != SYSMIS)
788     sys_warn (r, _("File specifies unexpected value %g as SYSMIS."), sysmis);
789   if (highest != HIGHEST)
790     sys_warn (r, _("File specifies unexpected value %g as HIGHEST."), highest);
791   if (lowest != LOWEST)
792     sys_warn (r, _("File specifies unexpected value %g as LOWEST."), lowest);
793 }
794
795 /* Read record type 7, subtype 11, which specifies how variables
796    should be displayed in GUI environments. */
797 static void
798 read_display_parameters (struct sfm_reader *r, size_t size, size_t count,
799                          struct dictionary *dict)
800 {
801   const size_t n_vars = count / 3 ;
802   bool warned = false;
803   int i;
804
805   if (count % 3 || n_vars != dict_get_var_cnt (dict)) 
806     sys_error (r, _("Bad size (%d) or count (%d) on extension 11."),
807                size, count);
808
809   for (i = 0; i < n_vars; ++i) 
810     {
811       int measure = read_int32 (r);
812       int width = read_int32 (r);
813       int align = read_int32 (r);
814       struct variable *v;
815
816       if (!measure_is_valid (measure) || !alignment_is_valid (align))
817         {
818           if (!warned)
819             sys_warn (r, _("Invalid variable display parameters.  "
820                            "Default parameters substituted."));
821           warned = true;
822           continue;
823         }
824
825       v = dict_get_var (dict, i);
826       var_set_measure (v, measure);
827       var_set_display_width (v, width);
828       var_set_alignment (v, align);
829     }
830 }
831
832 /* Reads record type 7, subtype 13, which gives the long name
833    that corresponds to each short name.  Modifies variable names
834    in DICT accordingly.  */
835 static void
836 read_long_var_name_map (struct sfm_reader *r, size_t size, size_t count,
837                         struct dictionary *dict)
838 {
839   struct variable_to_value_map *map;
840   struct variable *var;
841   char *long_name;
842   int warning_cnt = 0;
843   
844   map = open_variable_to_value_map (r, size * count);
845   while (read_variable_to_value_map (r, dict, map, &var, &long_name,
846                                      &warning_cnt))
847     {
848       char short_name[SHORT_NAME_LEN + 1];
849       strcpy (short_name, var_get_short_name (var));
850
851       /* Validate long name. */
852       if (!var_is_valid_name (long_name, false))
853         {
854           sys_warn (r, _("Long variable mapping from %s to invalid "
855                          "variable name `%s'."),
856                     var_get_name (var), long_name);
857           continue;
858         }
859                       
860       /* Identify any duplicates. */
861       if (strcasecmp (short_name, long_name)
862           && dict_lookup_var (dict, long_name) != NULL)
863         {
864           sys_warn (r, _("Duplicate long variable name `%s' "
865                          "within system file."), long_name);
866           continue;
867         }
868
869       /* Set long name.  Renaming a variable may clear the short
870          name, but we want to retain it, so re-set it
871          explicitly. */
872       dict_rename_var (dict, var, long_name);
873       var_set_short_name (var, short_name);
874     }
875   close_variable_to_value_map (r, map);
876 }
877
878 /* Reads record type 7, subtype 14, which gives the real length
879    of each very long string.  Rearranges DICT accordingly. */
880 static void
881 read_long_string_map (struct sfm_reader *r, size_t size, size_t count,
882                       struct dictionary *dict)
883 {
884   struct variable_to_value_map *map;
885   struct variable *var;
886   char *length_s;
887   int warning_cnt = 0;
888
889   r->has_vls = true;
890
891   map = open_variable_to_value_map (r, size * count);
892   while (read_variable_to_value_map (r, dict, map, &var, &length_s,
893                                      &warning_cnt))
894     {
895       long length, remaining_length;
896       size_t idx;
897
898       /* Get length. */
899       length = strtol (length_s, NULL, 10);
900       if (length < MIN_VERY_LONG_STRING || length == LONG_MAX) 
901         {
902           sys_warn (r, _("%s listed as string of length %s "
903                          "in length table."),
904                     var_get_name (var), length_s);
905           continue;
906         }
907
908       /* Group multiple variables into single variable
909          and delete all but the first. */
910       remaining_length = length;
911       for (idx = var_get_dict_index (var); remaining_length > 0; idx++)
912         if (idx < dict_get_var_cnt (dict)) 
913           remaining_length -= MIN (var_get_width (dict_get_var (dict, idx)),
914                                    EFFECTIVE_LONG_STRING_LENGTH);
915         else
916           sys_error (r, _("Very long string %s overflows dictionary."),
917                      var_get_name (var));
918       dict_delete_consecutive_vars (dict,
919                                     var_get_dict_index (var) + 1,
920                                     idx - var_get_dict_index (var) - 1);
921
922       /* Assign all the length to the first variable. */
923       var_set_width (var, length);
924     }
925   close_variable_to_value_map (r, map);
926   dict_compact_values (dict);
927 }
928
929 /* Reads value labels from sysfile H and inserts them into the
930    associated dictionary. */
931 static void
932 read_value_labels (struct sfm_reader *r,
933                    struct dictionary *dict, struct variable **var_by_value_idx)
934 {
935   struct pool *subpool;
936   
937   struct label 
938     {
939       char raw_value[8];        /* Value as uninterpreted bytes. */
940       union value value;        /* Value. */
941       char *label;              /* Null-terminated label string. */
942     };
943
944   struct label *labels = NULL;
945   int label_cnt;                /* Number of labels. */
946
947   struct variable **var = NULL; /* Associated variables. */
948   int var_cnt;                  /* Number of associated variables. */
949
950   int i;
951
952   subpool = pool_create_subpool (r->pool);
953
954   /* Read the type 3 record and record its contents.  We can't do
955      much with the data yet because we don't know whether it is
956      of numeric or string type. */
957
958   /* Read number of labels. */
959   label_cnt = read_int32 (r);
960
961   if (label_cnt >= INT32_MAX / sizeof *labels)
962     {    
963       sys_warn (r, _("Invalid number of labels: %d.  Ignoring labels."),
964                 label_cnt);
965       label_cnt = 0;
966     }
967
968   /* Read each value/label tuple into labels[]. */
969   labels = pool_nalloc (subpool, label_cnt, sizeof *labels);
970   for (i = 0; i < label_cnt; i++)
971     {
972       struct label *label = labels + i;
973       unsigned char label_len;
974       size_t padded_len;
975
976       /* Read value. */
977       read_bytes (r, label->raw_value, sizeof label->raw_value);
978
979       /* Read label length. */
980       read_bytes (r, &label_len, sizeof label_len);
981       padded_len = ROUND_UP (label_len + 1, 8);
982
983       /* Read label, padding. */
984       label->label = pool_alloc (subpool, padded_len + 1);
985       read_bytes (r, label->label, padded_len - 1);
986       label->label[label_len] = 0;
987     }
988
989   /* Now, read the type 4 record that has the list of variables
990      to which the value labels are to be applied. */
991
992   /* Read record type of type 4 record. */
993   if (read_int32 (r) != 4)
994     sys_error (r, _("Variable index record (type 4) does not immediately "
995                     "follow value label record (type 3) as it should."));
996
997   /* Read number of variables associated with value label from type 4
998      record. */
999   var_cnt = read_int32 (r);
1000   if (var_cnt < 1 || var_cnt > dict_get_var_cnt (dict))
1001     sys_error (r, _("Number of variables associated with a value label (%d) "
1002                     "is not between 1 and the number of variables (%d)."),
1003                var_cnt, dict_get_var_cnt (dict));
1004
1005   /* Read the list of variables. */
1006   var = pool_nalloc (subpool, var_cnt, sizeof *var);
1007   for (i = 0; i < var_cnt; i++)
1008     {
1009       var[i] = lookup_var_by_value_idx (r, var_by_value_idx, read_int32 (r));
1010       if (var_is_long_string (var[i]))
1011         sys_error (r, _("Value labels are not allowed on long string "
1012                         "variables (%s)."), var_get_name (var[i]));
1013     }
1014
1015   /* Type check the variables. */
1016   for (i = 1; i < var_cnt; i++)
1017     if (var_get_type (var[i]) != var_get_type (var[0]))
1018       sys_error (r, _("Variables associated with value label are not all of "
1019                       "identical type.  Variable %s is %s, but variable "
1020                       "%s is %s."),
1021                  var_get_name (var[0]),
1022                  var_is_numeric (var[0]) ? _("numeric") : _("string"),
1023                  var_get_name (var[i]),
1024                  var_is_numeric (var[i]) ? _("numeric") : _("string"));
1025
1026   /* Fill in labels[].value, now that we know the desired type. */
1027   for (i = 0; i < label_cnt; i++) 
1028     {
1029       struct label *label = labels + i;
1030       
1031       if (var_is_alpha (var[0]))
1032         buf_copy_rpad (label->value.s, sizeof label->value.s,
1033                        label->raw_value, sizeof label->raw_value);
1034       else
1035         label->value.f = flt64_to_double (r, (uint8_t *) label->raw_value);
1036     }
1037   
1038   /* Assign the `value_label's to each variable. */
1039   for (i = 0; i < var_cnt; i++)
1040     {
1041       struct variable *v = var[i];
1042       int j;
1043
1044       /* Add each label to the variable. */
1045       for (j = 0; j < label_cnt; j++)
1046         {
1047           struct label *label = &labels[j];
1048           if (!var_add_value_label (v, &label->value, label->label)) 
1049             {
1050               if (var_is_numeric (var[0]))
1051                 sys_warn (r, _("Duplicate value label for %g on %s."),
1052                           label->value.f, var_get_name (v));
1053               else
1054                 sys_warn (r, _("Duplicate value label for \"%.*s\" on %s."),
1055                           var_get_width (v), label->value.s,
1056                           var_get_name (v)); 
1057             }
1058         }
1059     }
1060
1061   pool_destroy (subpool);
1062 }
1063 \f
1064 /* Case reader. */
1065
1066 static void partial_record (struct sfm_reader *r)
1067      NO_RETURN;
1068 static bool read_case_number (struct sfm_reader *, double *);
1069 static bool read_case_string (struct sfm_reader *, char *, size_t);
1070 static int read_opcode (struct sfm_reader *);
1071 static bool read_compressed_number (struct sfm_reader *, double *);
1072 static bool read_compressed_string (struct sfm_reader *, char *);
1073 static bool read_whole_strings (struct sfm_reader *, char *, size_t);
1074
1075 /* Reads one case from READER's file into C.  Returns nonzero
1076    only if successful. */
1077 int
1078 sfm_read_case (struct sfm_reader *r, struct ccase *c)
1079 {
1080   if (r->error)
1081     return 0;
1082
1083   if (setjmp (r->bail_out))
1084     return 0;
1085
1086   if (!r->compressed && sizeof (double) == 8 && !r->has_vls) 
1087     {
1088       /* Fast path.  Read the whole case directly. */
1089       if (!try_read_bytes (r, case_data_all_rw (c),
1090                          sizeof (union value) * r->value_cnt))
1091         return 0;
1092
1093       /* Convert floating point numbers to native format if needed. */
1094       if (r->float_format != FLOAT_NATIVE_DOUBLE) 
1095         {
1096           int i;
1097           
1098           for (i = 0; i < r->var_cnt; i++) 
1099             if (r->vars[i].width == 0) 
1100               {
1101                 double *d = &case_data_rw_idx (c, r->vars[i].case_index)->f;
1102                 float_convert (r->float_format, d, FLOAT_NATIVE_DOUBLE, d); 
1103               }
1104         }
1105       return 1;
1106     }
1107   else 
1108     {
1109       /* Slow path.  Convert from external to internal format. */
1110       int i;
1111
1112       for (i = 0; i < r->var_cnt; i++)
1113         {
1114           struct sfm_var *sv = &r->vars[i];
1115           union value *v = case_data_rw_idx (c, sv->case_index);
1116
1117           if (sv->width == 0) 
1118             {
1119               if (!read_case_number (r, &v->f))
1120                 goto eof; 
1121             }
1122           else
1123             {
1124               /* Read the string data in segments up to 255 bytes
1125                  at a time, packed into 8-byte units. */
1126               const int max_chunk = MIN_VERY_LONG_STRING - 1;
1127               int ofs, chunk_size;
1128               for (ofs = 0; ofs < sv->width; ofs += chunk_size)
1129                 {
1130                   chunk_size = MIN (max_chunk, sv->width - ofs);
1131                   if (!read_case_string (r, v->s + ofs, chunk_size)) 
1132                     {
1133                       if (ofs)
1134                         partial_record (r);
1135                       goto eof; 
1136                     }
1137                 }
1138
1139               /* Very long strings have trailing wasted space
1140                  that we must skip. */
1141               if (sv->width >= MIN_VERY_LONG_STRING) 
1142                 {
1143                   int bytes_read = (sv->width / max_chunk * 256
1144                                     + ROUND_UP (sv->width % max_chunk, 8));
1145                   int total_bytes = sfm_width_to_bytes (sv->width);
1146                   int excess_bytes = total_bytes - bytes_read;
1147
1148                   while (excess_bytes > 0) 
1149                     {
1150                       char buffer[1024];
1151                       size_t chunk = MIN (sizeof buffer, excess_bytes);
1152                       if (!read_whole_strings (r, buffer, chunk))
1153                         partial_record (r);
1154                       excess_bytes -= chunk;
1155                     }
1156                 }
1157             }
1158         }
1159       return 1; 
1160
1161     eof:
1162       if (i != 0)
1163         partial_record (r);
1164       return 0;
1165     }
1166 }
1167
1168 /* Issues an error that R ends in a partial record. */
1169 static void
1170 partial_record (struct sfm_reader *r)
1171 {
1172   sys_error (r, _("File ends in partial case."));
1173 }
1174
1175 /* Reads a number from R and stores its value in *D.
1176    If R is compressed, reads a compressed number;
1177    otherwise, reads a number in the regular way.
1178    Returns true if successful, false if end of file is
1179    reached immediately. */
1180 static bool
1181 read_case_number (struct sfm_reader *r, double *d) 
1182 {
1183   if (!r->compressed)
1184     {
1185       uint8_t flt64[8];
1186       if (!try_read_bytes (r, flt64, sizeof flt64))
1187         return false;
1188       *d = flt64_to_double (r, flt64);
1189       return true;
1190     }
1191   else
1192     return read_compressed_number (r, d);
1193 }
1194
1195 /* Reads LENGTH string bytes from R into S.
1196    Always reads a multiple of 8 bytes; if LENGTH is not a
1197    multiple of 8, then extra bytes are read and discarded without
1198    being written to S.
1199    Reads compressed strings if S is compressed.
1200    Returns true if successful, false if end of file is
1201    reached immediately. */
1202 static bool
1203 read_case_string (struct sfm_reader *r, char *s, size_t length) 
1204 {
1205   size_t whole = ROUND_DOWN (length, 8);
1206   size_t partial = length % 8;
1207   
1208   if (whole) 
1209     {
1210       if (!read_whole_strings (r, s, whole))
1211         return false;
1212     }
1213
1214   if (partial)
1215     {
1216       char bounce[8];
1217       if (!read_whole_strings (r, bounce, sizeof bounce))
1218         {
1219           if (whole)
1220             partial_record (r);
1221           return false; 
1222         }
1223       memcpy (s + whole, bounce, partial);
1224     }
1225
1226   return true;
1227 }
1228
1229 /* Reads and returns the next compression opcode from R. */
1230 static int
1231 read_opcode (struct sfm_reader *r) 
1232 {
1233   assert (r->compressed);
1234   for (;;)
1235     {
1236       int opcode;
1237       if (r->opcode_idx >= sizeof r->opcodes) 
1238         {
1239           if (!try_read_bytes (r, r->opcodes, sizeof r->opcodes))
1240             return -1;
1241           r->opcode_idx = 0;
1242         }
1243       opcode = r->opcodes[r->opcode_idx++];
1244
1245       if (opcode != 0)
1246         return opcode;
1247     }
1248 }
1249
1250 /* Reads a compressed number from R and stores its value in D.
1251    Returns true if successful, false if end of file is
1252    reached immediately. */
1253 static bool
1254 read_compressed_number (struct sfm_reader *r, double *d)
1255 {
1256   int opcode = read_opcode (r); 
1257   switch (opcode)
1258     {
1259     case -1:
1260     case 252:
1261       return false;
1262
1263     case 253:
1264       *d = read_flt64 (r);
1265       break;
1266       
1267     case 254:
1268       sys_error (r, _("Compressed data is corrupt."));
1269
1270     case 255:
1271       *d = SYSMIS;
1272       break;
1273
1274     default:
1275       *d = opcode - r->bias;
1276       break;
1277     }
1278
1279   return true;
1280 }
1281
1282 /* Reads a compressed 8-byte string segment from R and stores it
1283    in DST.
1284    Returns true if successful, false if end of file is
1285    reached immediately. */
1286 static bool
1287 read_compressed_string (struct sfm_reader *r, char *dst)
1288 {
1289   switch (read_opcode (r))
1290     {
1291     case -1:
1292     case 252:
1293       return false;
1294
1295     case 253:
1296       read_bytes (r, dst, 8);
1297       break;
1298
1299     case 254:
1300       memset (dst, ' ', 8);
1301       break;
1302
1303     default:
1304       sys_error (r, _("Compressed data is corrupt."));
1305     }
1306
1307   return true;
1308 }
1309
1310 /* Reads LENGTH string bytes from R into S.
1311    LENGTH must be a multiple of 8.
1312    Reads compressed strings if S is compressed.
1313    Returns true if successful, false if end of file is
1314    reached immediately. */
1315 static bool
1316 read_whole_strings (struct sfm_reader *r, char *s, size_t length)
1317 {
1318   assert (length % 8 == 0);
1319   if (!r->compressed)
1320     return try_read_bytes (r, s, length);
1321   else
1322     {
1323       size_t ofs;
1324       for (ofs = 0; ofs < length; ofs += 8)
1325         if (!read_compressed_string (r, s + ofs)) 
1326           {
1327             if (ofs != 0)
1328               partial_record (r);
1329             return false;
1330           }
1331       return true;
1332     }
1333 }
1334 \f
1335 /* Creates and returns a table that can be used for translating a value
1336    index into a case to a "struct variable *" for DICT.  Multiple
1337    system file fields reference variables this way.
1338
1339    This table must be created before processing the very long
1340    string extension record, because that record causes some
1341    values to be deleted from the case and the dictionary to be
1342    compacted. */
1343 static struct variable **
1344 make_var_by_value_idx (struct sfm_reader *r, struct dictionary *dict) 
1345 {
1346   struct variable **var_by_value_idx;
1347   int value_idx = 0;
1348   int i;
1349
1350   var_by_value_idx = pool_nmalloc (r->pool,
1351                                    r->value_cnt, sizeof *var_by_value_idx);
1352   for (i = 0; i < dict_get_var_cnt (dict); i++) 
1353     {
1354       struct variable *v = dict_get_var (dict, i);
1355       int nv = var_is_numeric (v) ? 1 : DIV_RND_UP (var_get_width (v), 8);
1356       int j;
1357
1358       var_by_value_idx[value_idx++] = v;
1359       for (j = 1; j < nv; j++)
1360         var_by_value_idx[value_idx++] = NULL;
1361     }
1362   assert (value_idx == r->value_cnt);
1363
1364   return var_by_value_idx;
1365 }
1366
1367 /* Returns the "struct variable" corresponding to the given
1368    1-basd VALUE_IDX in VAR_BY_VALUE_IDX.  Verifies that the index
1369    is valid. */
1370 static struct variable *
1371 lookup_var_by_value_idx (struct sfm_reader *r,
1372                          struct variable **var_by_value_idx, int value_idx) 
1373 {
1374   struct variable *var;
1375   
1376   if (value_idx < 1 || value_idx > r->value_cnt)
1377     sys_error (r, _("Variable index %d not in valid range 1...%d."),
1378                value_idx, r->value_cnt);
1379
1380   var = var_by_value_idx[value_idx - 1];
1381   if (var == NULL)
1382     sys_error (r, _("Variable index %d refers to long string "
1383                     "continuation."),
1384                value_idx);
1385
1386   return var;
1387 }
1388
1389 /* Returns the variable in D with the given SHORT_NAME,
1390    or a null pointer if there is none. */
1391 static struct variable *
1392 lookup_var_by_short_name (struct dictionary *d, const char *short_name)
1393 {
1394   struct variable *var;
1395   size_t var_cnt;
1396   size_t i;
1397
1398   /* First try looking up by full name.  This often succeeds. */
1399   var = dict_lookup_var (d, short_name);
1400   if (var != NULL && !strcasecmp (var_get_short_name (var), short_name))
1401     return var;
1402
1403   /* Iterate through the whole dictionary as a fallback. */
1404   var_cnt = dict_get_var_cnt (d);
1405   for (i = 0; i < var_cnt; i++) 
1406     {
1407       var = dict_get_var (d, i);
1408       if (!strcasecmp (var_get_short_name (var), short_name))
1409         return var;
1410     }
1411
1412   return NULL;
1413 }
1414 \f
1415 /* Helpers for reading records that contain "variable=value"
1416    pairs. */
1417
1418 /* State. */
1419 struct variable_to_value_map 
1420   {
1421     struct substring buffer;    /* Record contents. */
1422     size_t pos;                 /* Current position in buffer. */
1423   };
1424
1425 /* Reads SIZE bytes into a "variable=value" map for R,
1426    and returns the map. */
1427 static struct variable_to_value_map *
1428 open_variable_to_value_map (struct sfm_reader *r, size_t size) 
1429 {
1430   struct variable_to_value_map *map = pool_alloc (r->pool, sizeof *map);
1431   char *buffer = pool_malloc (r->pool, size + 1);
1432   read_bytes (r, buffer, size);
1433   map->buffer = ss_buffer (buffer, size);
1434   map->pos = 0;
1435   return map;
1436 }
1437
1438 /* Closes MAP and frees its storage.
1439    Not really needed, because the pool will free the map anyway,
1440    but can be used to free it earlier. */
1441 static void
1442 close_variable_to_value_map (struct sfm_reader *r,
1443                              struct variable_to_value_map *map) 
1444 {
1445   pool_free (r->pool, ss_data (map->buffer));
1446 }
1447
1448 /* Reads the next variable=value pair from MAP.
1449    Looks up the variable in DICT and stores it into *VAR.
1450    Stores a null-terminated value into *VALUE. */
1451 static bool
1452 read_variable_to_value_map (struct sfm_reader *r, struct dictionary *dict,
1453                             struct variable_to_value_map *map,
1454                             struct variable **var, char **value,
1455                             int *warning_cnt) 
1456 {
1457   int max_warnings = 5;
1458   
1459   for (;;) 
1460     {
1461       struct substring short_name_ss, value_ss;
1462
1463       if (!ss_tokenize (map->buffer, ss_cstr ("="), &map->pos, &short_name_ss)
1464           || !ss_tokenize (map->buffer, ss_buffer ("\t\0", 2), &map->pos,
1465                            &value_ss)) 
1466         {
1467           if (*warning_cnt > max_warnings)
1468             sys_warn (r, _("Suppressed %d additional variable map warnings."),
1469                       *warning_cnt - max_warnings);
1470           return false; 
1471         }
1472       
1473       map->pos += ss_span (ss_substr (map->buffer, map->pos, SIZE_MAX),
1474                            ss_buffer ("\t\0", 2));
1475
1476       ss_data (short_name_ss)[ss_length (short_name_ss)] = '\0';
1477       *var = lookup_var_by_short_name (dict, ss_data (short_name_ss));
1478       if (*var == NULL)
1479         {
1480           if (++*warning_cnt <= 5)
1481             sys_warn (r, _("Variable map refers to unknown variable %s."),
1482                       ss_data (short_name_ss));
1483           continue;
1484         }
1485
1486       ss_data (value_ss)[ss_length (value_ss)] = '\0';
1487       *value = ss_data (value_ss);
1488
1489       return true;
1490     }
1491 }
1492 \f
1493 /* Messages. */
1494
1495 /* Displays a corruption message. */
1496 static void
1497 sys_msg (struct sfm_reader *r, int class, const char *format, va_list args)
1498 {
1499   struct msg m;
1500   struct string text;
1501
1502   ds_init_empty (&text);
1503   ds_put_format (&text, "\"%s\" near offset 0x%lx: ",
1504                  fh_get_file_name (r->fh), (unsigned long) ftell (r->file));
1505   ds_put_vformat (&text, format, args);
1506
1507   m.category = msg_class_to_category (class);
1508   m.severity = msg_class_to_severity (class);
1509   m.where.file_name = NULL;
1510   m.where.line_number = 0;
1511   m.text = ds_cstr (&text);
1512
1513   msg_emit (&m);
1514 }
1515
1516 /* Displays a warning for the current file position. */
1517 static void
1518 sys_warn (struct sfm_reader *r, const char *format, ...) 
1519 {
1520   va_list args;
1521   
1522   va_start (args, format);
1523   sys_msg (r, MW, format, args);
1524   va_end (args);
1525 }
1526
1527 /* Displays an error for the current file position,
1528    marks it as in an error state,
1529    and aborts reading it using longjmp. */
1530 static void
1531 sys_error (struct sfm_reader *r, const char *format, ...) 
1532 {
1533   va_list args;
1534   
1535   va_start (args, format);
1536   sys_msg (r, ME, format, args);
1537   va_end (args);
1538
1539   r->error = true;
1540   longjmp (r->bail_out, 1);
1541 }
1542 \f
1543 /* Reads BYTE_CNT bytes into BUF.
1544    Returns true if exactly BYTE_CNT bytes are successfully read.
1545    Aborts if an I/O error or a partial read occurs.
1546    If EOF_IS_OK, then an immediate end-of-file causes false to be
1547    returned; otherwise, immediate end-of-file causes an abort
1548    too. */
1549 static inline bool
1550 read_bytes_internal (struct sfm_reader *r, bool eof_is_ok,
1551                    void *buf, size_t byte_cnt)
1552 {
1553   size_t bytes_read = fread (buf, 1, byte_cnt, r->file);
1554   if (bytes_read == byte_cnt)
1555     return true;
1556   else if (ferror (r->file))
1557     sys_error (r, _("System error: %s."), strerror (errno));
1558   else if (!eof_is_ok || bytes_read != 0)
1559     sys_error (r, _("Unexpected end of file."));
1560   else
1561     return false;
1562 }
1563
1564 /* Reads BYTE_CNT into BUF.
1565    Aborts upon I/O error or if end-of-file is encountered. */
1566 static void
1567 read_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt)
1568 {
1569   read_bytes_internal (r, false, buf, byte_cnt);
1570 }
1571
1572 /* Reads BYTE_CNT bytes into BUF.
1573    Returns true if exactly BYTE_CNT bytes are successfully read.
1574    Returns false if an immediate end-of-file is encountered.
1575    Aborts if an I/O error or a partial read occurs. */
1576 static bool
1577 try_read_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt)
1578 {
1579   return read_bytes_internal (r, true, buf, byte_cnt);
1580 }
1581
1582 /* Reads a 32-bit signed integer from R and returns its value in
1583    host format. */
1584 static int32_t
1585 read_int32 (struct sfm_reader *r) 
1586 {
1587   uint8_t int32[4];
1588   read_bytes (r, int32, sizeof int32);
1589   return int32_to_native (r, int32);
1590 }
1591
1592 /* Reads a 64-bit floating-point number from R and returns its
1593    value in host format. */
1594 static double
1595 read_flt64 (struct sfm_reader *r) 
1596 {
1597   uint8_t flt64[8];
1598   read_bytes (r, flt64, sizeof flt64);
1599   return flt64_to_double (r, flt64);
1600 }
1601
1602 /* Reads exactly SIZE - 1 bytes into BUFFER
1603    and stores a null byte into BUFFER[SIZE - 1]. */
1604 static void
1605 read_string (struct sfm_reader *r, char *buffer, size_t size) 
1606 {
1607   assert (size > 0);
1608   read_bytes (r, buffer, size - 1);
1609   buffer[size - 1] = '\0';
1610 }
1611
1612 /* Skips BYTES bytes forward in R. */
1613 static void
1614 skip_bytes (struct sfm_reader *r, size_t bytes)
1615 {
1616   while (bytes > 0) 
1617     {
1618       char buffer[1024];
1619       size_t chunk = MIN (sizeof buffer, bytes);
1620       read_bytes (r, buffer, chunk);
1621       bytes -= chunk;
1622     }
1623 }
1624 \f
1625 /* Returns the value of the 32-bit signed integer at INT32,
1626    converted from the format used by R to the host format. */
1627 static int32_t
1628 int32_to_native (const struct sfm_reader *r, const uint8_t int32[4]) 
1629 {
1630   int32_t x;
1631   if (r->integer_format == INTEGER_NATIVE)
1632     memcpy (&x, int32, sizeof x);
1633   else
1634     x = integer_get (r->integer_format, int32, sizeof x);
1635   return x;
1636 }
1637
1638 /* Returns the value of the 64-bit floating point number at
1639    FLT64, converted from the format used by R to the host
1640    format. */
1641 static double
1642 flt64_to_double (const struct sfm_reader *r, const uint8_t flt64[8])
1643 {
1644   double x;
1645   if (r->float_format == FLOAT_NATIVE_DOUBLE)
1646     memcpy (&x, flt64, sizeof x);
1647   else
1648     float_convert (r->float_format, flt64, FLOAT_NATIVE_DOUBLE, &x);
1649   return x;
1650 }
1651