Separate settings and the SET command, for modularity.
[pspp] / src / data-list.c
index 2ed1f673fc5290d5f7c10e967c93eda2fc51aaab..ab166f0d65585b9c876ed06333e46240240cbde0 100644 (file)
@@ -41,6 +41,9 @@
 #include "tab.h"
 #include "var.h"
 #include "vfm.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
 \f
 /* Utility function. */
 
@@ -80,8 +83,6 @@ enum
 /* DATA LIST private data structure. */
 struct data_list_pgm
   {
-    struct trns_header h;
-
     struct dls_var_spec *first, *last; /* Variable parsing specifications. */
     struct dfm_reader *reader;  /* Data file reader. */
 
@@ -267,20 +268,14 @@ cmd_data_list (void)
     goto error;
 
   if (vfm_source != NULL)
-    {
-      dls->h.proc = data_list_trns_proc;
-      dls->h.free = data_list_trns_free;
-      add_transformation (&dls->h);
-    }
+    add_transformation (data_list_trns_proc, data_list_trns_free, dls);
   else 
     vfm_source = create_case_source (&data_list_source_class, dls);
 
   return CMD_SUCCESS;
 
  error:
-  destroy_dls_var_spec (dls->first);
-  free (dls->delims);
-  free (dls);
+  data_list_trns_free (dls);
   return CMD_FAILURE;
 }
 
