514e7bda6bbee7905d65c42029f618bb8bab54cf
[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 "file-handle.h"
47 #include "format.h"
48 #include "getline.h"
49 #include "hash.h"
50 #include "magic.h"
51 #include "misc.h"
52 #include "pfm.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     free_dictionary (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 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   int i;
687   
688   if (!match (68 /* 4 */))
689     lose ((h, _("Expected variable count record.")));
690   
691   ext->nvars = read_int (h);
692   if (ext->nvars <= 0 || ext->nvars == NOT_INT)
693     lose ((h, _("Invalid number of variables %d."), ext->nvars));
694   ext->vars = xmalloc (sizeof *ext->vars * ext->nvars);
695
696   /* Purpose of this value is unknown.  It is typically 161. */
697   {
698     int x = read_int (h);
699
700     if (x == NOT_INT)
701       goto lossage;
702     if (x != 161)
703       corrupt_msg (h, _("Unexpected flag value %d."), x);
704   }
705
706   ext->dict = new_dictionary (0);
707
708   if (match (70 /* 6 */))
709     {
710       char *name = read_string (h);
711       if (!name)
712         goto lossage;
713
714       strcpy (ext->dict->weight_var, name);
715       asciify (ext->dict->weight_var);
716     }
717   
718   for (i = 0; i < ext->nvars; i++)
719     {
720       int width;
721       unsigned char *name;
722       int fmt[6];
723       struct variable *v;
724       int j;
725
726       if (!match (71 /* 7 */))
727         lose ((h, _("Expected variable record.")));
728
729       width = read_int (h);
730       if (width == NOT_INT)
731         goto lossage;
732       if (width < 0)
733         lose ((h, _("Invalid variable width %d."), width));
734       ext->vars[i] = width;
735       
736       name = read_string (h);
737       if (name == NULL)
738         goto lossage;
739       for (j = 0; j < 6; j++)
740         {
741           fmt[j] = read_int (h);
742           if (fmt[j] == NOT_INT)
743             goto lossage;
744         }
745
746       /* Verify first character of variable name.
747
748          Weirdly enough, there is no # character in the SPSS portable
749          character set, so we can't check for it. */
750       if (strlen (name) > 8)
751         lose ((h, _("position %d: Variable name has %u characters."),
752                i, strlen (name)));
753       if ((name[0] < 74 /* A */ || name[0] > 125 /* Z */)
754           && name[0] != 152 /* @ */)
755         lose ((h, _("position %d: Variable name begins with invalid "
756                "character."), i));
757       if (name[0] >= 100 /* a */ && name[0] <= 125 /* z */)
758         {
759           corrupt_msg (h, _("position %d: Variable name begins with "
760                             "lowercase letter %c."),
761                        i, name[0] - 100 + 'a');
762           name[0] -= 26 /* a - A */;
763         }
764
765       /* Verify remaining characters of variable name. */
766       for (j = 1; j < (int) strlen (name); j++)
767         {
768           int c = name[j];
769
770           if (c >= 100 /* a */ && c <= 125 /* z */)
771             {
772               corrupt_msg (h, _("position %d: Variable name character %d "
773                                 "is lowercase letter %c."),
774                            i, j + 1, c - 100 + 'a');
775               name[j] -= 26 /* z - Z */;
776             }
777           else if ((c >= 64 /* 0 */ && c <= 99 /* Z */)
778                    || c == 127 /* . */ || c == 152 /* @ */
779                    || c == 136 /* $ */ || c == 146 /* _ */)
780             name[j] = c;
781           else
782             lose ((h, _("position %d: character `\\%03o' is not "
783                         "valid in a variable name."), i, c));
784         }
785
786       asciify (name);
787       if (width < 0 || width > 255)
788         lose ((h, "Bad width %d for variable %s.", width, name));
789
790       v = create_variable (ext->dict, name, width ? ALPHA : NUMERIC, width);
791       v->get.fv = v->fv;
792       if (v == NULL)
793         lose ((h, _("Duplicate variable name %s."), name));
794       if (!convert_format (h, &fmt[0], &v->print, v))
795         goto lossage;
796       if (!convert_format (h, &fmt[3], &v->write, v))
797         goto lossage;
798
799       /* Range missing values. */
800       if (match (75 /* B */))
801         {
802           v->miss_type = MISSING_RANGE;
803           if (!parse_value (h, &v->missing[0], v)
804               || !parse_value (h, &v->missing[1], v))
805             goto lossage;
806         }
807       else if (match (74 /* A */))
808         {
809           v->miss_type = MISSING_HIGH;
810           if (!parse_value (h, &v->missing[0], v))
811             goto lossage;
812         }
813       else if (match (73 /* 9 */))
814         {
815           v->miss_type = MISSING_LOW;
816           if (!parse_value (h, &v->missing[0], v))
817             goto lossage;
818         }
819
820       /* Single missing values. */
821       while (match (72 /* 8 */))
822         {
823           static const int map_next[MISSING_COUNT] =
824             {
825               MISSING_1, MISSING_2, MISSING_3, -1,
826               MISSING_RANGE_1, MISSING_LOW_1, MISSING_HIGH_1,
827               -1, -1, -1,
828             };
829
830           static const int map_ofs[MISSING_COUNT] = 
831             {
832               -1, 0, 1, 2, -1, -1, -1, 2, 1, 1,
833             };
834
835           v->miss_type = map_next[v->miss_type];
836           if (v->miss_type == -1)
837             lose ((h, _("Bad missing values for %s."), v->name));
838           
839           assert (map_ofs[v->miss_type] != -1);
840           if (!parse_value (h, &v->missing[map_ofs[v->miss_type]], v))
841             goto lossage;
842         }
843
844       if (match (76 /* C */))
845         {
846           char *label = read_string (h);
847           
848           if (label == NULL)
849             goto lossage;
850
851           v->label = xstrdup (label);
852           asciify (v->label);
853         }
854     }
855   ext->case_size = ext->dict->nval;
856
857   if (ext->dict->weight_var[0] != 0
858       && !find_dict_variable (ext->dict, ext->dict->weight_var))
859     lose ((h, _("Weighting variable %s not present in dictionary."),
860            ext->dict->weight_var));
861
862   return 1;
863
864  lossage:
865   return 0;
866 }
867
868 /* Parse a value for variable VV into value V.  Returns success. */
869 static int
870 parse_value (struct file_handle *h, union value *v, struct variable *vv)
871 {
872   if (vv->type == ALPHA)
873     {
874       char *mv = read_string (h);
875       int j;
876       
877       if (mv == NULL)
878         return 0;
879
880       strncpy (v->s, mv, 8);
881       for (j = 0; j < 8; j++)
882         if (v->s[j])
883           v->s[j] = spss2ascii[v->s[j]];
884         else
885           /* Value labels are always padded with spaces. */
886           v->s[j] = ' ';
887     }
888   else
889     {
890       v->f = read_float (h);
891       if (v->f == second_lowest_value)
892         return 0;
893     }
894
895   return 1;
896 }
897
898 /* Parse a value label record and return success. */
899 static int
900 read_value_label (struct file_handle *h)
901 {
902   struct pfm_fhuser_ext *ext = h->ext;
903
904   /* Variables. */
905   int nv;
906   struct variable **v;
907
908   /* Labels. */
909   int n_labels;
910
911   int i;
912
913   nv = read_int (h);
914   if (nv == NOT_INT)
915     return 0;
916
917   v = xmalloc (sizeof *v * nv);
918   for (i = 0; i < nv; i++)
919     {
920       char *name = read_string (h);
921       if (name == NULL)
922         goto lossage;
923       asciify (name);
924
925       v[i] = find_dict_variable (ext->dict, name);
926       if (v[i] == NULL)
927         lose ((h, _("Unknown variable %s while parsing value labels."), name));
928
929       if (v[0]->width != v[i]->width)
930         lose ((h, _("Cannot assign value labels to %s and %s, which "
931                     "have different variable types or widths."),
932                v[0]->name, v[i]->name));
933     }
934
935   n_labels = read_int (h);
936   if (n_labels == NOT_INT)
937     goto lossage;
938
939   for (i = 0; i < n_labels; i++)
940     {
941       union value val;
942       char *label;
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       /* Assign the value_label's to each variable. */
955       for (j = 0; j < nv; j++)
956         {
957           struct variable *var = v[j];
958
959           if (!val_labs_replace (var->val_labs, val, label))
960             continue;
961
962           if (var->type == NUMERIC)
963             lose ((h, _("Duplicate label for value %g for variable %s."),
964                    val.f, var->name));
965           else
966             lose ((h, _("Duplicate label for value `%.*s' for variable %s."),
967                    var->width, val.s, var->name));
968         }
969     }
970   free (v);
971   return 1;
972
973  lossage:
974   free (v);
975   return 0;
976 }
977
978 /* Reads one case from portable file H into the value array PERM
979    according to the instuctions given in associated dictionary DICT,
980    which must have the get.fv elements appropriately set.  Returns
981    nonzero only if successful. */
982 int
983 pfm_read_case (struct file_handle *h, union value *perm, struct dictionary *dict)
984 {
985   struct pfm_fhuser_ext *ext = h->ext;
986
987   union value *temp, *tp;
988   int i;
989
990   /* Check for end of file. */
991   if (ext->cc == 99 /* Z */)
992     return 0;
993   
994   /* The first concern is to obtain a full case relative to the data
995      file.  (Cases in the data file have no particular relationship to
996      cases in the active file.) */
997   tp = temp = local_alloc (sizeof *tp * ext->case_size);
998   for (tp = temp, i = 0; i < ext->nvars; i++)
999     if (ext->vars[i] == 0)
1000       {
1001         tp->f = read_float (h);
1002         if (tp->f == second_lowest_value)
1003           goto unexpected_eof;
1004         tp++;
1005       }
1006     else
1007       {
1008         char *s = read_string (h);
1009         if (s == NULL)
1010           goto unexpected_eof;
1011         asciify (s);
1012           
1013         st_bare_pad_copy (tp->s, s, ext->vars[i]);
1014         tp += DIV_RND_UP (ext->vars[i], MAX_SHORT_STRING);
1015       }
1016
1017   /* Translate a case in data file format to a case in active file
1018      format. */
1019   for (i = 0; i < dict->nvar; i++)
1020     {
1021       struct variable *v = dict->var[i];
1022
1023       if (v->get.fv == -1)
1024         continue;
1025       
1026       if (v->type == NUMERIC)
1027         perm[v->fv].f = temp[v->get.fv].f;
1028       else
1029         memcpy (&perm[v->fv].s, &temp[v->get.fv], v->width);
1030     }
1031
1032   local_free (temp);
1033   return 1;
1034
1035  unexpected_eof:
1036   lose ((h, _("End of file midway through case.")));
1037
1038  lossage:
1039   local_free (temp);
1040   return 0;
1041 }
1042
1043 static struct fh_ext_class pfm_r_class =
1044 {
1045   5,
1046   N_("reading as a portable file"),
1047   pfm_close,
1048 };