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