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