Allow parsing 0-based column ranges.
[pspp-builds.git] / src / language / command.c
index 1688a10eb6e3472dc5fa7e3ae0a21134827fc006..42580166c60e4fbcd708747d6c53fd8f3de2f293 100644 (file)
@@ -31,7 +31,6 @@
 #include <data/variable.h>
 #include <language/lexer/lexer.h>
 #include <language/prompt.h>
-#include <libpspp/alloc.h>
 #include <libpspp/assertion.h>
 #include <libpspp/compiler.h>
 #include <libpspp/message.h>
@@ -49,6 +48,9 @@
 #include <readline/readline.h>
 #endif
 
+#include "xalloc.h"
+#include "xmalloca.h"
+
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
@@ -619,32 +621,72 @@ report_state_mismatch (const struct command *command, enum cmd_state state)
   assert (!in_correct_state (command, state));
   if (state == CMD_STATE_INITIAL || state == CMD_STATE_DATA)
     {
-      const char *allowed[3];
-      int allowed_cnt;
-      char *s;
-
-      allowed_cnt = 0;
-      if (command->states & S_INITIAL)
-        allowed[allowed_cnt++] = _("before the active file has been defined");
-      else if (command->states & S_DATA)
-        allowed[allowed_cnt++] = _("after the active file has been defined");
-      if (command->states & S_INPUT_PROGRAM)
-        allowed[allowed_cnt++] = _("inside INPUT PROGRAM");
-      if (command->states & S_FILE_TYPE)
-        allowed[allowed_cnt++] = _("inside FILE TYPE");
-
-      if (allowed_cnt == 1)
-        s = xstrdup (allowed[0]);
-      else if (allowed_cnt == 2)
-        s = xasprintf (_("%s or %s"), allowed[0], allowed[1]);
-      else if (allowed_cnt == 3)
-        s = xasprintf (_("%s, %s, or %s"), allowed[0], allowed[1], allowed[2]);
-      else
-        NOT_REACHED ();
-
-      msg (SE, _("%s is allowed only %s."), command->name, s);
-
-      free (s);
+      switch (command->states)
+        {
+          /* One allowed state. */
+        case S_INITIAL:
+          msg (SE, _("%s is allowed only before the active file has "
+                     "been defined."), command->name);
+          break;
+        case S_DATA:
+          msg (SE, _("%s is allowed only after the active file has "
+                     "been defined."), command->name);
+          break;
+        case S_INPUT_PROGRAM:
+          msg (SE, _("%s is allowed only inside INPUT PROGRAM."),
+               command->name);
+          break;
+        case S_FILE_TYPE:
+          msg (SE, _("%s is allowed only inside FILE TYPE."), command->name);
+          break;
+
+          /* Two allowed states. */
+        case S_INITIAL | S_DATA:
+          NOT_REACHED ();
+        case S_INITIAL | S_INPUT_PROGRAM:
+          msg (SE, _("%s is allowed only before the active file has "
+                     "been defined or inside INPUT PROGRAM."), command->name);
+          break;
+        case S_INITIAL | S_FILE_TYPE:
+          msg (SE, _("%s is allowed only before the active file has "
+                     "been defined or inside FILE TYPE."), command->name);
+          break;
+        case S_DATA | S_INPUT_PROGRAM:
+          msg (SE, _("%s is allowed only after the active file has "
+                     "been defined or inside INPUT PROGRAM."), command->name);
+          break;
+        case S_DATA | S_FILE_TYPE:
+          msg (SE, _("%s is allowed only after the active file has "
+                     "been defined or inside FILE TYPE."), command->name);
+          break;
+        case S_INPUT_PROGRAM | S_FILE_TYPE:
+          msg (SE, _("%s is allowed only inside INPUT PROGRAM "
+                     "or inside FILE TYPE."), command->name);
+          break;
+
+          /* Three allowed states. */
+        case S_DATA | S_INPUT_PROGRAM | S_FILE_TYPE:
+          msg (SE, _("%s is allowed only after the active file has "
+                     "been defined, inside INPUT PROGRAM, or inside "
+                     "FILE TYPE."), command->name);
+          break;
+        case S_INITIAL | S_INPUT_PROGRAM | S_FILE_TYPE:
+          msg (SE, _("%s is allowed only before the active file has "
+                     "been defined, inside INPUT PROGRAM, or inside "
+                     "FILE TYPE."), command->name);
+          break;
+        case S_INITIAL | S_DATA | S_FILE_TYPE:
+          NOT_REACHED ();
+        case S_INITIAL | S_DATA | S_INPUT_PROGRAM:
+          NOT_REACHED ();
+
+          /* Four allowed states. */
+        case S_INITIAL | S_DATA | S_INPUT_PROGRAM | S_FILE_TYPE:
+          NOT_REACHED ();
+
+        default:
+          NOT_REACHED ();
+        }
     }
   else if (state == CMD_STATE_INPUT_PROGRAM)
     msg (SE, _("%s is not allowed inside INPUT PROGRAM."), command->name);
@@ -777,7 +819,7 @@ shell (void)
        {
          const char *cp = strrchr (shell_fn, '/');
          cp = cp ? &cp[1] : shell_fn;
-         shell_process = local_alloc (strlen (cp) + 8);
+         shell_process = xmalloca (strlen (cp) + 8);
          strcpy (shell_process, "-");
          strcat (shell_process, cp);
          if (strcmp (cp, "sh"))