Got rid of approx.h and replaced all references to approx_eq() by ==,
[pspp] / src / data-list.c
index b2d12893f0a3cdcf2d999b3a505535c83a2eeef6..a0036d6aa51c9b951027bb3dabf444d032898c04 100644 (file)
@@ -18,6 +18,7 @@
    02111-1307, USA. */
 
 #include <config.h>
+#include "data-list.h"
 #include <assert.h>
 #include <ctype.h>
 #include <float.h>
@@ -162,10 +163,7 @@ cmd_data_list (void)
            return CMD_FAILURE;
          dls.end = dict_lookup_var (default_dict, tokid);
          if (!dls.end) 
-            {
-              dls.end = dict_create_var (default_dict, tokid, 0);
-              assert (dls.end != NULL);
-            }
+            dls.end = dict_create_var_assert (default_dict, tokid, 0);
          lex_get ();
        }
       else if (token == T_ID)
@@ -518,11 +516,13 @@ fixed_parse_compatible (void)
        {
          convert_fmt_ItoO (&fx.spec.input, &v->print);
          v->write = v->print;
+          if (vfm_source != &input_program_source
+              && vfm_source != &file_type_source)
+            v->init = 0;
        }
       else
        {
-         v = dict_lookup_var (default_dict, fx.name[i]);
-         assert (v != NULL);
+         v = dict_lookup_var_assert (default_dict, fx.name[i]);
          if (!vfm_source)
            {
              msg (SE, _("%s is a duplicate variable name."), fx.name[i]);
@@ -626,6 +626,10 @@ dump_fmt_list (struct fmt_list *f)
                return 0;
              }
            
+            if (vfm_source != &input_program_source
+                && vfm_source != &file_type_source)
+              v->init = 0;
+
            fx.spec.input = f->f;
            convert_fmt_ItoO (&fx.spec.input, &v->print);
            v->write = v->print;
@@ -828,6 +832,10 @@ parse_free (void)
          
          v->print = v->write = out;
 
+          if (vfm_source != &input_program_source
+              && vfm_source != &file_type_source)
+            v->init = 0;
+
          strcpy (spec.name, name[i]);
          spec.fv = v->fv;
          spec.width = width;
@@ -967,14 +975,13 @@ cut_field (char **ret_cp, int *ret_len)
 static int read_from_data_list_fixed (void);
 static int read_from_data_list_free (void);
 static int read_from_data_list_list (void);
-static int do_reading (int flag);
 
 /* FLAG==0: reads any number of cases into temp_case and calls
    write_case() for each one, returns garbage.  FLAG!=0: reads one
    case into temp_case and returns -2 on eof, -1 otherwise.
    Uses dlsp as the relevant parsing description. */
 static int
-do_reading (int flag)
+do_reading (int flag, write_case_func *write_case, write_case_data wc_data)
 {
   int (*func) (void);
 
@@ -1030,7 +1037,7 @@ do_reading (int flag)
   else
     {
       while (func () != -2)
-       if (!write_case ())
+       if (!write_case (wc_data))
          {
            debug_printf ((_("abort in write_case()\n")));
            break;
@@ -1179,46 +1186,52 @@ read_from_data_list_list (void)
   return -1;
 }
 
-/* Destroys DATA LIST transformation or input program PGM. */
+/* Destroys SPEC. */
 static void
-destroy_dls (struct trns_header *pgm)
+destroy_dls_var_spec (struct dls_var_spec *spec) 
 {
-  struct data_list_pgm *dls = (struct data_list_pgm *) pgm;
-  struct dls_var_spec *iter, *next;
+  struct dls_var_spec *next;
 
-  iter = dls->spec;
-  while (iter)
+  while (spec != NULL)
     {
-      next = iter->next;
-      free (iter);
-      iter = next;
+      next = spec->next;
+      free (spec);
+      spec = next;
     }
+}
+
+/* Destroys DATA LIST transformation PGM. */
+static void
+destroy_dls (struct trns_header *pgm)
+{
+  struct data_list_pgm *dls = (struct data_list_pgm *) pgm;
+  destroy_dls_var_spec (dls->spec);
   fh_close_handle (dls->handle);
 }
 
 /* Note that since this is exclusively an input program, C is
    guaranteed to be temp_case. */
 static int
-read_one_case (struct trns_header *t, struct ccase *c unused)
+read_one_case (struct trns_header *t, struct ccase *c UNUSED)
 {
   dlsp = (struct data_list_pgm *) t;
-  return do_reading (1);
+  return do_reading (1, NULL, NULL);
 }
 \f
 /* Reads all the records from the data file and passes them to
    write_case(). */
 static void
-data_list_source_read (void)
+data_list_source_read (write_case_func *write_case, write_case_data wc_data)
 {
   dlsp = &dls;
-  do_reading (0);
+  do_reading (0, write_case, wc_data);
 }
 
 /* Destroys the source's internal data. */
 static void
 data_list_source_destroy_source (void)
 {
-  destroy_dls ((struct trns_header *) & dls);
+  destroy_dls (&dls.h);
 }
 
 struct case_stream data_list_source = 
@@ -1247,7 +1260,6 @@ struct repeating_data_trns
     struct trns_header h;
     struct dls_var_spec *spec; /* Variable parsing specifications. */
     struct file_handle *handle;        /* Input file, never NULL. */
-    /* Do not reorder preceding fields. */
 
     struct rpd_num_or_var starts_beg;  /* STARTS=, before the dash. */
     struct rpd_num_or_var starts_end;  /* STARTS=, after the dash. */
@@ -1255,15 +1267,22 @@ struct repeating_data_trns
     struct rpd_num_or_var length;      /* LENGTH= subcommand. */
     struct rpd_num_or_var cont_beg;    /* CONTINUED=, before the dash. */
     struct rpd_num_or_var cont_end;    /* CONTINUED=, after the dash. */
-    int id_beg, id_end;                        /* ID subcommand, beginning & end columns. */
-    struct variable *id_var;           /* ID subcommand, DATA LIST variable. */
-    struct fmt_spec id_spec;           /* ID subcommand, input format spec. */
+
+    /* ID subcommand. */
+    int id_beg, id_end;                        /* Beginning & end columns. */
+    struct variable *id_var;           /* DATA LIST variable. */
+    struct fmt_spec id_spec;           /* Input format spec. */
+    union value *id_value;              /* ID value. */
+
+    write_case_func *write_case;
+    write_case_data wc_data;
   };
 
 /* Information about the transformation being parsed. */
 static struct repeating_data_trns rpd;
 
-static int read_one_set_of_repetitions (struct trns_header *, struct ccase *);
+int repeating_data_trns_proc (struct trns_header *, struct ccase *);
+void repeating_data_trns_free (struct trns_header *);
 static int parse_num_or_var (struct rpd_num_or_var *, const char *);
 static int parse_repeating_data (void);
 static void find_variable_input_spec (struct variable *v,
@@ -1292,6 +1311,7 @@ cmd_repeating_data (void)
     = rpd.cont_end = rpd.starts_beg;
   rpd.id_beg = rpd.id_end = 0;
   rpd.id_var = NULL;
+  rpd.id_value = NULL;
   rpd.spec = NULL;
   first = &rpd.spec;
   next = NULL;
@@ -1318,7 +1338,7 @@ cmd_repeating_data (void)
          lex_match ('=');
          if (seen & 1)
            {
-             msg (SE, _("STARTS subcommand given multiple times."));
+             msg (SE, _("%s subcommand given multiple times."),"STARTS");
              return CMD_FAILURE;
            }
          seen |= 1;
@@ -1353,7 +1373,7 @@ cmd_repeating_data (void)
          lex_match ('=');
          if (seen & 2)
            {
-             msg (SE, _("OCCURS subcommand given multiple times."));
+             msg (SE, _("%s subcommand given multiple times."),"OCCURS");
              return CMD_FAILURE;
            }
          seen |= 2;
@@ -1366,7 +1386,7 @@ cmd_repeating_data (void)
          lex_match ('=');
          if (seen & 4)
            {
-             msg (SE, _("LENGTH subcommand given multiple times."));
+             msg (SE, _("%s subcommand given multiple times."),"LENGTH");
              return CMD_FAILURE;
            }
          seen |= 4;
@@ -1379,7 +1399,7 @@ cmd_repeating_data (void)
          lex_match ('=');
          if (seen & 8)
            {
-             msg (SE, _("CONTINUED subcommand given multiple times."));
+             msg (SE, _("%s subcommand given multiple times."),"CONTINUED");
              return CMD_FAILURE;
            }
          seen |= 8;
@@ -1412,7 +1432,7 @@ cmd_repeating_data (void)
          lex_match ('=');
          if (seen & 16)
            {
-             msg (SE, _("ID subcommand given multiple times."));
+             msg (SE, _("%s subcommand given multiple times."),"ID");
              return CMD_FAILURE;
            }
          seen |= 16;
@@ -1460,6 +1480,7 @@ cmd_repeating_data (void)
            return CMD_FAILURE;
 
          find_variable_input_spec (rpd.id_var, &rpd.id_spec);
+          rpd.id_value = xmalloc (sizeof *rpd.id_value * rpd.id_var->nv);
        }
       else if (lex_match_id ("TABLE"))
        table = 1;
@@ -1523,8 +1544,8 @@ cmd_repeating_data (void)
   {
     struct repeating_data_trns *new_trns;
 
-    rpd.h.proc = read_one_set_of_repetitions;
-    rpd.h.free = destroy_dls;
+    rpd.h.proc = repeating_data_trns_proc;
+    rpd.h.free = repeating_data_trns_free;
 
     new_trns = xmalloc (sizeof *new_trns);
     memcpy (new_trns, &rpd, sizeof *new_trns);
@@ -1700,14 +1721,14 @@ rpd_parse_record (int beg, int end, int ofs, struct ccase *c,
   /* Handle record ID values. */
   if (t->id_beg != 0)
     {
-      static union value comparator;
-      union value v;
+      union value id_temp[MAX_ELEMS_PER_VALUE];
       
+      /* Parse record ID into V. */
       {
        struct data_in di;
 
        data_in_finite_line (&di, line, len, t->id_beg, t->id_end);
-       di.v = &v;
+       di.v = compare_id ? id_temp : t->id_value;
        di.flags = 0;
        di.f1 = t->id_beg;
        di.format = t->id_spec;
@@ -1716,25 +1737,21 @@ rpd_parse_record (int beg, int end, int ofs, struct ccase *c,
          return 0;
       }
 
-      if (compare_id == 0)
-       comparator = v;
-      else if ((t->id_var->type == NUMERIC && comparator.f != v.f)
-              || (t->id_var->type == ALPHA
-                  && strncmp (comparator.s, v.s, t->id_var->width)))
+      if (compare_id
+          && compare_values (id_temp, t->id_value, t->id_var->width) != 0)
        {
-         char comp_str [64];
-         char v_str [64];
+         char expected_str [MAX_FORMATTED_LEN + 1];
+         char actual_str [MAX_FORMATTED_LEN + 1];
 
-         if (!data_out (comp_str, &t->id_var->print, &comparator))
-           comp_str[0] = 0;
-         if (!data_out (v_str, &t->id_var->print, &v))
-           v_str[0] = 0;
-         
-         comp_str[t->id_var->print.w] = v_str[t->id_var->print.w] = 0;
+         data_out (expected_str, &t->id_var->print, t->id_value);
+          expected_str[t->id_var->print.w] = '\0';
+
+         data_out (actual_str, &t->id_var->print, id_temp);
+          actual_str[t->id_var->print.w] = '\0';
            
          tmsg (SE, RPD_ERR, 
-               _("Mismatched case ID (%s).  Expected value was %s."),
-               v_str, comp_str);
+               _("Encountered mismatched record ID \"%s\" expecting \"%s\"."),
+               actual_str, expected_str);
 
          return 0;
        }
@@ -1765,7 +1782,7 @@ rpd_parse_record (int beg, int end, int ofs, struct ccase *c,
                  warned = 1;
 
                  tmsg (SW, RPD_ERR,
-                       _("Variable %s startging in column %d extends "
+                       _("Variable %s starting in column %d extends "
                          "beyond physical record length of %d."),
                        var_spec->v->name, fc, len);
                }
@@ -1787,7 +1804,7 @@ rpd_parse_record (int beg, int end, int ofs, struct ccase *c,
 
        cur += ofs;
 
-       if (!write_case ())
+       if (!t->write_case (t->wc_data))
          return 0;
       }
   }
@@ -1798,8 +1815,8 @@ rpd_parse_record (int beg, int end, int ofs, struct ccase *c,
 /* Analogous to read_one_case; reads one set of repetitions of the
    elements in the REPEATING DATA structure.  Returns -1 on success,
    -2 on end of file or on failure. */
-static int
-read_one_set_of_repetitions (struct trns_header *trns, struct ccase *c)
+int
+repeating_data_trns_proc (struct trns_header *trns, struct ccase *c)
 {
   dfm_push (dlsp->handle);
   
@@ -1932,3 +1949,29 @@ read_one_set_of_repetitions (struct trns_header *trns, struct ccase *c)
      transformations. */
   return -3;
 }
+
+void
+repeating_data_trns_free (struct trns_header *rpd_) 
+{
+  struct repeating_data_trns *rpd = (struct repeating_data_trns *) rpd_;
+
+  destroy_dls_var_spec (rpd->spec);
+  fh_close_handle (rpd->handle);
+  free (rpd->id_value);
+}
+
+/* This is a kluge.  It is only here until I have more time
+   tocome up with something better.  It lets
+   repeating_data_trns_proc() know how to write the cases that it
+   composes. */
+void
+repeating_data_set_write_case (struct trns_header *trns,
+                               write_case_func *write_case,
+                               write_case_data wc_data) 
+{
+  struct repeating_data_trns *t = (struct repeating_data_trns *) trns;
+
+  assert (trns->proc == repeating_data_trns_proc);
+  t->write_case = write_case;
+  t->wc_data = wc_data;
+}