Further clean up the CMD_* command result codes.
authorBen Pfaff <blp@gnu.org>
Tue, 2 May 2006 01:29:06 +0000 (01:29 +0000)
committerBen Pfaff <blp@gnu.org>
Tue, 2 May 2006 01:29:06 +0000 (01:29 +0000)
src/language/ChangeLog
src/language/command.c
src/language/command.h
src/language/data-io/ChangeLog
src/language/data-io/inpt-pgm.c
src/ui/terminal/main.c

index 4e88e3e7cfd4058558c5bae05401460567fed7dc..81997af685611606680f74140c584b8de6b80021 100644 (file)
@@ -1,3 +1,19 @@
+Mon May  1 18:17:52 2006  Ben Pfaff  <blp@gnu.org>
+
+       Further clean up the CMD_* command result codes.
+       
+       * command.c (cmd_result_is_valid): New function.
+       (cmd_result_is_success) Assert that argument is valid.  Simplified
+       check to one for a positive result.
+       (cmd_result_is_failure) Assert that argument is valid.  Simplified
+       check to one for a negative result.
+       (do_parse_command) Check that command's returned result is valid.
+
+       * command.h: (enum cmd_result) Renamed CMD_QUIT to CMD_FINISH and
+       updated all users.  Removed CMD_END_SUBLOOP in favor of new
+       CMD_PRIVATE_FIRST...CMD_PRIVATE_LAST range.  Changed failure codes
+       to have negative values.
+
 Mon May  1 15:56:56 2006  Ben Pfaff  <blp@gnu.org>
 
        Remove vestiges of FILE TYPE support. 
index 5712ddbe4b46a489c29b8041fd2ebcac4174590d..b5002caedfba30eea2c1a2580f066fa891b050ee 100644 (file)
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
 \f
+/* Returns true if RESULT is a valid "enum cmd_result",
+   false otherwise. */
+static inline bool
+cmd_result_is_valid (enum cmd_result result) 
+{
+  return (result == CMD_SUCCESS || result == CMD_EOF || result == CMD_FINISH
+          || (result >= CMD_PRIVATE_FIRST && result <= CMD_PRIVATE_LAST)
+          || result == CMD_FAILURE || result == CMD_NOT_IMPLEMENTED
+          || result == CMD_CASCADING_FAILURE);
+}
+
 /* Returns true if RESULT indicates success,
    false otherwise. */
 bool
 cmd_result_is_success (enum cmd_result result) 
 {
-  return (result == CMD_SUCCESS || result == CMD_EOF
-          || result == CMD_QUIT || result == CMD_END_SUBLOOP);
+  assert (cmd_result_is_valid (result));
+  return result > 0;
 }
 
 /* Returns true if RESULT indicates failure,
@@ -66,7 +77,8 @@ cmd_result_is_success (enum cmd_result result)
 bool
 cmd_result_is_failure (enum cmd_result result) 
 {
-  return !cmd_result_is_success (result);
+  assert (cmd_result_is_valid (result));
+  return result < 0;
 }
 \f
 /* Command processing states. */
@@ -175,6 +187,7 @@ do_parse_command (enum cmd_state state)
   tab_set_command_name (NULL);
   msg_set_command_name (NULL);
     
+  assert (cmd_result_is_valid (result));
   return result;
 }
 
@@ -628,7 +641,7 @@ command_generator (const char *text, int state)
 int
 cmd_finish (void)
 {
-  return CMD_QUIT;
+  return CMD_FINISH;
 }
 
 /* Parses the N command. */
index 0c4a5eac5a0473ac167dc634f09d66f4cceea30e..ec51f658689861494a1b94130d91825c73edac3c 100644 (file)
@@ -27,14 +27,19 @@ enum cmd_result
   {
     /* Successful return values. */
     CMD_SUCCESS = 1,            /* Successfully parsed and executed. */
-    CMD_EOF,                    /* No commands left. */
-    CMD_QUIT,                   /* Requested exit. */
-    CMD_END_SUBLOOP,            /* End of INPUT PROGRAM. */
+    CMD_EOF = 2,                /* End of input. */
+    CMD_FINISH = 3,             /* FINISH was executed. */
+
+    /* Range of successful return values available for use
+       by agreement between a command and the caller of
+       cmd_parse(). */
+    CMD_PRIVATE_FIRST = 4,      
+    CMD_PRIVATE_LAST = 127,      
 
     /* Various kinds of failures. */
-    CMD_FAILURE,                /* Not executed at all. */
-    CMD_NOT_IMPLEMENTED,        /* Command not implemented. */
-    CMD_CASCADING_FAILURE       /* Serious error: don't continue. */
+    CMD_FAILURE = -1,           /* Not executed at all. */
+    CMD_NOT_IMPLEMENTED = -2,   /* Command not implemented. */
+    CMD_CASCADING_FAILURE = -3  /* Serious error: don't continue. */
   };
 
 bool cmd_result_is_success (enum cmd_result);
