Adopt use of gnulib for portability.
[pspp-builds.git] / src / data-list.c
index 381d6f2c90dfaa347ed89bd359dc107845f5ac7a..2b088860bf71f7493995bb160852db1556828ef4 100644 (file)
@@ -14,8 +14,8 @@
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA. */
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA. */
 
 #include <config.h>
 #include "data-list.h"
@@ -41,6 +41,9 @@
 #include "tab.h"
 #include "var.h"
 #include "vfm.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
 \f
 /* Utility function. */
 
@@ -65,7 +68,7 @@ struct dls_var_spec
     int fc, lc;                        /* Column numbers in record. */
 
     /* Free format only. */
-    char name[SHORT_NAME_LEN + 1];             /* Name of variable. */
+    char name[LONG_NAME_LEN + 1]; /* Name of variable. */
   };
 
 /* Constants for DATA LIST type. */
@@ -268,14 +271,9 @@ cmd_data_list (void)
 
   if (vfm_source != NULL)
     {
-      struct data_list_pgm *new_pgm;
-
       dls->h.proc = data_list_trns_proc;
       dls->h.free = data_list_trns_free;
-
-      new_pgm = xmalloc (sizeof *new_pgm);
-      memcpy (new_pgm, &dls, sizeof *new_pgm);
-      add_transformation (&new_pgm->h);
+      add_transformation (&dls->h);
     }
   else 
     vfm_source = create_case_source (&data_list_source_class, dls);
@@ -383,7 +381,7 @@ parse_fixed (struct data_list_pgm *dls)
       else
        {
          msg (SE, _("SPSS-like or FORTRAN-like format "
-              "specification expected after variable names."));
+                     "specification expected after variable names."));
          goto fail;
        }
 
@@ -404,12 +402,7 @@ parse_fixed (struct data_list_pgm *dls)
     }
   else if (!dls->rec_cnt)
     dls->rec_cnt = dls->last->rec;
-  if (token != '.')
-    {
-      lex_error (_("expecting end of command"));
-      return 0;
-    }
-  return 1;
+  return lex_end_of_command () == CMD_SUCCESS;
 
 fail:
   for (i = 0; i < fx.name_cnt; i++)
@@ -858,10 +851,8 @@ parse_free (struct dls_var_spec **first, struct dls_var_spec **last)
       else
        {
          lex_match ('*');
-         input.type = FMT_F;
-         input.w = 8;
-         input.d = 0;
-         output = get_format();
+          input = make_input_format (FMT_F, 8, 0);
+         output = get_format ();
        }
 
       if (input.type == FMT_A || input.type == FMT_AHEX)
@@ -889,7 +880,7 @@ parse_free (struct dls_var_spec **first, struct dls_var_spec **last)
           spec->input = input;
           spec->v = v;
          spec->fv = v->fv;
-         strcpy (spec->name, v->name);
+         str_copy_trunc (spec->name, sizeof spec->name, v->name);
          append_var_spec (first, last, spec);
        }
       for (i = 0; i < name_cnt; i++)
@@ -897,9 +888,7 @@ parse_free (struct dls_var_spec **first, struct dls_var_spec **last)
       free (name);
     }
 
-  if (token != '.')
-    lex_error (_("expecting end of command"));
-  return 1;
+  return lex_end_of_command () == CMD_SUCCESS;
 }
 
 /* Displays a table giving information on free-format variable parsing
@@ -1252,7 +1241,6 @@ data_list_trns_free (struct trns_header *pgm)
   free (dls->delims);
   destroy_dls_var_spec (dls->first);
   dfm_close_reader (dls->reader);
-  free (pgm);
 }
 
 /* Handle DATA LIST transformation T, parsing data into C. */
