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