index 9333a05b7c6f366de3da151b321943c3790fe16e..7c486bc3553999bc1854972f92d87fe805a9efc2 100644 (file)
@@ -1,3 +1,28 @@
+Mon May  1 18:21:19 2006  Ben Pfaff  <blp@gnu.org>
+
+       Further clean up the CMD_* command result codes.
+       
+       * (enum cmd_result_extensions) New.  Add CMD_END_INPUT_PROGRAM and
+       CMD_END_CASE result codes.
+       (struct input_program_pgm) Added case_nr, write_case, wc_data
+       members for use by END CASE transformation.
+       (emit_END_CASE) New function.
+       (cmd_input_program) Interpret CMD_END_CASE by outputting an END
+       CASE transformation.  If none is output by the input program
+       itself, add one automatically at the end.  Change lack of
+       variables from warning to error.
+       (cmd_end_input_program) Return CMD_END_INPUT_PROGRAM instead of
+       CMD_END_SUBLOOP.
+       (input_program_source_read) No longer any need to special-case END
+       CASE.  Handle TRNS_DROP_CASE properly.  Initialize new members in
+       inp for use by END CASE transformation.
+       (destroy_input_program) New function.
+       (input_program_source_destroy) Just call destroy_input_program().
+       (cmd_end_case) Just return CMD_END_CASE.
+       (end_case_trns_proc) No longer a stub handled by
+       input_program_source_read().  Actually output the case and
+       increment the case number.
+
 Mon May  1 16:06:30 2006  Ben Pfaff  <blp@gnu.org>
 
        Remove vestiges of REPEATING DATA support.
index 90f22ec2a11712b43808f8a00eac94b5491d4444..0581249a841e6edd4ba8a15257a2ab2a29979ed3 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <data/case-source.h>
 #include <data/case.h>
