Enables Data Open/Save/New menuitems.
[pspp-builds.git] / src / language / data-io / inpt-pgm.c
index 11b633195b0e4f3715ee1ad5c1d7e2f0f016d02e..71860ebfaee9bd67f618d43e94471c91e62af4ed 100644 (file)
@@ -1,6 +1,5 @@
 /* PSPP - computes sample statistics.
    Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
-   Written by Ben Pfaff <blp@gnu.org>.
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -67,10 +66,10 @@ enum value_init_type
 struct input_program_pgm 
   {
     struct trns_chain *trns_chain;
+    enum trns_result restart;
 
+    bool inited_case;           /* Did one-time case initialization? */
     size_t case_nr;             /* Incremented by END CASE transformation. */
-    write_case_func *write_case;/* Called by END CASE. */
-    write_case_data wc_data;    /* Aux data used by END CASE. */
 
     enum value_init_type *init; /* How to initialize each `union value'. */
     size_t init_cnt;            /* Number of elements in inp_init. */
@@ -97,21 +96,21 @@ in_input_program (void)
 
 /* Emits an END CASE transformation for INP. */
 static void
-emit_END_CASE (struct input_program_pgm *inp) 
+emit_END_CASE (struct dataset *ds, struct input_program_pgm *inp) 
 {
-  add_transformation (end_case_trns_proc, NULL, inp);
+  add_transformation (ds, end_case_trns_proc, NULL, inp);
 }
 
 int
-cmd_input_program (void)
+cmd_input_program (struct lexer *lexer, struct dataset *ds)
 {
   struct input_program_pgm *inp;
   size_t i;
   bool saw_END_CASE = false;
 
-  discard_variables ();
-  if (token != '.')
-    return lex_end_of_command ();
+  discard_variables (ds);
+  if (lex_token (lexer) != '.')
+    return lex_end_of_command (lexer);
 
   inp = xmalloc (sizeof *inp);
   inp->trns_chain = NULL;
@@ -120,12 +119,12 @@ cmd_input_program (void)
   inside_input_program = true;
   for (;;) 
     {
-      enum cmd_result result = cmd_parse (CMD_STATE_INPUT_PROGRAM);
+      enum cmd_result result = cmd_parse_in_state (lexer, ds, CMD_STATE_INPUT_PROGRAM);
       if (result == CMD_END_INPUT_PROGRAM)
         break;
       else if (result == CMD_END_CASE) 
         {
-          emit_END_CASE (inp);
+          emit_END_CASE (ds, inp);
           saw_END_CASE = true; 
         }
       else if (cmd_result_is_failure (result) && result != CMD_FAILURE)
@@ -133,54 +132,60 @@ cmd_input_program (void)
           if (result == CMD_EOF)
             msg (SE, _("Unexpected end-of-file within INPUT PROGRAM."));
           inside_input_program = false;
-          discard_variables ();
+          discard_variables (ds);
           destroy_input_program (inp);
           return result;
         }
     }
   if (!saw_END_CASE)
-    emit_END_CASE (inp);
+    emit_END_CASE (ds, inp);
   inside_input_program = false;
 
-  if (dict_get_next_value_idx (default_dict) == 0) 
+  if (dict_get_next_value_idx (dataset_dict (ds)) == 0) 
     {
       msg (SE, _("Input program did not create any variables."));
-      discard_variables ();
+      discard_variables (ds);
       destroy_input_program (inp);
       return CMD_FAILURE;
     }
   
-  inp->trns_chain = proc_capture_transformations ();
+  inp->trns_chain = proc_capture_transformations (ds);
   trns_chain_finalize (inp->trns_chain);
 
+  inp->restart = TRNS_CONTINUE;
+  inp->inited_case = false;
+  inp->case_nr = 1;
+
   /* Figure out how to initialize each input case. */
-  inp->init_cnt = dict_get_next_value_idx (default_dict);
+  inp->init_cnt = dict_get_next_value_idx (dataset_dict (ds));
   inp->init = xnmalloc (inp->init_cnt, sizeof *inp->init);
   for (i = 0; i < inp->init_cnt; i++)
     inp->init[i] = -1;
-  for (i = 0; i < dict_get_var_cnt (default_dict); i++)
+  for (i = 0; i < dict_get_var_cnt (dataset_dict (ds)); i++)
     {
-      struct variable *var = dict_get_var (default_dict, i);
+      struct variable *var = dict_get_var (dataset_dict (ds), i);
+      size_t value_cnt = var_get_value_cnt (var);
       enum value_init_type value_init;
       size_t j;
       
-      value_init = var->type == NUMERIC ? INP_NUMERIC : INP_STRING;
-      value_init |= var->leave ? INP_INIT_ONCE : INP_REINIT;
+      value_init = var_is_numeric (var) ? INP_NUMERIC : INP_STRING;
+      value_init |= var_get_leave (var) ? INP_INIT_ONCE : INP_REINIT;
 
-      for (j = 0; j < var->nv; j++)
-        inp->init[j + var->fv] = value_init;
+      for (j = 0; j < value_cnt; j++)
+        inp->init[j + var_get_case_index (var)] = value_init;
     }
   for (i = 0; i < inp->init_cnt; i++)
     assert (inp->init[i] != -1);
