Update all #include directives to the currently preferred style.
[pspp-builds.git] / src / data / por-file-reader.c
index 823361b09593aacc7eb33dae402f1fb31e798bdf..3f8ee3c9fee47601c651850ba2ce6e3195028da0 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -15,7 +15,8 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
-#include "por-file-reader.h"
+
+#include "data/por-file-reader.h"
 
 #include <ctype.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 
-#include <data/casereader-provider.h>
-#include <data/casereader.h>
-#include <data/dictionary.h>
-#include <data/file-handle-def.h>
-#include <data/file-name.h>
-#include <data/format.h>
-#include <data/missing-values.h>
-#include <data/short-names.h>
-#include <data/value-labels.h>
-#include <data/variable.h>
-#include <libpspp/compiler.h>
-#include <libpspp/hash.h>
-#include <libpspp/message.h>
-#include <libpspp/misc.h>
-#include <libpspp/pool.h>
-#include <libpspp/str.h>
-
-#include "xalloc.h"
+#include "data/casereader-provider.h"
+#include "data/casereader.h"
+#include "data/dictionary.h"
+#include "data/file-handle-def.h"
+#include "data/file-name.h"
+#include "data/format.h"
+#include "data/missing-values.h"
+#include "data/short-names.h"
+#include "data/value-labels.h"
+#include "data/variable.h"
+#include "libpspp/compiler.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/pool.h"
+#include "libpspp/str.h"
+
+#include "gl/intprops.h"
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -74,8 +76,7 @@ struct pfm_reader
     char *trans;                /* 256-byte character set translation table. */
     int var_cnt;                /* Number of variables. */
     int weight_index;          /* 0-based index of weight variable, or -1. */
-    int *widths;                /* Variable widths, 0 for numeric. */
-    size_t value_cnt;          /* Number of `value's per case. */
+    struct caseproto *proto;    /* Format of output cases. */
     bool ok;                    /* Set false on I/O error. */
   };
 
@@ -96,16 +97,18 @@ error (struct pfm_reader *r, const char *msg, ...)
   va_list args;
 
   ds_init_empty (&text);
-  ds_put_format (&text, _("portable file %s corrupt at offset 0x%lx: "),
-                 fh_get_file_name (r->fh), ftell (r->file));
+  ds_put_format (&text, _("portable file %s corrupt at offset 0x%llx: "),
+                 fh_get_file_name (r->fh), (long long int) ftello (r->file));
   va_start (args, msg);
   ds_put_vformat (&text, msg, args);
   va_end (args);
 
-  m.category = MSG_GENERAL;
-  m.severity = MSG_ERROR;
+  m.category = MSG_C_GENERAL;
+  m.severity = MSG_S_ERROR;
   m.where.file_name = NULL;
   m.where.line_number = 0;
+  m.where.first_column = 0;
+  m.where.last_column = 0;
   m.text = ds_cstr (&text);
 
   msg_emit (&m);
@@ -125,16 +128,18 @@ warning (struct pfm_reader *r, const char *msg, ...)
   va_list args;
 
   ds_init_empty (&text);
-  ds_put_format (&text, _("reading portable file %s at offset 0x%lx: "),
-                 fh_get_file_name (r->fh), ftell (r->file));
+  ds_put_format (&text, _("reading portable file %s at offset 0x%llx: "),
+                 fh_get_file_name (r->fh), (long long int) ftello (r->file));
   va_start (args, msg);
   ds_put_vformat (&text, msg, args);
   va_end (args);
 
-  m.category = MSG_GENERAL;
-  m.severity = MSG_WARNING;
+  m.category = MSG_C_GENERAL;
+  m.severity = MSG_S_WARNING;
   m.where.file_name = NULL;
   m.where.line_number = 0;
+  m.where.first_column = 0;
+  m.where.last_column = 0;
   m.text = ds_cstr (&text);
 
   msg_emit (&m);