+#include <data/case-source.h>
 #include <data/dictionary.h>
 #include <data/variable.h>
 #include <language/command.h>
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
+/* Private result codes for use within INPUT PROGRAM. */
+enum cmd_result_extensions 
+  {
+    CMD_END_INPUT_PROGRAM = CMD_PRIVATE_FIRST,
+    CMD_END_CASE
+  };
+
 /* Indicates how a `union value' should be initialized. */
 enum value_init_type
   {
@@ -56,14 +64,23 @@ enum value_init_type
 
 struct input_program_pgm 
   {
+    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. */
     size_t case_size;           /* Size of case in bytes. */
   };
 
-static trns_proc_func end_case_trns_proc, reread_trns_proc, end_file_trns_proc;
+static void destroy_input_program (struct input_program_pgm *);
+static trns_proc_func end_case_trns_proc;
+static trns_proc_func reread_trns_proc;
+static trns_proc_func end_file_trns_proc;
 static trns_free_func reread_trns_free;
+
 static const struct case_source_class input_program_source_class;
+
 static bool inside_input_program;
 
 /* Returns true if we're parsing the inside of a INPUT
@@ -74,45 +91,67 @@ in_input_program (void)
   return inside_input_program;
 }
 
+/* Emits an END CASE transformation for INP. */
+static void
+emit_END_CASE (struct input_program_pgm *inp) 
+{
+  add_transformation (end_case_trns_proc, NULL, inp);
+}
+
 int
 cmd_input_program (void)
 {
   struct input_program_pgm *inp;
   size_t i;
+  bool saw_END_CASE = false;
 
   discard_variables ();
   if (token != '.')
     return lex_end_of_command ();
 
+  inp = xmalloc (sizeof *inp);
+  inp->init = NULL;
+  
   inside_input_program = true;
   for (;;) 
     {
       enum cmd_result result;
       lex_get ();
       result = cmd_parse (CMD_STATE_INPUT_PROGRAM);
-      if (result == CMD_END_SUBLOOP)
+      if (result == CMD_END_INPUT_PROGRAM)
         break;
-      if (result == CMD_EOF || result == CMD_QUIT || result == CMD_CASCADING_FAILURE)
+      else if (result == CMD_END_CASE) 
+        {
+          emit_END_CASE (inp);
+          saw_END_CASE = true; 
+        }
+      else if (cmd_result_is_failure (result) && result != CMD_FAILURE)
         {
           if (result == CMD_EOF)
             msg (SE, _("Unexpected end-of-file within INPUT PROGRAM."));
-          discard_variables ();
           inside_input_program = false;
+          discard_variables ();
+          destroy_input_program (inp);
           return result;
         }
     }
+  if (!saw_END_CASE)
+    emit_END_CASE (inp);
   inside_input_program = false;
 
-  if (dict_get_next_value_idx (default_dict) == 0)
-    msg (SW, _("No data-input or transformation commands specified "
-               "between INPUT PROGRAM and END INPUT PROGRAM."));
-
+  if (dict_get_next_value_idx (default_dict) == 0) 
+    {
+      msg (SE, _("Input program did not create any variables."));
+      discard_variables ();
+      destroy_input_program (inp);
+      return CMD_FAILURE;
+    }
+  
   /* Mark the boundary between INPUT PROGRAM transformations and
      ordinary transformations. */
   f_trns = n_trns;
 
   /* Figure out how to initialize each input case. */
-  inp = xmalloc (sizeof *inp);
   inp->init_cnt = dict_get_next_value_idx (default_dict);
   inp->init = xnmalloc (inp->init_cnt, sizeof *inp->init);
   for (i = 0; i < inp->init_cnt; i++)
@@ -143,7 +182,7 @@ int
 cmd_end_input_program (void)
 {
   assert (in_input_program ());
-  return CMD_END_SUBLOOP
+  return CMD_END_INPUT_PROGRAM
 }
 
 /* Initializes case C.  Called before the first case is read. */
@@ -203,45 +242,20 @@ input_program_source_read (struct case_source *source,
                            write_case_data wc_data)
 {
   struct input_program_pgm *inp = source->aux;
-  size_t i;
 
-  /* Nonzero if there were any END CASE commands in the set of
-     transformations.  If so, we don't automatically write out
-     cases. */
-  int end_case = 0;
-
-  /* FIXME?  This is the number of cases sent out of the input
-     program, not the number of cases written to the procedure.
-     The difference should only show up in $CASENUM in COMPUTE.
-     We should check behavior against SPSS. */
-  int cases_written = 0;
-
-  assert (inp != NULL);
-
-  /* Figure end_case. */
-  for (i = 0; i < f_trns; i++)
-    if (t_trns[i].proc == end_case_trns_proc)
-      end_case = 1;
-
-  init_case (inp, c);
-  for (;;)
+  inp->case_nr = 1;
+  inp->write_case = write_case;
+  inp->wc_data = wc_data;
+  for (init_case (inp, c); ; clear_case (inp, c))
     {
+      int i;
+      
       /* Perform transformations on `blank' case. */
       for (i = 0; i < f_trns; )
        {
           int code;
 
-          if (t_trns[i].proc == end_case_trns_proc) 
-            {
-              cases_written++;
-              if (!write_case (wc_data))
-                return false;
-              clear_case (inp, c);
-              i++;
-              continue;
-            }
-
-         code = t_trns[i].proc (t_trns[i].private, c, cases_written + 1);
+         code = t_trns[i].proc (t_trns[i].private, c, inp->case_nr);
          switch (code)
            {
            case TRNS_CONTINUE:
@@ -249,7 +263,7 @@ input_program_source_read (struct case_source *source,
              break;
 
             case TRNS_DROP_CASE:
-              abort ();
+              break;
 
             case TRNS_ERROR:
               return false;
@@ -265,18 +279,17 @@ input_program_source_read (struct case_source *source,
              break;
            }
        }
+    next_case: ;
+    }
+}
 
-      /* Write the case if appropriate. */
-      if (!end_case) 
-        {
-          cases_written++;
-          if (!write_case (wc_data))
-            return false;
-        }
-
-      /* Blank out the case for the next iteration. */
-    next_case:
-      clear_case (inp, c);
+static void
+destroy_input_program (struct input_program_pgm *pgm) 
+{
+  if (pgm != NULL) 
+    {
+      free (pgm->init);
+      free (pgm);
     }
 }
 
@@ -286,13 +299,7 @@ input_program_source_destroy (struct case_source *source)
 {
   struct input_program_pgm *inp = source->aux;
 
-  cancel_transformations ();
-
-  if (inp != NULL) 
-    {
-      free (inp->init);
-      free (inp);
-    }
+  destroy_input_program (inp);
 }
 
 static const struct case_source_class input_program_source_class =
@@ -307,18 +314,23 @@ int
 cmd_end_case (void)
 {
   assert (in_input_program ());
-  add_transformation (end_case_trns_proc, NULL, NULL);
-
+  if (token == '.')
+    return CMD_END_CASE;
   return lex_end_of_command ();
 }
 
-/* Should never be called, because this is handled in
-   input_program_source_read(). */
+/* Sends the current case as the source's output. */
 int
-end_case_trns_proc (void *trns_ UNUSED, struct ccase *c UNUSED,
-                    int case_num UNUSED)
+end_case_trns_proc (void *inp_, struct ccase *c, int case_nr UNUSED)
 {
-  abort ();
+  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;
 }
 
 /* REREAD transformation. */
index 018ba8aa3df2960077796246d88f8e3882b82841..2600a04883796c8870b63eb0ea3868dc7c465dba 100644 (file)
@@ -104,7 +104,7 @@ main (int argc, char **argv)
       for (;;)
         {
           int result = execute_command ();
-          if (result == CMD_EOF || result == CMD_QUIT)
+          if (result == CMD_EOF || result == CMD_FINISH)
             break;
           if (result == CMD_CASCADING_FAILURE && !getl_is_interactive ())
             {