-  inp->case_size = dict_get_case_size (default_dict);
+  inp->case_size = dict_get_case_size (dataset_dict (ds));
 
-  proc_set_source (create_case_source (&input_program_source_class, inp));
+  proc_set_source (ds, 
+                   create_case_source (&input_program_source_class, inp));
 
   return CMD_SUCCESS;
 }
 
 int
-cmd_end_input_program (void)
+cmd_end_input_program (struct lexer *lexer UNUSED, struct dataset *ds UNUSED)
 {
   assert (in_input_program ());
   return CMD_END_INPUT_PROGRAM; 
@@ -196,14 +201,15 @@ init_case (const struct input_program_pgm *inp, struct ccase *c)
     switch (inp->init[i]) 
       {
       case INP_NUMERIC | INP_INIT_ONCE:
-        case_data_rw (c, i)->f = 0.0;
+        case_data_rw_idx (c, i)->f = 0.0;
         break;
       case INP_NUMERIC | INP_REINIT:
-        case_data_rw (c, i)->f = SYSMIS;
+        case_data_rw_idx (c, i)->f = SYSMIS;
         break;
       case INP_STRING | INP_INIT_ONCE:
       case INP_STRING | INP_REINIT:
-        memset (case_data_rw (c, i)->s, ' ', sizeof case_data_rw (c, i)->s);
+        memset (case_data_rw_idx (c, i)->s, ' ',
+                sizeof case_data_rw_idx (c, i)->s);
         break;
       default:
         NOT_REACHED ();
@@ -222,40 +228,58 @@ clear_case (const struct input_program_pgm *inp, struct ccase *c)
       case INP_NUMERIC | INP_INIT_ONCE:
         break;
       case INP_NUMERIC | INP_REINIT:
-        case_data_rw (c, i)->f = SYSMIS;
+        case_data_rw_idx (c, i)->f = SYSMIS;
         break;
       case INP_STRING | INP_INIT_ONCE:
         break;
       case INP_STRING | INP_REINIT:
-        memset (case_data_rw (c, i)->s, ' ', sizeof case_data_rw (c, i)->s);
+        memset (case_data_rw_idx (c, i)->s, ' ',
+                sizeof case_data_rw_idx (c, i)->s);
         break;
       default:
         NOT_REACHED ();
       }
 }
 
-/* Executes each transformation in turn on a `blank' case.
-   Returns true if successful, false if an I/O error occurred. */
+/* Returns true if STATE is valid given the transformations that
+   are allowed within INPUT PROGRAM. */
+static bool
+is_valid_state (enum trns_result state) 
+{
+  return (state == TRNS_CONTINUE
+          || state == TRNS_ERROR
+          || state == TRNS_END_FILE
+          || state >= 0);
+}
+
+/* Reads one case into C.
+   Returns true if successful, false at end of file or if an
+   I/O error occurred. */
 static bool
-input_program_source_read (struct case_source *source,
-                           struct ccase *c,
-                           write_case_func *write_case,
-                           write_case_data wc_data)
+input_program_source_read (struct case_source *source, struct ccase *c)
 {
   struct input_program_pgm *inp = source->aux;
 
-  inp->case_nr = 1;
-  inp->write_case = write_case;
-  inp->wc_data = wc_data;
-  for (init_case (inp, c); ; clear_case (inp, c))
+  if (!inp->inited_case)
+    {
+      init_case (inp, c);
+      inp->inited_case = true;
+    }
+
+  do
     {
-      enum trns_result result = trns_chain_execute (inp->trns_chain, c,
-                                                    &inp->case_nr);
-      if (result == TRNS_ERROR)
+      assert (is_valid_state (inp->restart));
+      if (inp->restart == TRNS_ERROR || inp->restart == TRNS_END_FILE)
         return false;
-      else if (result == TRNS_END_FILE)
-        return true;
+
+      clear_case (inp, c);
+      inp->restart = trns_chain_execute (inp->trns_chain, inp->restart,
+                                         c, &inp->case_nr);
+      assert (is_valid_state (inp->restart));
     }
+  while (inp->restart < 0);
+
+  return true;
 }
 
 static void
@@ -269,13 +293,16 @@ destroy_input_program (struct input_program_pgm *pgm)
     }
 }
 
