Fix memory leaks.
[pspp] / src / pfm-read.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3    Written by Ben Pfaff <blp@gnu.org>.
4
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., 59 Temple Place - Suite 330, Boston, MA
18    02111-1307, USA. */
19
20 #include <config.h>
21 #include "pfm.h"
22 #include "error.h"
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <ctype.h>
27 #include <errno.h>
28 #include <math.h>
29 #include "alloc.h"
30 #include "case.h"
31 #include "file-handle.h"
32 #include "format.h"
33 #include "getline.h"
34 #include "hash.h"
35 #include "magic.h"
36 #include "misc.h"
37 #include "str.h"
38 #include "value-labels.h"
39 #include "var.h"
40
41 #include "debug-print.h"
42
43 /* pfm's file_handle extension. */
44 struct pfm_fhuser_ext
45   {
46     FILE *file;                 /* Actual file. */
47
48     struct dictionary *dict;    /* File's dictionary. */
49     int weight_index;           /* 0-based index of weight variable, or -1. */
50
51     unsigned char *trans;       /* 256-byte character set translation table. */
52
53     int nvars;                  /* Number of variables. */
54     int *vars;                  /* Variable widths, 0 for numeric. */
55     int case_size;              /* Number of `value's per case. */
56
57     unsigned char buf[83];      /* Input buffer. */
58     unsigned char *bp;          /* Buffer pointer. */
59     int cc;                     /* Current character. */
60   };
61
62 static struct fh_ext_class pfm_r_class;
63
64 static int 
65 corrupt_msg (struct file_handle *h, const char *format,...)
66      PRINTF_FORMAT (2, 3);
67
68 /* Displays a corruption error. */
69 static int
70 corrupt_msg (struct file_handle *h, const char *format, ...)
71 {
72   struct pfm_fhuser_ext *ext = h->ext;
73   char buf[1024];
74   
75   {
76     va_list args;
77
78     va_start (args, format);
79     vsnprintf (buf, 1024, format, args);
80     va_end (args);
81   }
82   
83   {
84     char *title;
85     struct error e;
86     const char *filename;
87
88     e.class = ME;
89     getl_location (&e.where.filename, &e.where.line_number);
90     filename = handle_get_filename (h);
91     e.title = title = local_alloc (strlen (filename) + 80);
92     sprintf (title, _("portable file %s corrupt at offset %ld: "),
93              filename, ftell (ext->file) - (82 - (long) (ext->bp - ext->buf)));
94     e.text = buf;
95
96     err_vmsg (&e);
97
98     local_free (title);
99   }
100   
101   return 0;
102 }
103
104 /* Closes a portable file after we're done with it. */
105 static void
106 pfm_close (struct file_handle *h)
107 {
108   struct pfm_fhuser_ext *ext = h->ext;
109
110   if (EOF == fclose (ext->file))
111     msg (ME, _("%s: Closing portable file: %s."),
112          handle_get_filename (h), strerror (errno));
113   free (ext->vars);
114   free (ext->trans);
115   free (h->ext);
116 }
117
118 /* Displays the message X with corrupt_msg, then jumps to the lossage
119    label. */
120 #define lose(X)                                 \
121         do                                      \
122           {                                     \
123             corrupt_msg X;                      \
124             goto lossage;                       \
125           }                                     \
126         while (0)
127
128 /* Read an 80-character line into handle H's buffer.  Return
129    success. */
130 static int
131 fill_buf (struct file_handle *h)
132 {
133   struct pfm_fhuser_ext *ext = h->ext;
134
135   if (80 != fread (ext->buf, 1, 80, ext->file))
136     lose ((h, _("Unexpected end of file.")));
137
138   /* PORTME: line ends. */
139   {
140     int c;
141     
142     c = getc (ext->file);
143     if (c != '\n' && c != '\r')
144       lose ((h, _("Bad line end.")));
145
146     c = getc (ext->file);
147     if (c != '\n' && c != '\r')
148       ungetc (c, ext->file);
149   }
150   
151   if (ext->trans)
152     {
153       int i;
154       
155       for (i = 0; i < 80; i++)
156         ext->buf[i] = ext->trans[ext->buf[i]];
157     }
158
159   ext->bp = ext->buf;
160
161   return 1;
162
163  lossage:
164   return 0;
165 }
166
167 /* Read a single character into cur_char.  Return success; */
168 static int
169 read_char (struct file_handle *h)
170 {
171   struct pfm_fhuser_ext *ext = h->ext;
172
173   if (ext->bp >= &ext->buf[80] && !fill_buf (h))
174     return 0;
175   ext->cc = *ext->bp++;
176   return 1;
177 }
178
179 /* Advance a single character. */
180 #define advance() if (!read_char (h)) goto lossage
181
182 /* Skip a single character if present, and return whether it was
183    skipped. */
184 static inline int
185 skip_char (struct file_handle *h, int c)
186 {
187   struct pfm_fhuser_ext *ext = h->ext;
188   
189   if (ext->cc == c)
190     {
191       advance ();
192       return 1;
193     }
194  lossage:
195   return 0;
196 }
197
198 /* Skip a single character if present, and return whether it was
199    skipped. */
200 #define match(C) skip_char (h, C)
201
202 static int read_header (struct file_handle *h);
203 static int read_version_data (struct file_handle *h, struct pfm_read_info *inf);
204 static int read_variables (struct file_handle *h);
205 static int read_value_label (struct file_handle *h);
206 void dump_dictionary (struct dictionary *dict);
207
208 /* Reads the dictionary from file with handle H, and returns it in a
209    dictionary structure.  This dictionary may be modified in order to
210    rename, reorder, and delete variables, etc. */
211 struct dictionary *
212 pfm_read_dictionary (struct file_handle *h, struct pfm_read_info *inf)
213 {
214   /* The file handle extension record. */
215   struct pfm_fhuser_ext *ext;
216
217   /* Check whether the file is already open. */
218   if (h->class == &pfm_r_class)
219     {
220       ext = h->ext;
221       return ext->dict;
222     }
223   else if (h->class != NULL)
224     {
225       msg (ME, _("Cannot read file %s as portable file: already opened "
226                  "for %s."),
227            handle_get_name (h), h->class->name);
228       return NULL;
229     }
230
231   msg (VM (1), _("%s: Opening portable-file handle %s for reading."),
232        handle_get_filename (h), handle_get_name (h));
233
234   /* Open the physical disk file. */
235   ext = xmalloc (sizeof (struct pfm_fhuser_ext));
236   ext->file = fopen (handle_get_filename (h), "rb");
237   if (ext->file == NULL)
238     {
239       msg (ME, _("An error occurred while opening \"%s\" for reading "
240                  "as a portable file: %s."),
241            handle_get_filename (h), strerror (errno));
242       err_cond_fail ();
243       free (ext);
244       return NULL;
245     }
246
247   /* Initialize the sfm_fhuser_ext structure. */
248   h->class = &pfm_r_class;
249   h->ext = ext;
250   ext->dict = NULL;
251   ext->trans = NULL;
252   if (!fill_buf (h))
253     goto lossage;
254   advance ();
255
256   /* Read the header. */
257   if (!read_header (h))
258     goto lossage;
259   
260   /* Read version, date info, product identification. */
261   if (!read_version_data (h, inf))
262     goto lossage;
263
264   /* Read variables. */
265   if (!read_variables (h))
266     goto lossage;
267
268   /* Value labels. */
269   while (match (77 /* D */))
270     if (!read_value_label (h))
271       goto lossage;
272
273   if (!match (79 /* F */))
274     lose ((h, _("Data record expected.")));
275
276   msg (VM (2), _("Read portable-file dictionary successfully."));
277
278   return ext->dict;
279
280  lossage:
281   /* Come here on unsuccessful completion. */
282   msg (VM (1), _("Error reading portable-file dictionary."));
283   
284   fclose (ext->file);
285   if (ext && ext->dict)
286     dict_destroy (ext->dict);
287   free (ext);
288   h->class = NULL;
289   h->ext = NULL;
290   return NULL;
291 }
292 \f
293 /* Read a floating point value and return its value, or
294    second_lowest_value on error. */
295 static double
296 read_float (struct file_handle *h)
297 {
298   struct pfm_fhuser_ext *ext = h->ext;                        
299   double num = 0.;
300   int got_dot = 0;
301   int got_digit = 0;
302   int exponent = 0;
303   int neg = 0;
304
305   /* Skip leading spaces. */
306   while (match (126 /* space */))
307     ;
308
309   if (match (137 /* * */))
310     {
311       advance ();       /* Probably a dot (.) but doesn't appear to matter. */
312       return SYSMIS;
313     }
314   else if (match (141 /* - */))
315     neg = 1;
316
317   for (;;)
318     {
319       if (ext->cc >= 64 /* 0 */ && ext->cc <= 93 /* T */)
320         {
321           got_digit++;
322
323           /* Make sure that multiplication by 30 will not overflow.  */
324           if (num > DBL_MAX * (1. / 30.))
325             /* The value of the digit doesn't matter, since we have already
326                gotten as many digits as can be represented in a `double'.
327                This doesn't necessarily mean the result will overflow.
328                The exponent may reduce it to within range.
329
330                We just need to record that there was another
331                digit so that we can multiply by 10 later.  */
332             ++exponent;
333           else
334             num = (num * 30.0) + (ext->cc - 64);
335
336           /* Keep track of the number of digits after the decimal point.
337              If we just divided by 30 here, we would lose precision.  */
338           if (got_dot)
339             --exponent;
340         }
341       else if (!got_dot && ext->cc == 127 /* . */)
342         /* Record that we have found the decimal point.  */
343         got_dot = 1;
344       else
345         /* Any other character terminates the number.  */
346         break;
347
348       advance ();
349     }
350
351   if (!got_digit)
352     lose ((h, "Number expected."));
353       
354   if (ext->cc == 130 /* + */ || ext->cc == 141 /* - */)
355     {
356       /* Get the exponent.  */
357       long int exp = 0;
358       int neg_exp = ext->cc == 141 /* - */;
359
360       for (;;)
361         {
362           advance ();
363
364           if (ext->cc < 64 /* 0 */ || ext->cc > 93 /* T */)
365             break;
366
367           if (exp > LONG_MAX / 30)
368             goto overflow;
369           exp = exp * 30 + (ext->cc - 64);
370         }
371
372       /* We don't check whether there were actually any digits, but we
373          probably should. */
374       if (neg_exp)
375         exp = -exp;
376       exponent += exp;
377     }
378   
379   if (!match (142 /* / */))
380     lose ((h, _("Missing numeric terminator.")));
381
382   /* Multiply NUM by 30 to the EXPONENT power, checking for overflow.  */
383
384   if (exponent < 0)
385     num *= pow (30.0, (double) exponent);
386   else if (exponent > 0)
387     {
388       if (num > DBL_MAX * pow (30.0, (double) -exponent))
389         goto overflow;
390       num *= pow (30.0, (double) exponent);
391     }
392
393   if (neg)
394     return -num;
395   else
396     return num;
397
398  overflow:
399   if (neg)
400     return -DBL_MAX / 10.;
401   else
402     return DBL_MAX / 10;
403
404  lossage:
405   return second_lowest_value;
406 }
407   
408 /* Read an integer and return its value, or NOT_INT on failure. */
409 static int
410 read_int (struct file_handle *h)
411 {
412   double f = read_float (h);
413
414   if (f == second_lowest_value)
415     goto lossage;
416   if (floor (f) != f || f >= INT_MAX || f <= INT_MIN)
417     lose ((h, _("Bad integer format.")));
418   return f;
419
420  lossage:
421   return NOT_INT;
422 }
423
424 /* Reads a string and returns its value in a static buffer, or NULL on
425    failure.  The buffer can be deallocated by calling with a NULL
426    argument. */
427 static unsigned char *
428 read_string (struct file_handle *h)
429 {
430   struct pfm_fhuser_ext *ext = h->ext;
431   static char *buf;
432   int n;
433   
434   if (h == NULL)
435     {
436       free (buf);
437       buf = NULL;
438       return NULL;
439     }
440   else if (buf == NULL)
441     buf = xmalloc (256);
442
443   n = read_int (h);
444   if (n == NOT_INT)
445     return NULL;
446   if (n < 0 || n > 255)
447     lose ((h, _("Bad string length %d."), n));
448   
449   {
450     int i;
451
452     for (i = 0; i < n; i++)
453       {
454         buf[i] = ext->cc;
455         advance ();
456       }
457   }
458   
459   buf[n] = 0;
460   return buf;
461
462  lossage:
463   return NULL;
464 }
465 \f
466 /* Reads the 464-byte file header. */
467 int
468 read_header (struct file_handle *h)
469 {
470   struct pfm_fhuser_ext *ext = h->ext;
471
472   /* For now at least, just ignore the vanity splash strings. */
473   {
474     int i;
475
476     for (i = 0; i < 200; i++)
477       advance ();
478   }
479   
480   {
481     unsigned char src[256];
482     int trans_temp[256];
483     int i;
484
485     for (i = 0; i < 256; i++)
486       {
487         src[i] = (unsigned char) ext->cc;
488         advance ();
489       }
490
491     for (i = 0; i < 256; i++)
492       trans_temp[i] = -1;
493
494     /* 0 is used to mark untranslatable characters, so we have to mark
495        it specially. */
496     trans_temp[src[64]] = 64;
497     for (i = 0; i < 256; i++)
498       if (trans_temp[src[i]] == -1)
499         trans_temp[src[i]] = i;
500     
501     ext->trans = xmalloc (256);
502     for (i = 0; i < 256; i++)
503       ext->trans[i] = trans_temp[i] == -1 ? 0 : trans_temp[i];
504
505     /* Translate the input buffer. */
506     for (i = 0; i < 80; i++)
507       ext->buf[i] = ext->trans[ext->buf[i]];
508     ext->cc = ext->trans[ext->cc];
509   }
510   
511   {
512     unsigned char sig[8] = {92, 89, 92, 92, 89, 88, 91, 93};
513     int i;
514
515     for (i = 0; i < 8; i++)
516       if (!match (sig[i]))
517         lose ((h, "Missing SPSSPORT signature."));
518   }
519
520   return 1;
521
522  lossage:
523   return 0;
524 }
525
526 /* Reads the version and date info record, as well as product and
527    subproduct identification records if present. */
528 int
529 read_version_data (struct file_handle *h, struct pfm_read_info *inf)
530 {
531   struct pfm_fhuser_ext *ext = h->ext;
532
533   /* Version. */
534   if (!match (74 /* A */))
535     lose ((h, "Unrecognized version code %d.", ext->cc));
536
537   /* Date. */
538   {
539     static const int map[] = {6, 7, 8, 9, 3, 4, 0, 1};
540     char *date = read_string (h);
541     int i;
542     
543     if (!date)
544       return 0;
545     if (strlen (date) != 8)
546       lose ((h, _("Bad date string length %d."), strlen (date)));
547     for (i = 0; i < 8; i++)
548       {
549         if (date[i] < 64 /* 0 */ || date[i] > 73 /* 9 */)
550           lose ((h, _("Bad character in date.")));
551         if (inf)
552           inf->creation_date[map[i]] = date[i] - 64 /* 0 */ + '0';
553       }
554     if (inf)
555       {
556         inf->creation_date[2] = inf->creation_date[5] = ' ';
557         inf->creation_date[10] = 0;
558       }
559   }
560   
561   /* Time. */
562   {
563     static const int map[] = {0, 1, 3, 4, 6, 7};
564     char *time = read_string (h);
565     int i;
566
567     if (!time)
568       return 0;
569     if (strlen (time) != 6)
570       lose ((h, _("Bad time string length %d."), strlen (time)));
571     for (i = 0; i < 6; i++)
572       {
573         if (time[i] < 64 /* 0 */ || time[i] > 73 /* 9 */)
574           lose ((h, _("Bad character in time.")));
575         if (inf)
576           inf->creation_time[map[i]] = time[i] - 64 /* 0 */ + '0';
577       }
578     if (inf)
579       {
580         inf->creation_time[2] = inf->creation_time[5] = ' ';
581         inf->creation_time[8] = 0;
582       }
583   }
584
585   /* Product. */
586   if (match (65 /* 1 */))
587     {
588       char *product;
589       
590       product = read_string (h);
591       if (product == NULL)
592         return 0;
593       if (inf)
594         strncpy (inf->product, product, 61);
595     }
596   else if (inf)
597     inf->product[0] = 0;
598
599   /* Subproduct. */
600   if (match (67 /* 3 */))
601     {
602       char *subproduct;
603
604       subproduct = read_string (h);
605       if (subproduct == NULL)
606         return 0;
607       if (inf)
608         strncpy (inf->subproduct, subproduct, 61);
609     }
610   else if (inf)
611     inf->subproduct[0] = 0;
612   return 1;
613   
614  lossage:
615   return 0;
616 }
617
618 static int
619 convert_format (struct file_handle *h, int fmt[3], struct fmt_spec *v,
620                 struct variable *vv)
621 {
622   v->type = translate_fmt (fmt[0]);
623   if (v->type == -1)
624     lose ((h, _("%s: Bad format specifier byte (%d)."), vv->name, fmt[0]));
625   v->w = fmt[1];
626   v->d = fmt[2];
627
628   /* FIXME?  Should verify the resulting specifier more thoroughly. */
629
630   if (v->type == -1)
631     lose ((h, _("%s: Bad format specifier byte (%d)."), vv->name, fmt[0]));
632   if ((vv->type == ALPHA) ^ ((formats[v->type].cat & FCAT_STRING) != 0))
633     lose ((h, _("%s variable %s has %s format specifier %s."),
634            vv->type == ALPHA ? _("String") : _("Numeric"),
635            vv->name,
636            formats[v->type].cat & FCAT_STRING ? _("string") : _("numeric"),
637            formats[v->type].name));
638   return 1;
639
640  lossage:
641   return 0;
642 }
643
644 /* Translation table from SPSS character code to this computer's
645    native character code (which is probably ASCII). */
646 static const unsigned char spss2ascii[256] =
647   {
648     "                                                                "
649     "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ."
650     "<(+|&[]!$*);^-/|,%_>?`:$@'=\"      ~-   0123456789   -() {}\\     "
651     "                                                                "
652   };
653
654 /* Translate string S into ASCII. */
655 static void
656 asciify (char *s)
657 {
658   for (; *s; s++)
659     *s = spss2ascii[(unsigned char) *s];
660 }
661
662 static int parse_value (struct file_handle *, union value *, struct variable *);
663
664 /* Read information on all the variables.  */
665 static int
666 read_variables (struct file_handle *h)
667 {
668   struct pfm_fhuser_ext *ext = h->ext;
669   char *weight_name = NULL;
670   int i;
671   
672   if (!match (68 /* 4 */))
673     lose ((h, _("Expected variable count record.")));
674   
675   ext->nvars = read_int (h);
676   if (ext->nvars <= 0 || ext->nvars == NOT_INT)
677     lose ((h, _("Invalid number of variables %d."), ext->nvars));
678   ext->vars = xmalloc (sizeof *ext->vars * ext->nvars);
679
680   /* Purpose of this value is unknown.  It is typically 161. */
681   {
682     int x = read_int (h);
683
684     if (x == NOT_INT)
685       goto lossage;
686     if (x != 161)
687       corrupt_msg (h, _("Unexpected flag value %d."), x);
688   }
689
690   ext->dict = dict_create ();
691
692   if (match (70 /* 6 */))
693     {
694       weight_name = read_string (h);
695       if (!weight_name)
696         goto lossage;
697
698       asciify (weight_name);
699       if (strlen (weight_name) > 8) 
700         {
701           corrupt_msg (h, _("Weight variable name (%s) truncated."),
702                        weight_name);
703           weight_name[8] = '\0';
704         }
705     }
706   
707   for (i = 0; i < ext->nvars; i++)
708     {
709       int width;
710       unsigned char *name;
711       int fmt[6];
712       struct variable *v;
713       int j;
714
715       if (!match (71 /* 7 */))
716         lose ((h, _("Expected variable record.")));
717
718       width = read_int (h);
719       if (width == NOT_INT)
720         goto lossage;
721       if (width < 0)
722         lose ((h, _("Invalid variable width %d."), width));
723       ext->vars[i] = width;
724       
725       name = read_string (h);
726       if (name == NULL)
727         goto lossage;
728       for (j = 0; j < 6; j++)
729         {
730           fmt[j] = read_int (h);
731           if (fmt[j] == NOT_INT)
732             goto lossage;
733         }
734
735       /* Verify first character of variable name.
736
737          Weirdly enough, there is no # character in the SPSS portable
738          character set, so we can't check for it. */
739       if (strlen (name) > 8)
740         lose ((h, _("position %d: Variable name has %u characters."),
741                i, strlen (name)));
742       if ((name[0] < 74 /* A */ || name[0] > 125 /* Z */)
743           && name[0] != 152 /* @ */)
744         lose ((h, _("position %d: Variable name begins with invalid "
745                "character."), i));
746       if (name[0] >= 100 /* a */ && name[0] <= 125 /* z */)
747         {
748           corrupt_msg (h, _("position %d: Variable name begins with "
749                             "lowercase letter %c."),
750                        i, name[0] - 100 + 'a');
751           name[0] -= 26 /* a - A */;
752         }
753
754       /* Verify remaining characters of variable name. */
755       for (j = 1; j < (int) strlen (name); j++)
756         {
757           int c = name[j];
758
759           if (c >= 100 /* a */ && c <= 125 /* z */)
760             {
761               corrupt_msg (h, _("position %d: Variable name character %d "
762                                 "is lowercase letter %c."),
763                            i, j + 1, c - 100 + 'a');
764               name[j] -= 26 /* z - Z */;
765             }
766           else if ((c >= 64 /* 0 */ && c <= 99 /* Z */)
767                    || c == 127 /* . */ || c == 152 /* @ */
768                    || c == 136 /* $ */ || c == 146 /* _ */)
769             name[j] = c;
770           else
771             lose ((h, _("position %d: character `\\%03o' is not "
772                         "valid in a variable name."), i, c));
773         }
774
775       asciify (name);
776       if (width < 0 || width > 255)
777         lose ((h, "Bad width %d for variable %s.", width, name));
778
779       v = dict_create_var (ext->dict, name, width);
780       v->get.fv = v->fv;
781       if (v == NULL)
782         lose ((h, _("Duplicate variable name %s."), name));
783       if (!convert_format (h, &fmt[0], &v->print, v))
784         goto lossage;
785       if (!convert_format (h, &fmt[3], &v->write, v))
786         goto lossage;
787
788       /* Range missing values. */
789       if (match (75 /* B */))
790         {
791           v->miss_type = MISSING_RANGE;
792           if (!parse_value (h, &v->missing[0], v)
793               || !parse_value (h, &v->missing[1], v))
794             goto lossage;
795         }
796       else if (match (74 /* A */))
797         {
798           v->miss_type = MISSING_HIGH;
799           if (!parse_value (h, &v->missing[0], v))
800             goto lossage;
801         }
802       else if (match (73 /* 9 */))
803         {
804           v->miss_type = MISSING_LOW;
805           if (!parse_value (h, &v->missing[0], v))
806             goto lossage;
807         }
808
809       /* Single missing values. */
810       while (match (72 /* 8 */))
811         {
812           static const int map_next[MISSING_COUNT] =
813             {
814               MISSING_1, MISSING_2, MISSING_3, -1,
815               MISSING_RANGE_1, MISSING_LOW_1, MISSING_HIGH_1,
816               -1, -1, -1,
817             };
818
819           static const int map_ofs[MISSING_COUNT] = 
820             {
821               -1, 0, 1, 2, -1, -1, -1, 2, 1, 1,
822             };
823
824           v->miss_type = map_next[v->miss_type];
825           if (v->miss_type == -1)
826             lose ((h, _("Bad missing values for %s."), v->name));
827           
828           assert (map_ofs[v->miss_type] != -1);
829           if (!parse_value (h, &v->missing[map_ofs[v->miss_type]], v))
830             goto lossage;
831         }
832
833       if (match (76 /* C */))
834         {
835           char *label = read_string (h);
836           
837           if (label == NULL)
838             goto lossage;
839
840           v->label = xstrdup (label);
841           asciify (v->label);
842         }
843     }
844
845   if (weight_name != NULL) 
846     {
847       struct variable *weight_var = dict_lookup_var (ext->dict, weight_name);
848       if (weight_var == NULL)
849         lose ((h, _("Weighting variable %s not present in dictionary."),
850                weight_name));
851       free (weight_name);
852
853       dict_set_weight (ext->dict, weight_var);
854     }
855
856   return 1;
857
858  lossage:
859   free (weight_name);
860   return 0;
861 }
862
863 /* Parse a value for variable VV into value V.  Returns success. */
864 static int
865 parse_value (struct file_handle *h, union value *v, struct variable *vv)
866 {
867   if (vv->type == ALPHA)
868     {
869       char *mv = read_string (h);
870       int j;
871       
872       if (mv == NULL)
873         return 0;
874
875       strncpy (v->s, mv, 8);
876       for (j = 0; j < 8; j++)
877         if (v->s[j])
878           v->s[j] = spss2ascii[v->s[j]];
879         else
880           /* Value labels are always padded with spaces. */
881           v->s[j] = ' ';
882     }
883   else
884     {
885       v->f = read_float (h);
886       if (v->f == second_lowest_value)
887         return 0;
888     }
889
890   return 1;
891 }
892
893 /* Parse a value label record and return success. */
894 static int
895 read_value_label (struct file_handle *h)
896 {
897   struct pfm_fhuser_ext *ext = h->ext;
898
899   /* Variables. */
900   int nv;
901   struct variable **v;
902
903   /* Labels. */
904   int n_labels;
905
906   int i;
907
908   nv = read_int (h);
909   if (nv == NOT_INT)
910     return 0;
911
912   v = xmalloc (sizeof *v * nv);
913   for (i = 0; i < nv; i++)
914     {
915       char *name = read_string (h);
916       if (name == NULL)
917         goto lossage;
918       asciify (name);
919
920       v[i] = dict_lookup_var (ext->dict, name);
921       if (v[i] == NULL)
922         lose ((h, _("Unknown variable %s while parsing value labels."), name));
923
924       if (v[0]->width != v[i]->width)
925         lose ((h, _("Cannot assign value labels to %s and %s, which "
926                     "have different variable types or widths."),
927                v[0]->name, v[i]->name));
928     }
929
930   n_labels = read_int (h);
931   if (n_labels == NOT_INT)
932     goto lossage;
933
934   for (i = 0; i < n_labels; i++)
935     {
936       union value val;
937       char *label;
938
939       int j;
940       
941       if (!parse_value (h, &val, v[0]))
942         goto lossage;
943       
944       label = read_string (h);
945       if (label == NULL)
946         goto lossage;
947       asciify (label);
948
949       /* Assign the value_label's to each variable. */
950       for (j = 0; j < nv; j++)
951         {
952           struct variable *var = v[j];
953
954           if (!val_labs_replace (var->val_labs, val, label))
955             continue;
956
957           if (var->type == NUMERIC)
958             lose ((h, _("Duplicate label for value %g for variable %s."),
959                    val.f, var->name));
960           else
961             lose ((h, _("Duplicate label for value `%.*s' for variable %s."),
962                    var->width, val.s, var->name));
963         }
964     }
965   free (v);
966   return 1;
967
968  lossage:
969   free (v);
970   return 0;
971 }
972
973 /* Reads one case from portable file H into PERM
974    according to the instuctions given in associated dictionary DICT,
975    which must have the get.fv elements appropriately set.  Returns
976    nonzero only if successful. */
977 int
978 pfm_read_case (struct file_handle *h, struct ccase *perm,
979                struct dictionary *dict)
980 {
981   struct pfm_fhuser_ext *ext = h->ext;
982
983   union value *temp, *tp;
984   int i;
985
986   /* Check for end of file. */
987   if (ext->cc == 99 /* Z */)
988     return 0;
989   
990   /* The first concern is to obtain a full case relative to the data
991      file.  (Cases in the data file have no particular relationship to
992      cases in the active file.) */
993   tp = temp = local_alloc (sizeof *tp * ext->case_size);
994   for (tp = temp, i = 0; i < ext->nvars; i++)
995     if (ext->vars[i] == 0)
996       {
997         tp->f = read_float (h);
998         if (tp->f == second_lowest_value)
999           goto unexpected_eof;
1000         tp++;
1001       }
1002     else
1003       {
1004         char *s = read_string (h);
1005         if (s == NULL)
1006           goto unexpected_eof;
1007         asciify (s);
1008           
1009         st_bare_pad_copy (tp->s, s, ext->vars[i]);
1010         tp += DIV_RND_UP (ext->vars[i], MAX_SHORT_STRING);
1011       }
1012
1013   /* Translate a case in data file format to a case in active file
1014      format. */
1015   for (i = 0; i < dict_get_var_cnt (dict); i++)
1016     {
1017       struct variable *v = dict_get_var (dict, i);
1018
1019       if (v->get.fv == -1)
1020         continue;
1021       
1022       if (v->type == NUMERIC)
1023         case_data_rw (perm, v->fv)->f = temp[v->get.fv].f;
1024       else
1025         memcpy (case_data_rw (perm, v->fv)->s, &temp[v->get.fv], v->width);
1026     }
1027
1028   local_free (temp);
1029   return 1;
1030
1031  unexpected_eof:
1032   lose ((h, _("End of file midway through case.")));
1033
1034  lossage:
1035   local_free (temp);
1036   return 0;
1037 }
1038
1039 static struct fh_ext_class pfm_r_class =
1040 {
1041   5,
1042   N_("reading as a portable file"),
1043   pfm_close,
1044 };