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