-/* Destroys an INPUT PROGRAM source. */
-static void
+/* Destroys the source.
+   Returns true if successful read, false if an I/O occurred
+   during destruction or previously. */
+static bool
 input_program_source_destroy (struct case_source *source)
 {
   struct input_program_pgm *inp = source->aux;
-
+  bool ok = inp->restart != TRNS_ERROR;
   destroy_input_program (inp);
+  return ok;
 }
 
 static const struct case_source_class input_program_source_class =
@@ -287,26 +314,22 @@ static const struct case_source_class input_program_source_class =
   };
 \f
 int
-cmd_end_case (void)
+cmd_end_case (struct lexer *lexer, struct dataset *ds UNUSED)
 {
   assert (in_input_program ());
-  if (token == '.')
+  if (lex_token (lexer) == '.')
     return CMD_END_CASE;
-  return lex_end_of_command ();
+  return lex_end_of_command (lexer);
 }
 
 /* Sends the current case as the source's output. */
 int
-end_case_trns_proc (void *inp_, struct ccase *c, casenum_t case_nr UNUSED)
+end_case_trns_proc (void *inp_, struct ccase *c UNUSED,
+                    casenumber case_nr UNUSED)
 {
   struct input_program_pgm *inp = inp_;
-
-  if (!inp->write_case (inp->wc_data))
-    return TRNS_ERROR;
-
   inp->case_nr++;
-  clear_case (inp, c);
-  return TRNS_CONTINUE;
+  return TRNS_END_CASE;
 }
 
 /* REREAD transformation. */
@@ -318,7 +341,7 @@ struct reread_trns
 
 /* Parses REREAD command. */
 int
-cmd_reread (void)
+cmd_reread (struct lexer *lexer, struct dataset *ds)
 {
   struct file_handle *fh;       /* File to be re-read. */
   struct expression *e;         /* Expression for column to set. */
@@ -326,11 +349,11 @@ cmd_reread (void)
 
   fh = fh_get_default_handle ();
   e = NULL;
-  while (token != '.')
+  while (lex_token (lexer) != '.')
     {
-      if (lex_match_id ("COLUMN"))
+      if (lex_match_id (lexer, "COLUMN"))
        {
-         lex_match ('=');
+         lex_match (lexer, '=');
          
          if (e)
            {
@@ -339,14 +362,14 @@ cmd_reread (void)
              return CMD_CASCADING_FAILURE;
            }
          
-         e = expr_parse (default_dict, EXPR_NUMBER);
+         e = expr_parse (lexer, ds, EXPR_NUMBER);
          if (!e)
            return CMD_CASCADING_FAILURE;
        }
-      else if (lex_match_id ("FILE"))
+      else if (lex_match_id (lexer, "FILE"))
        {
-         lex_match ('=');
-          fh = fh_parse (FH_REF_FILE | FH_REF_INLINE);
+         lex_match (lexer, '=');
+          fh = fh_parse (lexer, FH_REF_FILE | FH_REF_INLINE);
          if (fh == NULL)
            {
              expr_free (e);
@@ -355,22 +378,23 @@ cmd_reread (void)
        }
       else
        {
-         lex_error (NULL);
+         lex_error (lexer, NULL);
          expr_free (e);
+          return CMD_CASCADING_FAILURE;
        }
     }
 
   t = xmalloc (sizeof *t);
-  t->reader = dfm_open_reader (fh);
+  t->reader = dfm_open_reader (fh, lexer);
   t->column = e;
-  add_transformation (reread_trns_proc, reread_trns_free, t);
+  add_transformation (ds, reread_trns_proc, reread_trns_free, t);
 
   return CMD_SUCCESS;
 }
 
 /* Executes a REREAD transformation. */
 static int
-reread_trns_proc (void *t_, struct ccase *c, casenum_t case_num)
+reread_trns_proc (void *t_, struct ccase *c, casenumber case_num)
 {
   struct reread_trns *t = t_;
 
@@ -404,19 +428,19 @@ reread_trns_free (void *t_)
 
 /* Parses END FILE command. */
 int
-cmd_end_file (void)
+cmd_end_file (struct lexer *lexer, struct dataset *ds)
 {
   assert (in_input_program ());
 
-  add_transformation (end_file_trns_proc, NULL, NULL);
+  add_transformation (ds, end_file_trns_proc, NULL, NULL);
 
-  return lex_end_of_command ();
+  return lex_end_of_command (lexer);
 }
 
 /* Executes an END FILE transformation. */
 static int
 end_file_trns_proc (void *trns_ UNUSED, struct ccase *c UNUSED,
-                    casenum_t case_num UNUSED)
+                    casenumber case_num UNUSED)
 {
   return TRNS_END_FILE;
 }