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