work on lexer
[pspp] / src / data / pc+-file-reader.c
index 979be50c47aacef160540c46179d00e1fc10efa8..73b9ea804b715d83332d4af132d0225884dc0e48 100644 (file)
@@ -80,6 +80,9 @@ struct pcp_var_record
   {
     unsigned int pos;
 
+    bool drop;
+    union value tmp;
+
     char name[9];
     int width;
     struct fmt_spec format;
@@ -90,8 +93,6 @@ struct pcp_var_record
 
     struct pcp_value_label *val_labs;
     size_t n_val_labs;
-
-    struct variable *var;
   };
 
 struct pcp_value_label
@@ -190,11 +191,10 @@ static bool parse_variable_records (struct pcp_reader *, struct dictionary *,
 static struct any_reader *
 pcp_open (struct file_handle *fh)
 {
-  struct pcp_reader *r;
   struct stat s;
 
   /* Create and initialize reader. */
-  r = xzalloc (sizeof *r);
+  struct pcp_reader *r = XZALLOC (struct pcp_reader);
   r->any_reader.klass = &pcp_file_reader_class;
   r->pool = pool_create ();
   pool_register (r->pool, free, r);
@@ -396,15 +396,7 @@ pcp_get_strings (const struct any_reader *r_, struct pool *pool,
   return aux.n;
 }
 
-static void
-find_and_delete_var (struct dictionary *dict, const char *name)
-{
-  struct variable *var = dict_lookup_var (dict, name);
-  if (var)
-    dict_delete_var (dict, var);
-}
-
-/* Decodes the dictionary read from R, saving it into into *DICT.  Character
+/* Decodes the dictionary read from R, saving it into *DICT.  Character
    strings in R are decoded using ENCODING, or an encoding obtained from R if
    ENCODING is null, or the locale encoding if R specifies no encoding.
 
@@ -445,10 +437,6 @@ pcp_decode (struct any_reader *r_, const char *encoding,
      dictionary and may destroy or modify its variables. */
   r->proto = caseproto_ref_pool (dict_get_proto (dict), r->pool);
 
-  find_and_delete_var (dict, "CASENUM_");
-  find_and_delete_var (dict, "DATE_");
-  find_and_delete_var (dict, "WEIGHT_");
-
   *dictp = dict;
   if (infop)
     {
@@ -756,7 +744,7 @@ read_variables_record (struct pcp_reader *r)
       var->format.w = (format >> 8) & 0xff;
       var->format.d = format & 0xff;
       fmt_fix_output (&var->format);
-      var->width = fmt_var_width (&var->format);
+      var->width = fmt_var_width (var->format);
 
       if (var_label_ofs)
         {
@@ -811,7 +799,7 @@ parse_header (struct pcp_reader *r, const struct pcp_main_header *header,
   info->integer_format = INTEGER_LSB_FIRST;
   info->float_format = FLOAT_IEEE_DOUBLE_LE;
   info->compression = r->compressed ? ANY_COMP_SIMPLE : ANY_COMP_NONE;
-  info->case_cnt = r->n_cases;
+  info->n_cases = r->n_cases;
 
   /* Convert file label to UTF-8 and put it into DICT. */
   label = recode_and_trim_string (r->pool, dict_encoding, header->file_label);
@@ -840,7 +828,6 @@ parse_variable_records (struct pcp_reader *r, struct dictionary *dict,
 
   for (rec = var_recs; rec < &var_recs[n_var_recs]; rec++)
     {
-      struct variable *var;
       char *name;
       size_t i;
 
@@ -848,24 +835,28 @@ parse_variable_records (struct pcp_reader *r, struct dictionary *dict,
                                  rec->name, -1, r->pool);
       name[strcspn (name, " ")] = '\0';
 
-      /* Transform $DATE => DATE_, $WEIGHT => WEIGHT_, $CASENUM => CASENUM_. */
-      if (name[0] == '$')
-        name = pool_asprintf (r->pool, "%s_", name + 1);
+      /* Drop system variables. */
+      rec->drop = name[0] == '$';
+      if (rec->drop)
+        {
+          value_init_pool (r->pool, &rec->tmp, rec->width);
+          continue;
+        }
 
-      if (!dict_id_is_valid (dict, name, false) || name[0] == '#')
+      if (!dict_id_is_valid (dict, name) || name[0] == '#')
         {
           pcp_error (r, rec->pos, _("Invalid variable name `%s'."), name);
           return false;
         }
 
-      var = rec->var = dict_create_var (dict, name, rec->width);
+      struct variable *var = dict_create_var (dict, name, rec->width);
       if (var == NULL)
         {
           char *new_name = dict_make_unique_var_name (dict, NULL, NULL);
           pcp_warn (r, rec->pos, _("Renaming variable with duplicate name "
                                    "`%s' to `%s'."),
                     name, new_name);
-          var = rec->var = dict_create_var_assert (dict, new_name, rec->width);
+          var = dict_create_var_assert (dict, new_name, rec->width);
           free (new_name);
         }
       if (rec->weight)
@@ -900,8 +891,7 @@ parse_variable_records (struct pcp_reader *r, struct dictionary *dict,
           if (var_is_numeric (var))
             value.f = parse_float (rec->val_labs[i].value);
           else
-            memcpy (value_str_rw (&value, rec->width),
-                    rec->val_labs[i].value, rec->width);
+            memcpy (value.s, rec->val_labs[i].value, rec->width);
 
           utf8_label = recode_string ("UTF-8", dict_encoding,
                                       rec->val_labs[i].label, -1);
@@ -926,7 +916,7 @@ parse_variable_records (struct pcp_reader *r, struct dictionary *dict,
         }
 
       /* Set formats. */
-      var_set_both_formats (var, &rec->format);
+      var_set_both_formats (var, rec->format);
     }
 
   return true;
@@ -959,16 +949,16 @@ pcp_file_casereader_read (struct casereader *reader, void *r_)
   r->n_cases--;
 
   c = case_create (r->proto);
+  size_t case_idx = 0;
   for (i = 0; i < r->n_vars; i++)
     {
       struct pcp_var_record *var = &r->vars[i];
-      union value *v = case_data_rw_idx (c, i);
+      union value *v = var->drop ? &var->tmp : case_data_rw_idx (c, case_idx++);
 
       if (var->width == 0)
         retval = read_case_number (r, &v->f);
       else
-        retval = read_case_string (r, value_str_rw (v, var->width),
-                                   var->width);
+        retval = read_case_string (r, v->s, var->width);
 
       if (retval != 1)
         {
@@ -1152,9 +1142,7 @@ static void
 pcp_msg (struct pcp_reader *r, off_t offset,
          int class, const char *format, va_list args)
 {
-  struct msg m;
   struct string text;
-
   ds_init_empty (&text);
   if (offset >= 0)
     ds_put_format (&text, _("`%s' near offset 0x%llx: "),
@@ -1163,16 +1151,13 @@ pcp_msg (struct pcp_reader *r, off_t offset,
     ds_put_format (&text, _("`%s': "), fh_get_file_name (r->fh));
   ds_put_vformat (&text, format, args);
 
-  m.category = msg_class_to_category (class);
-  m.severity = msg_class_to_severity (class);
-  m.file_name = NULL;
-  m.first_line = 0;
-  m.last_line = 0;
-  m.first_column = 0;
-  m.last_column = 0;
-  m.text = ds_cstr (&text);
-
-  msg_emit (&m);
+  struct msg *m = xmalloc (sizeof *m);
+  *m = (struct msg) {
+    .category = msg_class_to_category (class),
+    .severity = msg_class_to_severity (class),
+    .text = ds_steal_cstr (&text),
+  };
+  msg_emit (m);
 }
 
 /* Displays a warning for offset OFFSET in the file. */
@@ -1208,11 +1193,11 @@ pcp_error (struct pcp_reader *r, off_t offset, const char *format, ...)
    an error. */
 static inline int
 read_bytes_internal (struct pcp_reader *r, bool eof_is_ok,
-                     void *buf, size_t byte_cnt)
+                     void *buf, size_t n_bytes)
 {
-  size_t bytes_read = fread (buf, 1, byte_cnt, r->file);
+  size_t bytes_read = fread (buf, 1, n_bytes, r->file);
   r->pos += bytes_read;
-  if (bytes_read == byte_cnt)
+  if (bytes_read == n_bytes)
     return 1;
   else if (ferror (r->file))
     {
@@ -1232,9 +1217,9 @@ read_bytes_internal (struct pcp_reader *r, bool eof_is_ok,
    Returns true if successful.
    Returns false upon I/O error or if end-of-file is encountered. */
 static bool
-read_bytes (struct pcp_reader *r, void *buf, size_t byte_cnt)
+read_bytes (struct pcp_reader *r, void *buf, size_t n_bytes)
 {
-  return read_bytes_internal (r, false, buf, byte_cnt) == 1;
+  return read_bytes_internal (r, false, buf, n_bytes) == 1;
 }
 
 /* Reads BYTE_CNT bytes into BUF.
@@ -1242,9 +1227,9 @@ read_bytes (struct pcp_reader *r, void *buf, size_t byte_cnt)
    Returns 0 if an immediate end-of-file is encountered.
    Returns -1 if an I/O error or a partial read occurs. */
 static int
-try_read_bytes (struct pcp_reader *r, void *buf, size_t byte_cnt)
+try_read_bytes (struct pcp_reader *r, void *buf, size_t n_bytes)
 {
-  return read_bytes_internal (r, true, buf, byte_cnt);
+  return read_bytes_internal (r, true, buf, n_bytes);
 }
 
 /* Reads a 16-bit signed integer from R and stores its value in host format in