@@ -153,7 +158,7 @@ close_reader (struct pfm_reader *r)
     {
       if (fn_close (fh_get_file_name (r->fh), r->file) == EOF)
         {
-          msg (ME, _("Error closing portable file \"%s\": %s."),
+          msg (ME, _("Error closing portable file `%s': %s."),
                fh_get_file_name (r->fh), strerror (errno));
           r->ok = false;
         }
@@ -256,8 +261,7 @@ pfm_open_reader (struct file_handle *fh, struct dictionary **dict,
   r->weight_index = -1;
   r->trans = NULL;
   r->var_cnt = 0;
-  r->widths = NULL;
-  r->value_cnt = 0;
+  r->proto = NULL;
   r->ok = true;
   if (setjmp (r->bail_out))
     goto error;
@@ -273,7 +277,7 @@ pfm_open_reader (struct file_handle *fh, struct dictionary **dict,
   r->file = fn_open (fh_get_file_name (r->fh), "rb");
   if (r->file == NULL)
     {
-      msg (ME, _("An error occurred while opening \"%s\" for reading "
+      msg (ME, _("An error occurred while opening `%s' for reading "
                  "as a portable file: %s."),
            fh_get_file_name (r->fh), strerror (errno));
       goto error;
@@ -296,8 +300,8 @@ pfm_open_reader (struct file_handle *fh, struct dictionary **dict,
   if (!match (r, 'F'))
     error (r, _("Data record expected."));
 
-  r->value_cnt = dict_get_next_value_idx (*dict);
-  return casereader_create_sequential (NULL, r->value_cnt, CASENUMBER_MAX,
+  r->proto = caseproto_ref_pool (dict_get_proto (*dict), r->pool);
+  return casereader_create_sequential (NULL, r->proto, CASENUMBER_MAX,
                                        &por_file_casereader_class, r);
 
  error:
@@ -448,6 +452,28 @@ read_string (struct pfm_reader *r, char *buf)
   *buf = '\0';
 }
 
+
+/* Reads a string into BUF, which must have room for 256
+   characters.
+   Returns the number of bytes read.
+*/
+static size_t
+read_bytes (struct pfm_reader *r, uint8_t *buf)
+{
+  int n = read_int (r);
+  if (n < 0 || n > 255)
+    error (r, _("Bad string length %d."), n);
+
+  while (n-- > 0)
+    {
+      *buf++ = r->cc;
+      advance (r);
+    }
+  return n;
+}
+
+
+
 /* Reads a string and returns a copy of it allocated from R's
    pool. */
 static char *
@@ -608,7 +634,7 @@ assign_default:
   return fmt_default_for_width (var_get_width (v));
 }
 
-static union value parse_value (struct pfm_reader *, struct variable *);
+static void parse_value (struct pfm_reader *, int width, union value *);
 
 /* Read information on all the variables.  */
 static void
@@ -623,7 +649,6 @@ read_variables (struct pfm_reader *r, struct dictionary *dict)
   r->var_cnt = read_int (r);
   if (r->var_cnt <= 0)
     error (r, _("Invalid number of variables %d."), r->var_cnt);
-  r->widths = pool_nalloc (r->pool, r->var_cnt, sizeof *r->widths);
 
   /* Purpose of this value is unknown.  It is typically 161. */
   read_int (r);
@@ -652,7 +677,6 @@ read_variables (struct pfm_reader *r, struct dictionary *dict)
       width = read_int (r);
       if (width < 0)
        error (r, _("Invalid variable width %d."), width);
-      r->widths[i] = width;
 
       read_string (r, name);
       for (j = 0; j < 6; j++)
@@ -668,17 +692,15 @@ read_variables (struct pfm_reader *r, struct dictionary *dict)
       v = dict_create_var (dict, name, width);
       if (v == NULL)
         {
-          int i;
-          for (i = 1; i < 100000; i++)
+          unsigned long int i;
+          for (i = 1; ; i++)
             {
-              char try_name[VAR_NAME_LEN + 1];
-              sprintf (try_name, "%.*s_%d", VAR_NAME_LEN - 6, name, i);
+              char try_name[8 + 1 + INT_STRLEN_BOUND (i) + 1];
+              sprintf (try_name, "%s_%lu", name, i);
               v = dict_create_var (dict, try_name, width);
               if (v != NULL)
                 break;
             }
-          if (v == NULL)
-            error (r, _("Duplicate variable name %s in position %d."), name, i);
           warning (r, _("Duplicate variable name %s in position %d renamed "
                         "to %s."), name, i, var_get_name (v));
         }
@@ -689,7 +711,7 @@ read_variables (struct pfm_reader *r, struct dictionary *dict)
       var_set_write_format (v, &write);
 
       /* Range missing values. */
-      mv_init (&miss, var_get_width (v));
+      mv_init (&miss, width);
       if (match (r, 'B'))
         {
           double x = read_float (r);
@@ -704,11 +726,17 @@ read_variables (struct pfm_reader *r, struct dictionary *dict)
       /* Single missing values. */
       while (match (r, '8'))
         {
-          union value value = parse_value (r, v);
+          int mv_width = MIN (width, 8);
+          union value value;
+
+          parse_value (r, mv_width, &value);
+          value_resize (&value, mv_width, width);
           mv_add_value (&miss, &value);
+          value_destroy (&value, width);
         }
 
       var_set_missing_values (v, &miss);
+      mv_destroy (&miss);
 
       if (match (r, 'C'))
         {
@@ -729,22 +757,19 @@ read_variables (struct pfm_reader *r, struct dictionary *dict)
     }
 }
 
-/* Parse a value for variable VV into value V. */
-static union value
-parse_value (struct pfm_reader *r, struct variable *vv)
+/* Parse a value of with WIDTH into value V. */
+static void
+parse_value (struct pfm_reader *r, int width, union value *v)
 {
-  union value v;
-
-  if (var_is_alpha (vv))
+  value_init (v, width);
+  if (width > 0)
     {
-      char string[256];
-      read_string (r, string);
-      buf_copy_str_rpad (v.s, 8, string);
+      uint8_t buf[256];
+      size_t n_bytes = read_bytes (r, buf);
+      value_copy_buf_rpad (v, width, buf, n_bytes, ' ');
     }
   else
-    v.f = read_float (r);
-
-  return v;
+    v->f = read_float (r);
 }
 
 /* Parse a value label record and return success. */
@@ -784,17 +809,14 @@ read_value_label (struct pfm_reader *r, struct dictionary *dict)
       char label[256];
       int j;
 
-      val = parse_value (r, v[0]);
+      parse_value (r, var_get_width (v[0]), &val);
       read_string (r, label);
 
       /* Assign the value label to each variable. */
       for (j = 0; j < nv; j++)
-       {
-         struct variable *var = v[j];
+        var_replace_value_label (v[j], &val, label);
 
-         if (!var_is_long_string (var))
-            var_replace_value_label (var, &val, label);
-       }
+      value_destroy (&val, var_get_width (v[0]));
     }
 }
 
@@ -814,50 +836,46 @@ read_documents (struct pfm_reader *r, struct dictionary *dict)
     }
 }
 
-/* Reads one case from portable file R into C. */
-static bool
-por_file_casereader_read (struct casereader *reader, void *r_, struct ccase *c)
+/* Reads and returns one case from portable file R.  Returns a
+   null pointer on failure. */
+static struct ccase *
+por_file_casereader_read (struct casereader *reader, void *r_)
 {
   struct pfm_reader *r = r_;
+  struct ccase *volatile c;
   size_t i;
-  size_t idx;
 
-  case_create (c, casereader_get_value_cnt (reader));
+  c = case_create (r->proto);
   setjmp (r->bail_out);
   if (!r->ok)
     {
       casereader_force_error (reader);
-      case_destroy (c);
-      return false;
+      case_unref (c);
+      return NULL;
     }
 
   /* Check for end of file. */
   if (r->cc == 'Z')
     {
-      case_destroy (c);
-      return false;
+      case_unref (c);
+      return NULL;
     }
 
-  idx = 0;
   for (i = 0; i < r->var_cnt; i++)
     {
-      int width = r->widths[i];
+      int width = caseproto_get_width (r->proto, i);
 
       if (width == 0)
-        {
-          case_data_rw_idx (c, idx)->f = read_float (r);
-          idx++;
-        }
+        case_data_rw_idx (c, i)->f = read_float (r);
       else
         {
-          char string[256];
-          read_string (r, string);
-          buf_copy_str_rpad (case_data_rw_idx (c, idx)->s, width, string);
-          idx += DIV_RND_UP (width, MAX_SHORT_STRING);
+          uint8_t buf[256];
+          size_t n_bytes = read_bytes (r, buf);
+          u8_buf_copy_rpad (case_str_rw_idx (c, i), width, buf, n_bytes, ' ');
         }
     }
 
-  return true;
+  return c;
 }
 
 /* Returns true if FILE is an SPSS portable file,