@@ -1327,6 +1315,7 @@ 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 = 
@@ -1383,7 +1372,11 @@ cmd_repeating_data (void)
 {
   struct repeating_data_trns *rpd;
   int table = 1;                /* Print table? */
-  unsigned seen = 0;            /* Mark subcommands as already seen. */
+  bool saw_starts = false;      /* Saw STARTS subcommand? */
+  bool saw_occurs = false;      /* Saw OCCURS subcommand? */
+  bool saw_length = false;      /* Saw LENGTH subcommand? */
+  bool saw_continued = false;   /* Saw CONTINUED subcommand? */
+  bool saw_id = false;          /* Saw ID subcommand? */
   struct file_handle *const fh = default_handle;
   
   assert (case_source_is_complex (vfm_source));
@@ -1420,13 +1413,13 @@ cmd_repeating_data (void)
       else if (lex_match_id ("STARTS"))
        {
          lex_match ('=');
-         if (seen & 1)
+         if (saw_starts)
            {
              msg (SE, _("%s subcommand given multiple times."),"STARTS");
              goto error;
            }
-         seen |= 1;
-
+          saw_starts = true;
+          
          if (!parse_num_or_var (&rpd->starts_beg, "STARTS beginning column"))
            goto error;
 
@@ -1436,11 +1429,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
@@ -1455,12 +1447,12 @@ cmd_repeating_data (void)
       else if (lex_match_id ("OCCURS"))
        {
          lex_match ('=');
-         if (seen & 2)
+         if (saw_occurs)
            {
              msg (SE, _("%s subcommand given multiple times."),"OCCURS");
              goto error;
            }
-         seen |= 2;
+         saw_occurs |= 2;
 
          if (!parse_num_or_var (&rpd->occurs, "OCCURS"))
            goto error;
@@ -1468,12 +1460,12 @@ cmd_repeating_data (void)
       else if (lex_match_id ("LENGTH"))
        {
          lex_match ('=');
-         if (seen & 4)
+         if (saw_length & 4)
            {
              msg (SE, _("%s subcommand given multiple times."),"LENGTH");
              goto error;
            }
-         seen |= 4;
+         saw_length |= 4;
 
          if (!parse_num_or_var (&rpd->length, "LENGTH"))
            goto error;
@@ -1481,16 +1473,17 @@ cmd_repeating_data (void)
       else if (lex_match_id ("CONTINUED"))
        {
          lex_match ('=');
-         if (seen & 8)
+         if (saw_continued & 8)
            {
              msg (SE, _("%s subcommand given multiple times."),"CONTINUED");
              goto error;
            }
-         seen |= 8;
+         saw_continued |= 8;
 
          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 ();
@@ -1514,12 +1507,12 @@ cmd_repeating_data (void)
       else if (lex_match_id ("ID"))
        {
          lex_match ('=');
-         if (seen & 16)
+         if (saw_id & 16)
            {
              msg (SE, _("%s subcommand given multiple times."),"ID");
              goto error;
            }
-         seen |= 16;
+         saw_id |= 16;
          
          if (!lex_force_int ())
            goto error;
@@ -1583,58 +1576,71 @@ cmd_repeating_data (void)
     }
 
   /* Comes here when DATA specification encountered. */
-  if ((seen & (1 | 2)) != (1 | 2))
+  if (!saw_starts || !saw_occurs)
     {
-      if ((seen & 1) == 0)
+      if (!saw_starts)
        msg (SE, _("Missing required specification STARTS."));
-      if ((seen & 2) == 0)
+      if (!saw_occurs)
        msg (SE, _("Missing required specification OCCURS."));
       goto error;
     }
 
   /* Enforce ID restriction. */
-  if ((seen & 16) && !(seen & 8))
+  if (saw_id && !saw_continued)
     {
       msg (SE, _("ID specified without CONTINUED."));
       goto error;
     }
 
-  /* Calculate starts_end, cont_end if necessary. */
-  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->starts_end.var == NULL)
-    rpd->cont_end.num = handle_get_record_width (fh);
-      
-  /* Calculate length if possible. */
-  if ((seen & 4) == 0)
+  /* Calculate and check starts_end, cont_end if necessary. */
+  if (rpd->starts_end.num == 0 && rpd->starts_end.var == NULL) 
     {
-      struct dls_var_spec *iter;
-      
-      for (iter = rpd->first; iter; iter = iter->next)
-       {
-         if (iter->lc > rpd->length.num)
-           rpd->length.num = iter->lc;
-       }
-      assert (rpd->length.num != 0);
+      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 ('=');
   if (!parse_repeating_data (&rpd->first, &rpd->last))
     goto error;
 
+  /* Calculate length if necessary. */
+  if (!saw_length)
+    {
+      struct dls_var_spec *iter;
+      
+      for (iter = rpd->first; iter; iter = iter->next)
+        if (iter->lc > rpd->length.num)
+          rpd->length.num = iter->lc;
+      assert (rpd->length.num != 0);
+    }
+  
   if (table)
     dump_fixed_table (rpd->first, fh, rpd->last->rec);
 
-  {
-    struct repeating_data_trns *new_trns;
-
-    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);
-    add_transformation ((struct trns_header *) new_trns);
-  }
+  rpd->h.proc = repeating_data_trns_proc;
+  rpd->h.free = repeating_data_trns_free;
+  add_transformation (&rpd->h);
 
   return lex_end_of_command ();
 
@@ -1739,7 +1745,7 @@ parse_repeating_data (struct dls_var_spec **first, struct dls_var_spec **last)
       else
        {
          msg (SE, _("SPSS-like or FORTRAN-like format "
-              "specification expected after variable names."));
+                     "specification expected after variable names."));
          goto fail;
        }
 
@@ -1747,11 +1753,6 @@ parse_repeating_data (struct dls_var_spec **first, struct dls_var_spec **last)
        free (fx.name[i]);
       free (fx.name);
     }
-  if (token != '.')
-    {
-      lex_error (_("expecting end of command"));
-      return 0;
-    }
   
   return 1;
 
@@ -1769,21 +1770,13 @@ parse_repeating_data (struct dls_var_spec **first, struct dls_var_spec **last)
 static int
 realize_value (struct rpd_num_or_var *n, struct ccase *c)
 {
-  if (n->num > 0)
-    return n->num;
-  
-  assert (n->num == 0);
   if (n->var != NULL)
     {
       double v = case_num (c, n->var->fv);
-
-      if (v == SYSMIS || v <= INT_MIN || v >= INT_MAX)
-       return -1;
-      else
-       return v;
+      return v != SYSMIS && v >= INT_MIN && v <= INT_MAX ? v : -1;
     }
   else
-    return 0;
+    return n->num;
 }
 
 /* Parameter record passed to rpd_parse_record(). */