Fix syntax generation
[pspp] / src / data / por-file-reader.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU 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, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include "data/por-file-reader.h"
20
21 #include <ctype.h>
22 #include <errno.h>
23 #include <math.h>
24 #include <setjmp.h>
25 #include <stdarg.h>
26 #include <stdbool.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29
30 #include "data/casereader-provider.h"
31 #include "data/casereader.h"
32 #include "data/dictionary.h"
33 #include "data/file-handle-def.h"
34 #include "data/file-name.h"
35 #include "data/format.h"
36 #include "data/missing-values.h"
37 #include "data/short-names.h"
38 #include "data/value-labels.h"
39 #include "data/variable.h"
40 #include "libpspp/compiler.h"
41 #include "libpspp/i18n.h"
42 #include "libpspp/message.h"
43 #include "libpspp/misc.h"
44 #include "libpspp/pool.h"
45 #include "libpspp/str.h"
46
47 #include "gl/intprops.h"
48 #include "gl/minmax.h"
49 #include "gl/xalloc.h"
50
51 #include "gettext.h"
52 #define _(msgid) gettext (msgid)
53 #define N_(msgid) (msgid)
54
55 /* portable_to_local[PORTABLE] translates the given portable
56    character into the local character set. */
57 static const char portable_to_local[256] =
58   {
59     "                                                                "
60     "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ."
61     "<(+|&[]!$*);^-/|,%_>?`:$@'=\"      ~-   0123456789   -() {}\\     "
62     "                                                                "
63   };
64
65 /* Portable file reader. */
66 struct pfm_reader
67   {
68     struct pool *pool;          /* All the portable file state. */
69
70     jmp_buf bail_out;           /* longjmp() target for error handling. */
71
72     struct file_handle *fh;     /* File handle. */
73     struct fh_lock *lock;       /* Read lock for file. */
74     FILE *file;                 /* File stream. */
75     int line_length;            /* Number of characters so far on this line. */
76     char cc;                    /* Current character. */
77     char *trans;                /* 256-byte character set translation table. */
78     int var_cnt;                /* Number of variables. */
79     int weight_index;           /* 0-based index of weight variable, or -1. */
80     struct caseproto *proto;    /* Format of output cases. */
81     bool ok;                    /* Set false on I/O error. */
82   };
83
84 static const struct casereader_class por_file_casereader_class;
85
86 static void
87 error (struct pfm_reader *r, const char *msg,...)
88      PRINTF_FORMAT (2, 3)
89      NO_RETURN;
90
91 /* Displays MSG as an error message and aborts reading the
92    portable file via longjmp(). */
93 static void
94 error (struct pfm_reader *r, const char *msg, ...)
95 {
96   struct msg m;
97   struct string text;
98   va_list args;
99
100   ds_init_empty (&text);
101   ds_put_format (&text, _("portable file %s corrupt at offset 0x%llx: "),
102                  fh_get_file_name (r->fh), (long long int) ftello (r->file));
103   va_start (args, msg);
104   ds_put_vformat (&text, msg, args);
105   va_end (args);
106
107   m.category = MSG_C_GENERAL;
108   m.severity = MSG_S_ERROR;
109   m.file_name = NULL;
110   m.first_line = 0;
111   m.last_line = 0;
112   m.first_column = 0;
113   m.last_column = 0;
114   m.text = ds_cstr (&text);
115
116   msg_emit (&m);
117
118   r->ok = false;
119
120   longjmp (r->bail_out, 1);
121 }
122
123 /* Displays MSG as an warning for the current position in
124    portable file reader R. */
125 static void
126 warning (struct pfm_reader *r, const char *msg, ...)
127 {
128   struct msg m;
129   struct string text;
130   va_list args;
131
132   ds_init_empty (&text);
133   ds_put_format (&text, _("reading portable file %s at offset 0x%llx: "),
134                  fh_get_file_name (r->fh), (long long int) ftello (r->file));
135   va_start (args, msg);
136   ds_put_vformat (&text, msg, args);
137   va_end (args);
138
139   m.category = MSG_C_GENERAL;
140   m.severity = MSG_S_WARNING;
141   m.file_name = NULL;
142   m.first_line = 0;
143   m.last_line = 0;
144   m.first_column = 0;
145   m.last_column = 0;
146   m.text = ds_cstr (&text);
147
148   msg_emit (&m);
149 }
150
151 /* Close and destroy R.
152    Returns false if an error was detected on R, true otherwise. */
153 static bool
154 close_reader (struct pfm_reader *r)
155 {
156   bool ok;
157   if (r == NULL)
158     return true;
159
160   if (r->file)
161     {
162       if (fn_close (fh_get_file_name (r->fh), r->file) == EOF)
163         {
164           msg (ME, _("Error closing portable file `%s': %s."),
165                fh_get_file_name (r->fh), strerror (errno));
166           r->ok = false;
167         }
168       r->file = NULL;
169     }
170
171   fh_unlock (r->lock);
172   fh_unref (r->fh);
173
174   ok = r->ok;
175   pool_destroy (r->pool);
176
177   return ok;
178 }
179
180 /* Closes portable file reader R, after we're done with it. */
181 static void
182 por_file_casereader_destroy (struct casereader *reader, void *r_)
183 {
184   struct pfm_reader *r = r_;
185   if (!close_reader (r))
186     casereader_force_error (reader);
187 }
188
189 /* Read a single character into cur_char.  */
190 static void
191 advance (struct pfm_reader *r)
192 {
193   int c;
194
195   /* Read the next character from the file.
196      Ignore carriage returns entirely.
197      Mostly ignore new-lines, but if a new-line occurs before the
198      line has reached 80 bytes in length, then treat the
199      "missing" bytes as spaces. */
200   for (;;)
201     {
202       while ((c = getc (r->file)) == '\r')
203         continue;
204       if (c != '\n')
205         break;
206
207       if (r->line_length < 80)
208         {
209           c = ' ';
210           ungetc ('\n', r->file);
211           break;
212         }
213       r->line_length = 0;
214     }
215   if (c == EOF)
216     error (r, _("unexpected end of file"));
217
218   if (r->trans != NULL)
219     c = r->trans[c];
220   r->cc = c;
221   r->line_length++;
222 }
223
224 /* Skip a single character if present, and return whether it was
225    skipped. */
226 static inline bool
227 match (struct pfm_reader *r, int c)
228 {
229   if (r->cc == c)
230     {
231       advance (r);
232       return true;
233     }
234   else
235     return false;
236 }
237
238 static void read_header (struct pfm_reader *);
239 static void read_version_data (struct pfm_reader *, struct pfm_read_info *);
240 static void read_variables (struct pfm_reader *, struct dictionary *);
241 static void read_value_label (struct pfm_reader *, struct dictionary *);
242 static void read_documents (struct pfm_reader *, struct dictionary *);
243
244 /* Reads the dictionary from file with handle H, and returns it in a
245    dictionary structure.  This dictionary may be modified in order to
246    rename, reorder, and delete variables, etc. */
247 struct casereader *
248 pfm_open_reader (struct file_handle *fh, struct dictionary **dict,
249                  struct pfm_read_info *info)
250 {
251   struct pool *volatile pool = NULL;
252   struct pfm_reader *volatile r = NULL;
253
254   *dict = dict_create (get_default_encoding ());
255
256   /* Create and initialize reader. */
257   pool = pool_create ();
258   r = pool_alloc (pool, sizeof *r);
259   r->pool = pool;
260   r->fh = fh_ref (fh);
261   r->lock = NULL;
262   r->file = NULL;
263   r->line_length = 0;
264   r->weight_index = -1;
265   r->trans = NULL;
266   r->var_cnt = 0;
267   r->proto = NULL;
268   r->ok = true;
269   if (setjmp (r->bail_out))
270     goto error;
271
272   /* Lock file. */
273   /* TRANSLATORS: this fragment will be interpolated into
274      messages in fh_lock() that identify types of files. */
275   r->lock = fh_lock (fh, FH_REF_FILE, N_("portable file"), FH_ACC_READ, false);
276   if (r->lock == NULL)
277     goto error;
278
279   /* Open file. */
280   r->file = fn_open (fh_get_file_name (r->fh), "rb");
281   if (r->file == NULL)
282     {
283       msg (ME, _("An error occurred while opening `%s' for reading "
284                  "as a portable file: %s."),
285            fh_get_file_name (r->fh), strerror (errno));
286       goto error;
287     }
288
289   /* Read header, version, date info, product id, variables. */
290   read_header (r);
291   read_version_data (r, info);
292   read_variables (r, *dict);
293
294   /* Read value labels. */
295   while (match (r, 'D'))
296     read_value_label (r, *dict);
297
298   /* Read documents. */
299   if (match (r, 'E'))
300     read_documents (r, *dict);
301
302   /* Check that we've made it to the data. */
303   if (!match (r, 'F'))
304     error (r, _("Data record expected."));
305
306   r->proto = caseproto_ref_pool (dict_get_proto (*dict), r->pool);
307   return casereader_create_sequential (NULL, r->proto, CASENUMBER_MAX,
308                                        &por_file_casereader_class, r);
309
310  error:
311   close_reader (r);
312   dict_destroy (*dict);
313   *dict = NULL;
314   return NULL;
315 }
316 \f
317 /* Returns the value of base-30 digit C,
318    or -1 if C is not a base-30 digit. */
319 static int
320 base_30_value (unsigned char c)
321 {
322   static const char base_30_digits[] = "0123456789ABCDEFGHIJKLMNOPQRST";
323   const char *p = strchr (base_30_digits, c);
324   return p != NULL ? p - base_30_digits : -1;
325 }
326
327 /* Read a floating point value and return its value. */
328 static double
329 read_float (struct pfm_reader *r)
330 {
331   double num = 0.;
332   int exponent = 0;
333   bool got_dot = false;         /* Seen a decimal point? */
334   bool got_digit = false;       /* Seen any digits? */
335   bool negative = false;        /* Number is negative? */
336
337   /* Skip leading spaces. */
338   while (match (r, ' '))
339     continue;
340
341   /* `*' indicates system-missing. */
342   if (match (r, '*'))
343     {
344       advance (r);      /* Probably a dot (.) but doesn't appear to matter. */
345       return SYSMIS;
346     }
347
348   negative = match (r, '-');
349   for (;;)
350     {
351       int digit = base_30_value (r->cc);
352       if (digit != -1)
353         {
354           got_digit = true;
355
356           /* Make sure that multiplication by 30 will not overflow.  */
357           if (num > DBL_MAX * (1. / 30.))
358             /* The value of the digit doesn't matter, since we have already
359                gotten as many digits as can be represented in a `double'.
360                This doesn't necessarily mean the result will overflow.
361                The exponent may reduce it to within range.
362
363                We just need to record that there was another
364                digit so that we can multiply by 10 later.  */
365             ++exponent;
366           else
367             num = (num * 30.0) + digit;
368
369           /* Keep track of the number of digits after the decimal point.
370              If we just divided by 30 here, we would lose precision.  */
371           if (got_dot)
372             --exponent;
373         }
374       else if (!got_dot && r->cc == '.')
375         /* Record that we have found the decimal point.  */
376         got_dot = 1;
377       else
378         /* Any other character terminates the number.  */
379         break;
380
381       advance (r);
382     }
383
384   /* Check that we had some digits. */
385   if (!got_digit)
386     error (r, _("Number expected."));
387
388   /* Get exponent if any. */
389   if (r->cc == '+' || r->cc == '-')
390     {
391       long int exp = 0;
392       bool negative_exponent = r->cc == '-';
393       int digit;
394
395       for (advance (r); (digit = base_30_value (r->cc)) != -1; advance (r))
396         {
397           if (exp > LONG_MAX / 30)
398             {
399               exp = LONG_MAX;
400               break;
401             }
402           exp = exp * 30 + digit;
403         }
404
405       /* We don't check whether there were actually any digits, but we
406          probably should. */
407       if (negative_exponent)
408         exp = -exp;
409       exponent += exp;
410     }
411
412   /* Numbers must end with `/'. */
413   if (!match (r, '/'))
414     error (r, _("Missing numeric terminator."));
415
416   /* Multiply `num' by 30 to the `exponent' power, checking for
417      overflow.  */
418   if (exponent < 0)
419     num *= pow (30.0, (double) exponent);
420   else if (exponent > 0)
421     {
422       if (num > DBL_MAX * pow (30.0, (double) -exponent))
423         num = DBL_MAX;
424       else
425         num *= pow (30.0, (double) exponent);
426     }
427
428   return negative ? -num : num;
429 }
430
431 /* Read an integer and return its value. */
432 static int
433 read_int (struct pfm_reader *r)
434 {
435   double f = read_float (r);
436   if (floor (f) != f || f >= INT_MAX || f <= INT_MIN)
437     error (r, _("Invalid integer."));
438   return f;
439 }
440
441 /* Reads a string into BUF, which must have room for 256
442    characters. */
443 static void
444 read_string (struct pfm_reader *r, char *buf)
445 {
446   int n = read_int (r);
447   if (n < 0 || n > 255)
448     error (r, _("Bad string length %d."), n);
449
450   while (n-- > 0)
451     {
452       *buf++ = r->cc;
453       advance (r);
454     }
455   *buf = '\0';
456 }
457
458
459 /* Reads a string into BUF, which must have room for 256
460    characters.
461    Returns the number of bytes read.
462 */
463 static size_t
464 read_bytes (struct pfm_reader *r, uint8_t *buf)
465 {
466   int n = read_int (r);
467   if (n < 0 || n > 255)
468     error (r, _("Bad string length %d."), n);
469
470   while (n-- > 0)
471     {
472       *buf++ = r->cc;
473       advance (r);
474     }
475   return n;
476 }
477
478
479
480 /* Reads a string and returns a copy of it allocated from R's
481    pool. */
482 static char *
483 read_pool_string (struct pfm_reader *r)
484 {
485   char string[256];
486   read_string (r, string);
487   return pool_strdup (r->pool, string);
488 }
489 \f
490 /* Reads the 464-byte file header. */
491 static void
492 read_header (struct pfm_reader *r)
493 {
494   char *trans;
495   int i;
496
497   /* Read and ignore vanity splash strings. */
498   for (i = 0; i < 200; i++)
499     advance (r);
500
501   /* Skip the first 64 characters of the translation table.
502      We don't care about these.  They are probably all set to
503      '0', marking them as untranslatable, and that would screw
504      up our actual translation of the real '0'. */
505   for (i = 0; i < 64; i++)
506     advance (r);
507
508   /* Read the rest of the translation table. */
509   trans = pool_malloc (r->pool, 256);
510   memset (trans, 0, 256);
511   for (; i < 256; i++)
512     {
513       unsigned char c;
514
515       advance (r);
516
517       c = r->cc;
518       if (trans[c] == 0)
519         trans[c] = portable_to_local[i];
520     }
521
522   /* Set up the translation table, then read the first
523      translated character. */
524   r->trans = trans;
525   advance (r);
526
527   /* Skip and verify signature. */
528   for (i = 0; i < 8; i++)
529     if (!match (r, "SPSSPORT"[i]))
530       {
531         msg (SE, _("%s: Not a portable file."), fh_get_file_name (r->fh));
532         longjmp (r->bail_out, 1);
533       }
534 }
535
536 /* Reads the version and date info record, as well as product and
537    subproduct identification records if present. */
538 static void
539 read_version_data (struct pfm_reader *r, struct pfm_read_info *info)
540 {
541   static const char empty_string[] = "";
542   char *date, *time;
543   const char *product, *subproduct;
544   int i;
545
546   /* Read file. */
547   if (!match (r, 'A'))
548     error (r, _("Unrecognized version code `%c'."), r->cc);
549   date = read_pool_string (r);
550   time = read_pool_string (r);
551   product = match (r, '1') ? read_pool_string (r) : empty_string;
552   if (match (r, '2'))
553     {
554       /* Skip "author" field. */
555       read_pool_string (r);
556     }
557   subproduct = match (r, '3') ? read_pool_string (r) : empty_string;
558
559   /* Validate file. */
560   if (strlen (date) != 8)
561     error (r, _("Bad date string length %zu."), strlen (date));
562   if (strlen (time) != 6)
563     error (r, _("Bad time string length %zu."), strlen (time));
564
565   /* Save file info. */
566   if (info != NULL)
567     {
568       /* Date. */
569       for (i = 0; i < 8; i++)
570         {
571           static const int map[] = {6, 7, 8, 9, 3, 4, 0, 1};
572           info->creation_date[map[i]] = date[i];
573         }
574       info->creation_date[2] = info->creation_date[5] = ' ';
575       info->creation_date[10] = 0;
576
577       /* Time. */
578       for (i = 0; i < 6; i++)
579         {
580           static const int map[] = {0, 1, 3, 4, 6, 7};
581           info->creation_time[map[i]] = time[i];
582         }
583       info->creation_time[2] = info->creation_time[5] = ' ';
584       info->creation_time[8] = 0;
585
586       /* Product. */
587       str_copy_trunc (info->product, sizeof info->product, product);
588       str_copy_trunc (info->subproduct, sizeof info->subproduct, subproduct);
589     }
590 }
591
592 /* Translates a format specification read from portable file R as
593    the three integers INTS into a normal format specifier FORMAT,
594    checking that the format is appropriate for variable V. */
595 static struct fmt_spec
596 convert_format (struct pfm_reader *r, const int portable_format[3],
597                 struct variable *v, bool *report_error)
598 {
599   struct fmt_spec format;
600   bool ok;
601
602   if (!fmt_from_io (portable_format[0], &format.type))
603     {
604       if (*report_error)
605         warning (r, _("%s: Bad format specifier byte (%d).  Variable "
606                       "will be assigned a default format."),
607                  var_get_name (v), portable_format[0]);
608       goto assign_default;
609     }
610
611   format.w = portable_format[1];
612   format.d = portable_format[2];
613
614   msg_disable ();
615   ok = (fmt_check_output (&format)
616         && fmt_check_width_compat (&format, var_get_width (v)));
617   msg_enable ();
618
619   if (!ok)
620     {
621       if (*report_error)
622         {
623           char fmt_string[FMT_STRING_LEN_MAX + 1];
624           fmt_to_string (&format, fmt_string);
625           if (var_is_numeric (v))
626             warning (r, _("Numeric variable %s has invalid format "
627                           "specifier %s."),
628                      var_get_name (v), fmt_string);
629           else
630             warning (r, _("String variable %s with width %d has "
631                           "invalid format specifier %s."),
632                      var_get_name (v), var_get_width (v), fmt_string);
633         }
634       goto assign_default;
635     }
636
637   return format;
638
639 assign_default:
640   *report_error = false;
641   return fmt_default_for_width (var_get_width (v));
642 }
643
644 static void parse_value (struct pfm_reader *, int width, union value *);
645
646 /* Read information on all the variables.  */
647 static void
648 read_variables (struct pfm_reader *r, struct dictionary *dict)
649 {
650   char *weight_name = NULL;
651   int i;
652
653   if (!match (r, '4'))
654     error (r, _("Expected variable count record."));
655
656   r->var_cnt = read_int (r);
657   if (r->var_cnt <= 0)
658     error (r, _("Invalid number of variables %d."), r->var_cnt);
659
660   if (match (r, '5'))
661     read_int (r);
662
663   if (match (r, '6'))
664     {
665       weight_name = read_pool_string (r);
666       if (strlen (weight_name) > SHORT_NAME_LEN)
667         error (r, _("Weight variable name (%s) truncated."), weight_name);
668     }
669
670   for (i = 0; i < r->var_cnt; i++)
671     {
672       int width;
673       char name[256];
674       int fmt[6];
675       struct variable *v;
676       struct missing_values miss;
677       struct fmt_spec print, write;
678       bool report_error = true;
679       int j;
680
681       if (!match (r, '7'))
682         error (r, _("Expected variable record."));
683
684       width = read_int (r);
685       if (width < 0)
686         error (r, _("Invalid variable width %d."), width);
687
688       read_string (r, name);
689       for (j = 0; j < 6; j++)
690         fmt[j] = read_int (r);
691
692       if (!dict_id_is_valid (dict, name, false)
693           || *name == '#' || *name == '$')
694         error (r, _("Invalid variable name `%s' in position %d."), name, i);
695       str_uppercase (name);
696
697       if (width < 0 || width > 255)
698         error (r, _("Bad width %d for variable %s."), width, name);
699
700       v = dict_create_var (dict, name, width);
701       if (v == NULL)
702         {
703           unsigned long int i;
704           for (i = 1; ; i++)
705             {
706               char try_name[8 + 1 + INT_STRLEN_BOUND (i) + 1];
707               sprintf (try_name, "%s_%lu", name, i);
708               v = dict_create_var (dict, try_name, width);
709               if (v != NULL)
710                 break;
711             }
712           warning (r, _("Duplicate variable name %s in position %d renamed "
713                         "to %s."), name, i, var_get_name (v));
714         }
715
716       print = convert_format (r, &fmt[0], v, &report_error);
717       write = convert_format (r, &fmt[3], v, &report_error);
718       var_set_print_format (v, &print);
719       var_set_write_format (v, &write);
720
721       /* Range missing values. */
722       mv_init (&miss, width);
723       if (match (r, 'B'))
724         {
725           double x = read_float (r);
726           double y = read_float (r);
727           mv_add_range (&miss, x, y);
728         }
729       else if (match (r, 'A'))
730         mv_add_range (&miss, read_float (r), HIGHEST);
731       else if (match (r, '9'))
732         mv_add_range (&miss, LOWEST, read_float (r));
733
734       /* Single missing values. */
735       while (match (r, '8'))
736         {
737           int mv_width = MIN (width, 8);
738           union value value;
739
740           parse_value (r, mv_width, &value);
741           value_resize (&value, mv_width, width);
742           mv_add_value (&miss, &value);
743           value_destroy (&value, width);
744         }
745
746       var_set_missing_values (v, &miss);
747       mv_destroy (&miss);
748
749       if (match (r, 'C'))
750         {
751           char label[256];
752           read_string (r, label);
753           var_set_label (v, label, false); /* XXX */
754         }
755     }
756
757   if (weight_name != NULL)
758     {
759       struct variable *weight_var = dict_lookup_var (dict, weight_name);
760       if (weight_var == NULL)
761         error (r, _("Weighting variable %s not present in dictionary."),
762                weight_name);
763
764       dict_set_weight (dict, weight_var);
765     }
766 }
767
768 /* Parse a value of with WIDTH into value V. */
769 static void
770 parse_value (struct pfm_reader *r, int width, union value *v)
771 {
772   value_init (v, width);
773   if (width > 0)
774     {
775       uint8_t buf[256];
776       size_t n_bytes = read_bytes (r, buf);
777       value_copy_buf_rpad (v, width, buf, n_bytes, ' ');
778     }
779   else
780     v->f = read_float (r);
781 }
782
783 /* Parse a value label record and return success. */
784 static void
785 read_value_label (struct pfm_reader *r, struct dictionary *dict)
786 {
787   /* Variables. */
788   int nv;
789   struct variable **v;
790
791   /* Labels. */
792   int n_labels;
793
794   int i;
795
796   nv = read_int (r);
797   v = pool_nalloc (r->pool, nv, sizeof *v);
798   for (i = 0; i < nv; i++)
799     {
800       char name[256];
801       read_string (r, name);
802
803       v[i] = dict_lookup_var (dict, name);
804       if (v[i] == NULL)
805         error (r, _("Unknown variable %s while parsing value labels."), name);
806
807       if (var_get_type (v[0]) != var_get_type (v[i]))
808         error (r, _("Cannot assign value labels to %s and %s, which "
809                     "have different variable types."),
810                var_get_name (v[0]), var_get_name (v[i]));
811     }
812
813   n_labels = read_int (r);
814   for (i = 0; i < n_labels; i++)
815     {
816       union value val;
817       char label[256];
818       int j;
819
820       parse_value (r, var_get_width (v[0]), &val);
821       read_string (r, label);
822
823       /* Assign the value label to each variable. */
824       for (j = 0; j < nv; j++)
825         var_replace_value_label (v[j], &val, label);
826
827       value_destroy (&val, var_get_width (v[0]));
828     }
829 }
830
831 /* Reads a set of documents from portable file R into DICT. */
832 static void
833 read_documents (struct pfm_reader *r, struct dictionary *dict)
834 {
835   int line_cnt;
836   int i;
837
838   line_cnt = read_int (r);
839   for (i = 0; i < line_cnt; i++)
840     {
841       char line[256];
842       read_string (r, line);
843       dict_add_document_line (dict, line, false);
844     }
845 }
846
847 /* Reads and returns one case from portable file R.  Returns a
848    null pointer on failure. */
849 static struct ccase *
850 por_file_casereader_read (struct casereader *reader, void *r_)
851 {
852   struct pfm_reader *r = r_;
853   struct ccase *volatile c;
854   size_t i;
855
856   c = case_create (r->proto);
857   setjmp (r->bail_out);
858   if (!r->ok)
859     {
860       casereader_force_error (reader);
861       case_unref (c);
862       return NULL;
863     }
864
865   /* Check for end of file. */
866   if (r->cc == 'Z')
867     {
868       case_unref (c);
869       return NULL;
870     }
871
872   for (i = 0; i < r->var_cnt; i++)
873     {
874       int width = caseproto_get_width (r->proto, i);
875
876       if (width == 0)
877         case_data_rw_idx (c, i)->f = read_float (r);
878       else
879         {
880           uint8_t buf[256];
881           size_t n_bytes = read_bytes (r, buf);
882           u8_buf_copy_rpad (case_str_rw_idx (c, i), width, buf, n_bytes, ' ');
883         }
884     }
885
886   return c;
887 }
888
889 /* Returns true if FILE is an SPSS portable file,
890    false otherwise. */
891 bool
892 pfm_detect (FILE *file)
893 {
894   unsigned char header[464];
895   char trans[256];
896   int cooked_cnt, raw_cnt, line_len;
897   int i;
898
899   cooked_cnt = raw_cnt = 0;
900   line_len = 0;
901   while (cooked_cnt < sizeof header)
902     {
903       int c = getc (file);
904       if (c == EOF || raw_cnt++ > 512)
905         return false;
906       else if (c == '\n')
907         {
908           while (line_len < 80 && cooked_cnt < sizeof header)
909             {
910               header[cooked_cnt++] = ' ';
911               line_len++;
912             }
913           line_len = 0;
914         }
915       else if (c != '\r')
916         {
917           header[cooked_cnt++] = c;
918           line_len++;
919         }
920     }
921
922   memset (trans, 0, 256);
923   for (i = 64; i < 256; i++)
924     {
925       unsigned char c = header[i + 200];
926       if (trans[c] == 0)
927         trans[c] = portable_to_local[i];
928     }
929
930   for (i = 0; i < 8; i++)
931     if (trans[header[i + 456]] != "SPSSPORT"[i])
932       return false;
933
934   return true;
935 }
936
937 static const struct casereader_class por_file_casereader_class =
938   {
939     por_file_casereader_read,
940     por_file_casereader_destroy,
941     NULL,
942     NULL,
943   };