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