@@ -314,7 +309,7 @@ struct fmt_list
 struct fixed_parsing_state
   {
     char **name;               /* Variable names. */
-    int name_cnt;              /* Number of names. */
+    size_t name_cnt;           /* Number of names. */
 
     int recno;                 /* Index of current record. */
     int sc;                    /* 1-based column number of starting column for
@@ -334,7 +329,7 @@ static int
 parse_fixed (struct data_list_pgm *dls)
 {
   struct fixed_parsing_state fx;
-  int i;
+  size_t i;
 
   fx.recno = 0;
   fx.sc = 1;
@@ -825,9 +820,9 @@ parse_free (struct dls_var_spec **first, struct dls_var_spec **last)
     {
       struct fmt_spec input, output;
       char **name;
-      int name_cnt;
+      size_t name_cnt;
       int width;
-      int i;
+      size_t i;
 
       if (!parse_DATA_LIST_vars (&name, &name_cnt, PV_NONE))
        return 0;
@@ -849,7 +844,7 @@ parse_free (struct dls_var_spec **first, struct dls_var_spec **last)
        {
          lex_match ('*');
           input = make_input_format (FMT_F, 8, 0);
-         output = get_format ();
+         output = *get_format ();
        }
 
       if (input.type == FMT_A || input.type == FMT_AHEX)
@@ -1230,22 +1225,22 @@ destroy_dls_var_spec (struct dls_var_spec *spec)
     }
 }
 
-/* Destroys DATA LIST transformation PGM. */
+/* Destroys DATA LIST transformation DLS. */
 static void
-data_list_trns_free (struct trns_header *pgm)
+data_list_trns_free (void *dls_)
 {
-  struct data_list_pgm *dls = (struct data_list_pgm *) pgm;
+  struct data_list_pgm *dls = dls_;
   free (dls->delims);
   destroy_dls_var_spec (dls->first);
   dfm_close_reader (dls->reader);
+  free (dls);
 }
 
-/* Handle DATA LIST transformation T, parsing data into C. */
+/* Handle DATA LIST transformation DLS, parsing data into C. */
 static int
-data_list_trns_proc (struct trns_header *t, struct ccase *c,
-                     int case_num UNUSED)
+data_list_trns_proc (void *dls_, struct ccase *c, int case_num UNUSED)
 {
-  struct data_list_pgm *dls = (struct data_list_pgm *) t;
+  struct data_list_pgm *dls = dls_;
   data_list_read_func *read_func;
   int retval;
 
@@ -1312,7 +1307,6 @@ static void
 data_list_source_destroy (struct case_source *source)
 {
   data_list_trns_free (source->aux);
-  free (source->aux);
 }
 
 const struct case_source_class data_list_source_class = 
@@ -1335,7 +1329,6 @@ struct rpd_num_or_var
 /* REPEATING DATA private data structure. */
 struct repeating_data_trns
   {
-    struct trns_header h;
     struct dls_var_spec *first, *last; /* Variable parsing specifications. */
     struct dfm_reader *reader;         /* Input file, never NULL. */
 
@@ -1426,11 +1419,10 @@ cmd_repeating_data (void)
              if (!parse_num_or_var (&rpd->starts_end, "STARTS ending column"))
                goto error;
            } else {
-             /* Otherwise, rpd->starts_end is left uninitialized.
-                This is okay.  We will initialize it later from the
-                record length of the file.  We can't do this now
-                because we can't be sure that the user has specified
-                the file handle yet. */
+             /* Otherwise, rpd->starts_end is uninitialized.  We
+                will initialize it later from the record length
+                of the file.  We can't do so now because the
+                file handle may not be specified yet. */
            }
 
          if (rpd->starts_beg.num != 0 && rpd->starts_end.num != 0
@@ -1450,7 +1442,7 @@ cmd_repeating_data (void)
              msg (SE, _("%s subcommand given multiple times."),"OCCURS");
              goto error;
            }
-         saw_occurs |= 2;
+         saw_occurs = true;
 
          if (!parse_num_or_var (&rpd->occurs, "OCCURS"))
            goto error;
@@ -1458,12 +1450,12 @@ cmd_repeating_data (void)
       else if (lex_match_id ("LENGTH"))
        {
          lex_match ('=');
-         if (saw_length & 4)
+         if (saw_length)
            {
              msg (SE, _("%s subcommand given multiple times."),"LENGTH");
              goto error;
            }
-         saw_length |= 4;
+         saw_length = true;
 
          if (!parse_num_or_var (&rpd->length, "LENGTH"))
            goto error;
@@ -1471,16 +1463,17 @@ cmd_repeating_data (void)
       else if (lex_match_id ("CONTINUED"))
        {
          lex_match ('=');
-         if (saw_continued & 8)
+         if (saw_continued)
            {
              msg (SE, _("%s subcommand given multiple times."),"CONTINUED");
              goto error;
            }
-         saw_continued |= 8;
+         saw_continued = true;
 
          if (!lex_match ('/'))
            {
-             if (!parse_num_or_var (&rpd->cont_beg, "CONTINUED beginning column"))
+             if (!parse_num_or_var (&rpd->cont_beg,
+                                     "CONTINUED beginning column"))
                goto error;
 
              lex_negative_to_dash ();
@@ -1504,12 +1497,12 @@ cmd_repeating_data (void)
       else if (lex_match_id ("ID"))
        {
          lex_match ('=');
-         if (saw_id & 16)
+         if (saw_id)
            {
              msg (SE, _("%s subcommand given multiple times."),"ID");
              goto error;
            }
-         saw_id |= 16;
+         saw_id = true;
          
          if (!lex_force_int ())
            goto error;
@@ -1554,7 +1547,7 @@ cmd_repeating_data (void)
            goto error;
 
          find_variable_input_spec (rpd->id_var, &rpd->id_spec);
-          rpd->id_value = xmalloc (sizeof *rpd->id_value * rpd->id_var->nv);
+          rpd->id_value = xnmalloc (rpd->id_var->nv, sizeof *rpd->id_value);
        }
       else if (lex_match_id ("TABLE"))
        table = 1;
@@ -1589,13 +1582,32 @@ cmd_repeating_data (void)
       goto error;
     }
 
-  /* Calculate starts_end, cont_end if necessary and possible. */
-  if (fh != NULL) 
+  /* Calculate and check starts_end, cont_end if necessary. */
+  if (rpd->starts_end.num == 0 && rpd->starts_end.var == NULL) 
     {
-      if (rpd->starts_end.num == 0 && rpd->starts_end.var == NULL)
-        rpd->starts_end.num = handle_get_record_width (fh);
-      if (rpd->cont_end.num == 0 && rpd->cont_end.var == NULL)
-        rpd->cont_end.num = handle_get_record_width (fh);
+      rpd->starts_end.num = fh != NULL ? handle_get_record_width (fh) : 80;
+      if (rpd->starts_beg.num != 0 
+          && rpd->starts_beg.num > rpd->starts_end.num)
+        {
+          msg (SE, _("STARTS beginning column (%d) exceeds "
+                     "default STARTS ending column taken from file's "
+                     "record width (%d)."),
+               rpd->starts_beg.num, rpd->starts_end.num);
+          goto error;
+        } 
+    }
+  if (rpd->cont_end.num == 0 && rpd->cont_end.var == NULL) 
+    {
+      rpd->cont_end.num = fh != NULL ? handle_get_record_width (fh) : 80;
+      if (rpd->cont_beg.num != 0
+          && rpd->cont_beg.num > rpd->cont_end.num)
+        {
+          msg (SE, _("CONTINUED beginning column (%d) exceeds "
+                     "default CONTINUED ending column taken from file's "
+                     "record width (%d)."),
+               rpd->cont_beg.num, rpd->cont_end.num);
+          goto error;
+        } 
     }
   
   lex_match ('=');
@@ -1616,15 +1628,12 @@ cmd_repeating_data (void)
   if (table)
     dump_fixed_table (rpd->first, fh, rpd->last->rec);
 
-  rpd->h.proc = repeating_data_trns_proc;
-  rpd->h.free = repeating_data_trns_free;
-  add_transformation (&rpd->h);
+  add_transformation (repeating_data_trns_proc, repeating_data_trns_free, rpd);
 
   return lex_end_of_command ();
 
  error:
-  destroy_dls_var_spec (rpd->first);
-  free (rpd->id_value);
+  repeating_data_trns_free (rpd);
   return CMD_FAILURE;
 }
 
@@ -1634,14 +1643,15 @@ cmd_repeating_data (void)
 static void 
 find_variable_input_spec (struct variable *v, struct fmt_spec *spec)
 {
-  int i;
+  size_t i;
   
   for (i = 0; i < n_trns; i++)
     {
-      struct data_list_pgm *pgm = (struct data_list_pgm *) t_trns[i];
+      struct transformation *trns = &t_trns[i];
       
-      if (pgm->h.proc == data_list_trns_proc)
+      if (trns->proc == data_list_trns_proc)
        {
+          struct data_list_pgm *pgm = trns->private;
          struct dls_var_spec *iter;
 
          for (iter = pgm->first; iter; iter = iter->next)
@@ -1700,7 +1710,7 @@ static int
 parse_repeating_data (struct dls_var_spec **first, struct dls_var_spec **last)
 {
   struct fixed_parsing_state fx;
-  int i;
+  size_t i;
 
   fx.recno = 0;
   fx.sc = 1;
@@ -1744,23 +1754,17 @@ parse_repeating_data (struct dls_var_spec **first, struct dls_var_spec **last)
 /* Obtains the real value for rpd_num_or_var N in case C and returns
    it.  The valid range is nonnegative numbers, but numbers outside
    this range can be returned and should be handled by the caller as
-   invalid.  If N does not have a value, returns DEFAULT_VALUE,
-   which must be nonzero if this is possible. */
+   invalid. */
 static int
-realize_value (struct rpd_num_or_var *n, struct ccase *c, int default_value)
+realize_value (struct rpd_num_or_var *n, struct ccase *c)
 {
-  if (n->num != 0)
-    return n->num;
-  else if (n->var != NULL)
+  if (n->var != NULL)
     {
       double v = case_num (c, n->var->fv);
       return v != SYSMIS && v >= INT_MIN && v <= INT_MAX ? v : -1;
     }
-  else 
-    {
-      assert (default_value != 0);
-      return default_value;
-    }
+  else
+    return n->num;
 }
 
 /* Parameter record passed to rpd_parse_record(). */
@@ -1884,10 +1888,9 @@ rpd_parse_record (const struct rpd_parse_info *info)
    DATA structure.  Returns -1 on success, -2 on end of file or
    on failure. */
 int
-repeating_data_trns_proc (struct trns_header *trns, struct ccase *c,
-                          int case_num UNUSED)
+repeating_data_trns_proc (void *trns_, struct ccase *c, int case_num UNUSED)
 {
-  struct repeating_data_trns *t = (struct repeating_data_trns *) trns;
+  struct repeating_data_trns *t = trns_;
     
   struct fixed_string line;       /* Current record. */
 
@@ -1915,13 +1918,13 @@ repeating_data_trns_proc (struct trns_header *trns, struct ccase *c,
   dfm_forward_record (t->reader);
 
   /* Calculate occurs, length. */
-  occurs_left = occurs = realize_value (&t->occurs, c, 0);
+  occurs_left = occurs = realize_value (&t->occurs, c);
   if (occurs <= 0)
     {
       tmsg (SE, RPD_ERR, _("Invalid value %d for OCCURS."), occurs);
       return -3;
     }
-  starts_beg = realize_value (&t->starts_beg, c, 0);
+  starts_beg = realize_value (&t->starts_beg, c);
   if (starts_beg <= 0)
     {
       tmsg (SE, RPD_ERR, _("Beginning column for STARTS (%d) must be "
@@ -1929,7 +1932,7 @@ repeating_data_trns_proc (struct trns_header *trns, struct ccase *c,
             starts_beg);
       return -3;
     }
-  starts_end = realize_value (&t->starts_end, c, line.length + 1);
+  starts_end = realize_value (&t->starts_end, c);
   if (starts_end < starts_beg)
     {
       tmsg (SE, RPD_ERR, _("Ending column for STARTS (%d) is less than "
@@ -1937,14 +1940,14 @@ repeating_data_trns_proc (struct trns_header *trns, struct ccase *c,
             starts_end, starts_beg);
       skip_first_record = 1;
     }
-  length = realize_value (&t->length, c, 0);
+  length = realize_value (&t->length, c);
   if (length < 0)
     {
       tmsg (SE, RPD_ERR, _("Invalid value %d for LENGTH."), length);
       length = 1;
       occurs = occurs_left = 1;
     }
-  cont_beg = realize_value (&t->cont_beg, c, 0);
+  cont_beg = realize_value (&t->cont_beg, c);
   if (cont_beg < 0)
     {
       tmsg (SE, RPD_ERR, _("Beginning column for CONTINUED (%d) must be "
@@ -1952,7 +1955,7 @@ repeating_data_trns_proc (struct trns_header *trns, struct ccase *c,
             cont_beg);
       return -2;
     }
-  cont_end = realize_value (&t->cont_end, c, line.length + 1);
+  cont_end = realize_value (&t->cont_end, c);
   if (cont_end < cont_beg)
     {
       tmsg (SE, RPD_ERR, _("Ending column for CONTINUED (%d) is less than "
@@ -2039,25 +2042,26 @@ repeating_data_trns_proc (struct trns_header *trns, struct ccase *c,
 
 /* Frees a REPEATING DATA transformation. */
 void
-repeating_data_trns_free (struct trns_header *rpd_) 
+repeating_data_trns_free (void *rpd_) 
 {
-  struct repeating_data_trns *rpd = (struct repeating_data_trns *) rpd_;
+  struct repeating_data_trns *rpd = rpd_;
 
   destroy_dls_var_spec (rpd->first);
   dfm_close_reader (rpd->reader);
   free (rpd->id_value);
+  free (rpd);
 }
 
 /* Lets repeating_data_trns_proc() know how to write the cases
    that it composes.  Not elegant. */
 void
-repeating_data_set_write_case (struct trns_header *trns,
+repeating_data_set_write_case (struct transformation *trns_,
                                write_case_func *write_case,
                                write_case_data wc_data) 
 {
-  struct repeating_data_trns *t = (struct repeating_data_trns *) trns;
+  struct repeating_data_trns *t = trns_->private;
 
-  assert (trns->proc == repeating_data_trns_proc);
+  assert (trns_->proc == repeating_data_trns_proc);
   t->write_case = write_case;
   t->wc_data = wc_data;
 }