Changed DFM from open-at-first-access to explicit-open. Before,
authorBen Pfaff <blp@gnu.org>
Sun, 21 Mar 2004 03:06:11 +0000 (03:06 +0000)
committerBen Pfaff <blp@gnu.org>
Sun, 21 Mar 2004 03:06:11 +0000 (03:06 +0000)
calling dfm_get_record() or dfm_put_record() would automatically
open the file.  Now, you have to call dfm_open_for_reading() or
dfm_open_for_writing() explicitly.  This makes it possible to
check permissions, file existence, etc. earlier.

Also made struct file_handle more opaque, and clean up in general.

Fixed cmd_parse() so that it always skips past a full command
name.  A few special commands for which this would be bad get
special treatment.  This lets us drop code for skipping past the
end of a command name in most cmd_*() functions.  It's not worth
listing all the commands affected.

Start work on better test framework.

Fix memory leaks.

Misc other changes.

70 files changed:
src/ChangeLog
src/Makefile.am
src/aggregate.c
src/apply-dict.c
src/autorecode.c
src/command.c
src/command.def
src/command.h
src/compute.c
src/correlations.q
src/count.c
src/crosstabs.q
src/data-list.c
src/debug.c [new file with mode: 0644]
src/descript.q
src/dfm.c
src/dfm.h
src/do-if.c
src/error.c
src/expr-evl.c
src/expr-prs.c
src/expr.h
src/file-handle.h
src/file-handle.q
src/file-type.c
src/filename.c
src/filename.h
src/flip.c
src/formats.c
src/frequencies.q
src/get.c
src/include.c
src/inpt-pgm.c
src/levene.c
src/lexer.c
src/lexer.h
src/list.q
src/loop.c
src/main.c
src/matrix-data.c
src/means.q
src/mis-val.c
src/modify-vars.c
src/numeric.c
src/pfm-read.c
src/pfm-write.c
src/print.c
src/recode.c
src/rename-vars.c
src/repeat.c
src/sample.c
src/sel-if.c
src/set.q
src/sfm-read.c
src/sfm-write.c
src/sort.c
src/split-file.c
src/sysfile-info.c
src/t-test.q
src/temporary.c
src/title.c
src/val-labs.c
src/var-labs.c
src/vector.c
src/vfm.c
src/weight.c
tests/ChangeLog
tests/command/list.sh
tests/command/print.sh
tests/command/weight.sh

index 30730f0a2eed915e78aba57981ea67d3324954c4..90df01c4715d6cacb282c4cc0f47e1ef90847c74 100644 (file)
@@ -1,3 +1,199 @@
+Sat Mar 20 17:57:23 2004  Ben Pfaff  <blp@gnu.org>
+
+       * levene.c: Add #include.
+
+       * set.q: (set_viewport) Add `int' argument to make its prototype
+       correct for signal().
+
+Sat Mar 20 15:35:17 2004  Ben Pfaff  <blp@gnu.org>
+
+       * expr-evl.c: (expr_evaluate) Assert that `c' is nonzero before
+       using it.
+
+Sat Mar 20 15:18:16 2004  Ben Pfaff  <blp@gnu.org>
+
+       Changed DFM from open-at-first-access to explicit-open.  Before,
+       calling dfm_get_record() or dfm_put_record() would automatically
+       open the file.  Now, you have to call dfm_open_for_reading() or
+       dfm_open_for_writing() explicitly.  This makes it possible to
+       check permissions, file existence, etc. earlier.
+
+       Also made struct file_handle more opaque, and clean up in general.
+
+       * data-list.c: (cmd_data_list) Open handle for reading.
+
+       * dfm.c: (struct dfm_fhuser_ext) Add `where', `saw_begin_data'
+       members.
+       (open_file_r) Renamed dfm_open_for_reading(), rewrote.
+       (open_file_w) Renamed dfm_open_for_writing(), rewrote.
+       (open_inline_file) Removed.
+       (read_record) For inline_file, if we haven't seen BEGIN DATA, read
+       it.  Deal with line_number in extension record instead of file
+       handle.
+       (dfm_get_record) Rewrote.
+       (dfm_put_record) Rewrote.
+       (dfm_push) Assert file is open and one of ours.  Deal with
+       line_number in extension record instead of file handle.
+       (dfm_pop) Assert file is open and one of ours.  Deal with
+       line_number in extension record instead of file handle.
+       (cmd_begin_data) Use dfm_open_for_reading().  Mark that we saw
+       BEGIN DATA.     
+
+       * file-handle.h: (enum constants RH_RF_*) Removed.
+       (enum constants FH_MD_*) Removed.
+       (struct file_handle) Removed `name', `norm_fn', `fn', `where',
+       `recform', `lrecl', `mode' members.  Public references to
+       `recform' changed to use handle_get_mode(), references to `lrecl'
+       changed to use handle_get_record_width().  Added `private' member.
+       (enum file_handle_mode) New.
+
+       * file-handle.q: (struct private_file_handle) New structure.
+       (struct file_handle_list) New structure.
+       (static var files) New.
+       (static var file_handles) Removed.
+       (init_file_handle) Removed.
+       (create_file_handle) Removed.
+       (get_handle_with_name) New function.
+       (get_handle_for_filename) New function.
+       (cmd_file_handle) Rewritten.
+       (hash_file_handle) Removed.
+       (cmp_file_handle) Removed.
+       (fh_init_files) Rewritten.
+       (fh_parse_file_handle) Rewritten.  Allows identifiers as
+       filenames.
+       (fh_get_handle_by_name) Renamed handle_get_name(), all references
+       updated.  Rewritten.
+       (fh_get_handle_by_filename) Renamed handle_get_filename(), all
+       references updated.  Rewritten.
+       (fh_record_width) Renamed handle_get_record_width(), all
+       references updated.  Rewritten.
+       (handle_get_mode) New function.
+
+       * file-type.c: (cmd_file_type) Open handle for reading.
+
+       * filename.c: [unix] (struct file_identity) New structure.
+       [unix] (fn_get_identity) New function.
+       [unix] (fn_free_identity) New function.
+       [unix] (fn_compare_file_identities) New function.
+       [!unix] (struct file_identity) New structure.
+       [!unix] (fn_get_identity) New function.
+       [!unix] (fn_free_identity) New function.
+       [!unix] (fn_compare_file_identities) New function.
+
+       * lexer.c: (static var put) Renamed put_token, all references
+       updated.
+       (static var put_tokstr) New.
+       (static var put_tokval) New.
+       (lex_init) Initialize put_tokstr().
+       (restore_token) New function.
+       (save_token) New function.
+       (lex_get) Use restore_token().
+       (lex_put_back) Use save_token().
+       (lex_put_back_id) New function.
+       (lex_put_forward) Removed.
+       (lex_preprocess_line) Set put_token instead of using
+       lex_put_forward().
+       (lex_negative_to_dash) Use save_token(), set put_token directly.
+       (dump_token) Use stderr instead of stdout.
+
+       * main.c: (main) Remove call to cmd_init().
+       
+       * matrix-data.c: (cmd_matrix_data) Open file for reading.
+
+       * pfm-read.c: Use handle_get_filename() instead of trying to use
+       h->fn directly, all over.
+
+       * pfm-write.c: Ditto.
+
+       * print.c: (internal_cmd_print) Open handle for writing.
+       (dump_table) Use handle_get_filename().
+       (print_trns_proc) Use handle_get_mode().
+       (cmd_print_space) Use fh_parse_file_handle().
+       Open handle for writing.
+       [0] (debug_print) Removed.
+
+       * sfm-read.c: Use handle_get_filename() instead of trying to use
+       h->fn directly, all over.
+
+       * sfm-write.c: Ditto.
+
+Sat Mar 20 14:35:48 2004  Ben Pfaff  <blp@gnu.org>
+
+       Fix memory leaks.
+       
+       * autorecode.c: (arc_free) Free arc->src_values.
+
+       * error.c: (msg) Free buf.
+
+       * val-labs.c: (do_value_labels) Always free vars.
+
+       * vfm.c: (close_active_file) If sink has no make_source then call
+       its destroy function.
+
+Sat Mar 20 14:00:24 2004  Ben Pfaff  <blp@gnu.org>
+
+       Fixed cmd_parse() so that it always skips past a full command
+       name.  A few special commands for which this would be bad get
+       special treatment.  This lets us drop code for skipping past the
+       end of a command name in most cmd_*() functions.  It's not worth
+       listing all the commands affected.
+
+       * command.c: (struct command) Remove `cmd' member, replace by
+       `name' member, all references updated.  Remove `word', `next',
+       `skip_entire_name' members.
+       (macro DEFCMD) Deal with revised `struct command'.
+       (macro UNIMPL) Ditto.
+       (macro SPCCMD) New macro for commands whose last word shouldn't be
+       skipped.
+       (static array cmd_table[]) Make const, rename `commands', remove
+       sentinel element.
+       (macro COMMAND_CNT) New macro.
+       (split_words) Removed.
+       (cmd_init) Removed.
+       (FILE_TYPE_okay) Make parameter const.
+       (cmd_parse) Improve error messages.
+       (match_strings) New function.
+       (next_word) New function.
+       (enum command_match) New enum.
+       (conflicting_3char_prefixes) New function.
+       (conflicting_3char_prefix_command) New function.
+       (cmd_match_words) New function.
+       (count_matching_commands) New function.
+       (get_command_name) New function.
+       (free_words) New function.
+       (unknown_command_error) New function.
+       (figure_out_command) Renamed parse_command_name(), rewritten.
+
+       * command.def: Removed @ command.  Marked BEGIN DATA, DOCUMENT,
+       FILE LABEL, REMARK, SUBTITLE, TITLE as special.  Renamed EVALUATE
+       to DEBUG EVALUATE.  Added N alias for N OF CASES, SORT alias for
+       SORT CASES.
+
+       * command.h: (macro SPCCMD) New.
+
+       * include.c: (cmd_include_at) Removed.
+       (cmd_include) Allow identifier to be used as filename.
+
+       * inpt-pgm.c: (cmd_reread) Use fh_parse_file_handle().
+
+       * t-test.q: (cmd_t_test) Command name is now parsed for us.
+       
+
+Sat Mar 20 13:56:00 2004  Ben Pfaff  <blp@gnu.org>
+
+       Start work on better test framework.
+       
+       * Makefile.am: (pspp_sources) Add debug.c.
+       
+       * debug.c: New file.
+
+       * compute.c: (cmd_evaluate) Moved to debug.c, renamed
+       cmd_debug_evaluate().
+
+       * expr-prs.c: (expr_parse) Remove PXP_DUMP support.
+
+       * expr.h: (enum constant PXP_DUMP) Removed.
+
 Sat Mar 20 00:05:42 WST 2004 John Darrington <john@darrington.wattle.id.au>
 
        * set.q:  Implemented the SHOW command, and synced it to the existing 
index 487b4e36234b01a8eafe642040ddde350e9c34c3..3c7773785797e5e843d6c5558b73fcd8b0f378b8 100644 (file)
@@ -39,7 +39,7 @@ apply-dict.c ascii.c autorecode.c bitvector.h \
 cmdline.c cmdline.h command.c command.def command.h compute.c          \
 copyleft.c copyleft.h \
 count.c data-in.c data-in.h data-list.c        data-list.h \
-data-out.c debug-print.h devind.c devind.h dfm.c dfm.h \
+data-out.c debug.c debug-print.h devind.c devind.h dfm.c dfm.h \
 dictionary.c do-if.c do-ifP.h error.c error.h expr-evl.c expr-opt.c    \
 expr-prs.c expr.h exprP.h file-handle.h file-type.c    \
 filename.c filename.h flip.c font.h format.c format.def format.h       \
index 72b4605978a650d7c6da5127fd2ab9388e5ae658..193125087cce21539a372becbd14fd6580b3bf05 100644 (file)
@@ -169,8 +169,6 @@ cmd_aggregate (void)
   dict_set_label (agr.dict, dict_get_label (default_dict));
   dict_set_documents (agr.dict, dict_get_documents (default_dict));
   
-  lex_match_id ("AGGREGATE");
-
   /* Read most of the subcommands. */
   for (;;)
     {
index 541d93382ddafed986cfe1811a684438573cdf85..9f6867cc4ea3da247a04a677dbd9b8733126edab 100644 (file)
@@ -42,9 +42,6 @@ cmd_apply_dictionary (void)
 
   int i;
   
-  lex_match_id ("APPLY");
-  lex_match_id ("DICTIONARY");
-  
   lex_match_id ("FROM");
   lex_match ('=');
   handle = fh_parse_file_handle ();
index f6b8e15ece49a73ae1737ab9036300198350897a..52104e7acaaaaf51455a619bc997ef989117bb38 100644 (file)
@@ -103,7 +103,6 @@ cmd_autorecode (void)
   arc.print = 0;
   dst_cnt = 0;
 
-  lex_match_id ("AUTORECODE");
   lex_match_id ("VARIABLES");
   lex_match ('=');
   if (!parse_variables (default_dict, &arc.src_vars, &arc.var_cnt,
@@ -205,7 +204,8 @@ arc_free (struct autorecode_pgm *arc)
       int i;
 
       for (i = 0; i < arc->var_cnt; i++)
-        hsh_destroy (arc->src_values[i]); 
+        hsh_destroy (arc->src_values[i]);
+      free (arc->src_values);
     }
   pool_destroy (arc->src_values_pool);
 }
index 163f9845742ee095096f8791c7d18d64d47f4a52..b6a0babeb5968a398dd50eea37e82920b3b4ee13 100644 (file)
@@ -43,8 +43,6 @@
 #if HAVE_SYS_WAIT_H
 #include <sys/wait.h>
 #endif
-
-#include "debug-print.h"
 \f
 /* Global variables. */
 
@@ -59,71 +57,37 @@ const char *cur_proc;
 /* A single command. */
 struct command
   {
-    /* Initialized statically. */
-    char cmd[22];              /* Command name. */
+    const char *name;          /* Command name. */
     int transition[4];         /* Transitions to make from each state. */
     int (*func) (void);                /* Function to call. */
-
-    /* Calculated at startup time. */
-    char *word[3];             /* cmd[], divided into individual words. */
-    struct command *next;      /* Next command with same word[0]. */
+    int skip_entire_name;       /* If zero, we don't skip the
+                                   final token in the command name. */
   };
 
 /* Define the command array. */
 #define DEFCMD(NAME, T1, T2, T3, T4, FUNC)             \
-       {NAME, {T1, T2, T3, T4}, FUNC, {NULL, NULL, NULL}, NULL},
+       {NAME, {T1, T2, T3, T4}, FUNC, 1},
+#define SPCCMD(NAME, T1, T2, T3, T4, FUNC)             \
+       {NAME, {T1, T2, T3, T4}, FUNC, 0},
 #define UNIMPL(NAME, T1, T2, T3, T4)                   \
-       {NAME, {T1, T2, T3, T4}, NULL, {NULL, NULL, NULL}, NULL},
-static struct command cmd_table[] = 
+       {NAME, {T1, T2, T3, T4}, NULL, 1},
+static const struct command commands[] = 
   {
 #include "command.def"
-    {"", {ERRO, ERRO, ERRO, ERRO}, NULL, {NULL, NULL, NULL}, NULL},
   };
 #undef DEFCMD
 #undef UNIMPL
+
+#define COMMAND_CNT (sizeof commands / sizeof *commands)
 \f
 /* Command parser. */
 
-static struct command *figure_out_command (void);
-
-/* Breaks the `cmd' member of C into individual words and sets C's
-   word[] member appropriately. */
-static void
-split_words (struct command *c)
-{
-  char *cmd, *save;
-  int i;
-
-  cmd = xstrdup (c->cmd);
-  for (i = 0; i < 3; i++)
-    cmd = c->word[i] = strtok_r (i == 0 ? cmd : NULL, " -", &save);
-}
-
-/* Initializes the command parser. */
-void
-cmd_init (void)
-{
-  struct command *c;
-
-  /* Break up command names into words. */
-  for (c = cmd_table; c->cmd[0]; c++)
-    split_words (c);
-
-  /* Make chains of commands having the same first word. */
-  for (c = cmd_table; c->cmd[0]; c++)
-    {
-      struct command *first;
-      for (first = c; c[1].word[0] && !strcmp (c[0].word[0], c[1].word[0]); c++)
-       c->next = c + 1;
-
-      c->next = NULL;
-    }
-}
+static const struct command *parse_command_name (void);
 
 /* Determines whether command C is appropriate to call in this
    part of a FILE TYPE structure. */
 static int
-FILE_TYPE_okay (struct command *c)
+FILE_TYPE_okay (const struct command *c)
 {
   int okay = 0;
   
@@ -131,12 +95,12 @@ FILE_TYPE_okay (struct command *c)
       && c->func != cmd_data_list
       && c->func != cmd_repeating_data
       && c->func != cmd_end_file_type)
-    msg (SE, _("%s not allowed inside FILE TYPE/END FILE TYPE."), c->cmd);
+    msg (SE, _("%s not allowed inside FILE TYPE/END FILE TYPE."), c->name);
 #if 0
   /* FIXME */
   else if (c->func == cmd_repeating_data && fty.type == FTY_GROUPED)
     msg (SE, _("%s not allowed inside FILE TYPE GROUPED/END FILE TYPE."),
-        c->cmd);
+        c->name);
   else if (!fty.had_rec_type && c->func != cmd_record_type)
     msg (SE, _("RECORD TYPE must be the first command inside a "
                      "FILE TYPE structure."));
@@ -159,7 +123,7 @@ FILE_TYPE_okay (struct command *c)
 int
 cmd_parse (void)
 {
-  struct command *cp;  /* Iterator used to find the proper command. */
+  const struct command *cp;    /* Iterator used to find the proper command. */
 
 #if C_ALLOCA
   /* The generic alloca package performs garbage collection when it is
@@ -183,17 +147,17 @@ cmd_parse (void)
      always an ID token. */
   if (token != T_ID)
     {
-      msg (SE, _("This line does not begin with a valid command name."));
+      lex_error (_("expecting command name"));
       return CMD_FAILURE;
     }
 
   /* Parse the command name. */
-  cp = figure_out_command ();
+  cp = parse_command_name ();
   if (cp == NULL)
     return CMD_FAILURE;
   if (cp->func == NULL)
     {
-      msg (SE, _("%s is not yet implemented."), cp->cmd);
+      msg (SE, _("%s is not yet implemented."), cp->name);
       while (token && token != '.')
        lex_get ();
       return CMD_SUCCESS;
@@ -221,15 +185,10 @@ cmd_parse (void)
        N_("%s is only allowed within an input program."),
       };
 
-      msg (SE, gettext (state_name[pgm_state]), cp->cmd);
+      msg (SE, gettext (state_name[pgm_state]), cp->name);
       return CMD_FAILURE;
     }
 
-#if DEBUGGING
-  if (cp->func != cmd_remark)
-    printf (_("%s command beginning\n"), cp->cmd);
-#endif
-
   /* The structured output manager numbers all its tables.  Increment
      the major table number for each separate procedure. */
   som_new_series ();
@@ -243,7 +202,7 @@ cmd_parse (void)
       const char *prev_proc;
       
       prev_proc = cur_proc;
-      cur_proc = cp->cmd;
+      cur_proc = cp->name;
       result = cp->func ();
       cur_proc = prev_proc;
     }
@@ -261,140 +220,331 @@ cmd_parse (void)
          }
       }
 
-#if DEBUGGING
-    if (cp->func != cmd_remark)
-      printf (_("%s command completed\n\n"), cp->cmd);
-#endif
-
     /* Pass the command's success value up to the caller. */
     return result;
   }
 }
 
-/* Parse the command name and return a pointer to the corresponding
-   struct command if successful.
-   If not successful, return a null pointer. */
-static struct command *
-figure_out_command (void)
+static size_t
+match_strings (const char *a, size_t a_len,
+               const char *b, size_t b_len) 
 {
-  static const char *unk =
-    N_("The identifier(s) specified do not form a valid command name:");
-
-  static const char *inc = 
-    N_("The identifier(s) specified do not form a complete command name:");
-
-  struct command *cp;
+  size_t match_len = 0;
+  
+  while (a_len > 0 && b_len > 0) 
+    {
+      /* Mismatch always returns zero. */
+      if (*a++ != *b++)
+        return 0;
+
+      /* Advance. */
+      a_len--;
+      b_len--;
+      match_len++;
+    }
 
-  /* Parse the INCLUDE short form.
-     Note that `@' is a valid character in identifiers. */
-  if (tokid[0] == '@')
-    return &cmd_table[0];
+  return match_len;
+}
 
-  /* Find a command whose first word matches this identifier.
-     If it is the only command that begins with this word, return
-     it. */
-  for (cp = cmd_table; cp->cmd[0]; cp++)
-    if (lex_id_match (cp->word[0], tokid))
-      break;
+/* Returns the first character in the first word in STRING,
+   storing the word's length in *WORD_LEN.  If no words remain,
+   returns a null pointer and stores 0 in *WORD_LEN.  Words are
+   sequences of alphanumeric characters or single
+   non-alphanumeric characters.  Words are delimited by
+   spaces. */
+static const char *
+find_word (const char *string, size_t *word_len) 
+{
+  /* Skip whitespace and asterisks. */
+  while (isspace (*string))
+    string++;
 
-  if (cp->cmd[0] == '\0')
+  /* End of string? */
+  if (*string == '\0') 
     {
-      msg (SE, "%s %s.", gettext (unk), ds_value (&tokstr));
+      *word_len = 0;
       return NULL;
     }
 
-  if (cp->next == NULL)
-    return cp;
-  
-  /* We know that there is more than one command starting with this
-     word.  Read the next word in the command name. */
+  /* Special one-character word? */
+  if (!isalnum ((unsigned char) *string)) 
+    {
+      *word_len = 1;
+      return string;
+    }
+
+  /* Alphanumeric word. */
+  *word_len = 1;
+  while (isalnum ((unsigned char) string[*word_len]))
+    (*word_len)++;
+
+  return string;
+}
+
+/* Returns nonzero if strings A and B can be confused based on
+   their first three letters. */
+static int
+conflicting_3char_prefixes (const char *a, const char *b) 
+{
+  size_t aw_len, bw_len;
+  const char *aw, *bw;
+
+  aw = find_word (a, &aw_len);
+  bw = find_word (b, &bw_len);
+  assert (aw != NULL && bw != NULL);
+
+  return ((aw_len > 3 && bw_len > 3)
+          || (aw_len == 3 && bw_len > 3)
+          || (bw_len == 3 && aw_len > 3)) && !memcmp (aw, bw, 3);
+}
+
+/* Returns nonzero if CMD can be confused with another command
+   based on the first three letters of its first word. */
+static int
+conflicting_3char_prefix_command (const struct command *cmd) 
+{
+  assert (cmd >= commands && cmd < commands + COMMAND_CNT);
+
+  return ((cmd > commands
+           && conflicting_3char_prefixes (cmd[-1].name, cmd[0].name))
+          || (cmd < commands + COMMAND_CNT
+              && conflicting_3char_prefixes (cmd[0].name, cmd[1].name)));
+}
+
+/* Ways that a set of words can match a command name. */
+enum command_match
   {
-    struct command *ocp = cp;
-    
-    /* Verify that the next token is an identifier, because we
-       must disambiguate this command name. */
-    lex_get ();
-    if (token != T_ID)
+    MISMATCH,           /* Not a match. */
+    PARTIAL_MATCH,      /* The words begin the command name. */
+    COMPLETE_MATCH      /* The words are the command name. */
+  };
+
+/* Figures out how well the WORD_CNT words in WORDS match CMD,
+   and returns the appropriate enum value.  If WORDS are a
+   partial match for CMD and the next word in CMD is a dash, then
+   *DASH_POSSIBLE is set to 1 if DASH_POSSIBLE is non-null;
+   otherwise, *DASH_POSSIBLE is unchanged. */
+static enum command_match
+cmd_match_words (const struct command *cmd,
+                 char *const words[], size_t word_cnt,
+                 int *dash_possible)
+{
+  const char *word;
+  size_t word_len;
+  size_t word_idx;
+
+  for (word = find_word (cmd->name, &word_len), word_idx = 0;
+       word != NULL && word_idx < word_cnt;
+       word = find_word (word + word_len, &word_len), word_idx++)
+    if (word_len != strlen (words[word_idx])
+        || memcmp (word, words[word_idx], word_len))
       {
-       /* If there's a command whose name is the first word only,
-          return it.  This happens with, i.e., PRINT vs. PRINT
-          SPACE. */
-       if (ocp->word[1] == NULL)
-         return ocp;
-       
-       msg (SE, "%s %s.", gettext (inc), ds_value (&tokstr));
-       return NULL;
+        size_t match_chars = match_strings (word, word_len,
+                                            words[word_idx],
+                                            strlen (words[word_idx]));
+        if (match_chars == 0) 
+          {
+            /* Mismatch. */
+            return MISMATCH;
+          }
+        else if (match_chars == 1 || match_chars == 2) 
+          {
+            /* One- and two-character abbreviations are not
+               acceptable. */
+            return MISMATCH; 
+          }
+        else if (match_chars == 3) 
+          {
+            /* Three-character abbreviations are acceptable
+               in the first word of a command if there are
+               no name conflicts.  They are always
+               acceptable after the first word. */
+            if (word_idx == 0 && conflicting_3char_prefix_command (cmd))
+              return MISMATCH;
+          }
+        else /* match_chars > 3 */ 
+          {
+            /* Four-character and longer abbreviations are
+               always acceptable.  */
+          }
       }
 
-    for (; cp; cp = cp->next)
-      if (cp->word[1] && lex_id_match (cp->word[1], tokid))
-       break;
+  if (word == NULL && word_idx == word_cnt) 
+    {
+      /* cmd->name = "FOO BAR", words[] = {"FOO", "BAR"}. */
+      return COMPLETE_MATCH;
+    }
+  else if (word == NULL) 
+    {
+      /* cmd->name = "FOO BAR", words[] = {"FOO", "BAR", "BAZ"}. */
+      return MISMATCH; 
+    }
+  else 
+    {
+      /* cmd->name = "FOO BAR BAZ", words[] = {"FOO", "BAR"}. */
+      if (word[0] == '-' && dash_possible != NULL)
+        *dash_possible = 1;
+      return PARTIAL_MATCH; 
+    }
+}
 
-    if (cp == NULL)
-      {
-       /* No match.  If there's a command whose name is the first
-          word only, return it.  This happens with, i.e., PRINT
-          vs. PRINT SPACE. */
-       if (ocp->word[1] == NULL)
-         return ocp;
-       
-       msg (SE, "%s %s %s.", gettext (unk), ocp->word[0], tokid);
-       return NULL;
-      }
+/* Returns the number of commands for which the WORD_CNT words in
+   WORDS are a partial or complete match.  If some partial match
+   has a dash as the next word, then *DASH_POSSIBLE is set to 1,
+   otherwise it is set to 0. */
+static int
+count_matching_commands (char *const words[], size_t word_cnt,
+                         int *dash_possible) 
+{
+  const struct command *cmd;
+  int cmd_match_count;
+
+  cmd_match_count = 0;
+  *dash_possible = 0;
+  for (cmd = commands; cmd < commands + COMMAND_CNT; cmd++) 
+    if (cmd_match_words (cmd, words, word_cnt, dash_possible) != MISMATCH) 
+      cmd_match_count++; 
+
+  return cmd_match_count;
+}
+
+/* Returns the command for which the WORD_CNT words in WORDS are
+   a complete match.  Returns a null pointer if no such command
+   exists. */
+static const struct command *
+get_complete_match (char *const words[], size_t word_cnt) 
+{
+  const struct command *cmd;
   
-    /* Check whether the next token is an identifier.
-       If not, bail. */
-    if (!isalpha ((unsigned char) (lex_look_ahead ())))
-      {
-       /* Check whether there is an unambiguous interpretation.
-          If not, give an error. */
-       if (cp->word[2]
-           && cp->next
-           && !strcmp (cp->word[1], cp->next->word[1]))
-         {
-           msg (SE, "%s %s %s.", gettext (inc), ocp->word[0], ocp->word[1]);
-           return NULL;
-         }
-       else
-         return cp;
-      }
-  }
+  for (cmd = commands; cmd < commands + COMMAND_CNT; cmd++) 
+    if (cmd_match_words (cmd, words, word_cnt, NULL) == COMPLETE_MATCH) 
+      return cmd; 
   
-  /* If this command can have a third word, disambiguate based on it. */
-  if (cp->word[2]
-      || (cp->next
-         && cp->next->word[2]
-         && !strcmp (cp->word[1], cp->next->word[1])))
+  return NULL;
+}
+
+/* Frees the WORD_CNT words in WORDS. */
+static void
+free_words (char *words[], size_t word_cnt) 
+{
+  size_t idx;
+  
+  for (idx = 0; idx < word_cnt; idx++)
+    free (words[idx]);
+}
+
+/* Flags an error that the command whose name is given by the
+   WORD_CNT words in WORDS is unknown. */
+static void
+unknown_command_error (char *const words[], size_t word_cnt) 
+{
+  size_t idx;
+  size_t words_len;
+  char *name, *cp;
+
+  words_len = 0;
+  for (idx = 0; idx < word_cnt; idx++)
+    words_len += strlen (words[idx]);
+
+  cp = name = xmalloc (words_len + word_cnt + 16);
+  for (idx = 0; idx < word_cnt; idx++) 
     {
-      struct command *ocp = cp;
+      if (idx != 0)
+        *cp++ = ' ';
+      cp = stpcpy (cp, words[idx]);
+    }
+  *cp = '\0';
+
+  msg (SE, _("Unknown command %s."), name);
+
+  free (name);
+}
+
+
+/* Parse the command name and return a pointer to the corresponding
+   struct command if successful.
+   If not successful, return a null pointer. */
+static const struct command *
+parse_command_name (void)
+{
+  char *words[16];
+  int word_cnt;
+  int complete_word_cnt;
+  int dash_possible;
+
+  dash_possible = 0;
+  word_cnt = complete_word_cnt = 0;
+  while (token == T_ID || (dash_possible && token == '-')) 
+    {
+      int cmd_match_cnt;
       
+      assert (word_cnt < sizeof words / sizeof *words);
+      if (token == T_ID)
+        words[word_cnt++] = xstrdup (ds_value (&tokstr));
+      else
+        words[word_cnt++] = xstrdup ("-");
+
+      cmd_match_cnt = count_matching_commands (words, word_cnt,
+                                               &dash_possible);
+      if (cmd_match_cnt == 0) 
+        break;
+      else if (cmd_match_cnt == 1) 
+        {
+          const struct command *command = get_complete_match (words, word_cnt);
+          if (command != NULL) 
+            {
+              if (command->skip_entire_name)
+                lex_get ();
+              free_words (words, word_cnt);
+              return command;
+            }
+        }
+      else /* cmd_match_cnt > 1 */
+        {
+          /* Do we have a complete command name so far? */
+          if (get_complete_match (words, word_cnt) != NULL)
+            complete_word_cnt = word_cnt;
+        }
       lex_get ();
-      assert (token == T_ID);
-
-      /* Try to find a command with this third word.
-        If found, bail. */
-      for (; cp; cp = cp->next)
-       if (cp->word[2]
-           && !strcmp (cp->word[1], ocp->word[1])
-           && lex_id_match (cp->word[2], tokid))
-         break;
-
-      if (cp != NULL)
-       return cp;
-
-      /* If no command with this third word found, make sure that
-        there's a command with those first two words but without a
-        third word. */
-      cp = ocp;
-      if (cp->word[2])
-       {
-         msg (SE, "%s %s %s %s.",
-              gettext (unk), ocp->word[0], ocp->word[1], ds_value (&tokstr));
-         return 0;
-       }
     }
 
-  return cp;
+  /* If we saw a complete command name earlier, drop back to
+     it. */
+  if (complete_word_cnt) 
+    {
+      int pushback_word_cnt;
+      const struct command *command;
+
+      /* Get the command. */
+      command = get_complete_match (words, complete_word_cnt);
+      assert (command != NULL);
+
+      /* Figure out how many words we want to keep.
+         We normally want to swallow the entire command. */
+      pushback_word_cnt = complete_word_cnt + 1;
+      if (!command->skip_entire_name)
+        pushback_word_cnt--;
+      
+      /* FIXME: We only support one-token pushback. */
+      assert (pushback_word_cnt + 1 >= word_cnt);
+
+      while (word_cnt > pushback_word_cnt) 
+        {
+          word_cnt--;
+          if (strcmp (words[word_cnt], "-")) 
+            lex_put_back_id (words[word_cnt]);
+          else
+            lex_put_back ('-');
+          free (words[word_cnt]);
+        }
+
+      free_words (words, word_cnt);
+      return command;
+    }
+
+  unknown_command_error (words, word_cnt);
+  free_words (words, word_cnt);
+  return NULL;
 }
 \f
 /* Simple commands. */
@@ -544,9 +694,6 @@ cmd_n_of_cases (void)
   /* Value for N. */
   int x;
 
-  lex_match_id ("N");
-  lex_match_id ("OF");
-  lex_match_id ("CASES");
   if (!lex_force_int ())
     return CMD_FAILURE;
   x = lex_integer ();
@@ -561,7 +708,6 @@ cmd_n_of_cases (void)
 int
 cmd_execute (void)
 {
-  lex_match_id ("EXECUTE");
   procedure (NULL, NULL);
   return lex_end_of_command ();
 }
@@ -570,15 +716,12 @@ cmd_execute (void)
 int
 cmd_erase (void)
 {
-
   if ( safer_mode() ) 
     { 
       msg (SE, _("This command not allowed when the SAFER option is set.")); 
       return CMD_FAILURE; 
     } 
-
   
-  lex_match_id ("ERASE");
   if (!lex_force_match_id ("FILE"))
     return CMD_FAILURE;
   lex_match ('=');
@@ -709,8 +852,6 @@ cmd_host (void)
       return CMD_FAILURE; 
     } 
 
-  lex_match_id ("HOST");
-
 #ifdef unix
   /* Figure out whether to invoke an interactive shell or to execute a
      single shell command. */
@@ -740,9 +881,6 @@ cmd_host (void)
 int
 cmd_new_file (void)
 {
-  lex_match_id ("NEW");
-  lex_match_id ("FILE");
-  
   discard_variables ();
 
   return lex_end_of_command ();
@@ -752,9 +890,6 @@ cmd_new_file (void)
 int
 cmd_clear_transformations (void)
 {
-  lex_match_id ("CLEAR");
-  lex_match_id ("TRANSFORMATIONS");
-
   if (getl_reading_script)
     {
       msg (SW, _("This command is not valid in a syntax file."));
@@ -762,6 +897,8 @@ cmd_clear_transformations (void)
     }
 
   cancel_transformations ();
+  /* FIXME: what about variables created by transformations?
+     They need to be properly initialized. */
 
   return CMD_SUCCESS;
 }
index c3ee874b617405ac146a6351cfd1f6fb17c79e56..a6f4610b19722e3cf1de12cc0a7395fedb1997d4 100644 (file)
 #define PROC STATE_PROC
 #define ERRO STATE_ERROR
 
-DEFCMD ("@",                      INIT, INPU, TRAN, PROC, cmd_include_at)
 UNIMPL ("ADD FILES",              TRAN, ERRO, TRAN, TRAN)
 DEFCMD ("ADD VALUE LABELS",       ERRO, INPU, TRAN, TRAN, cmd_add_value_labels)
 DEFCMD ("AGGREGATE",              ERRO, ERRO, PROC, TRAN, cmd_aggregate)
 DEFCMD ("APPLY DICTIONARY",       ERRO, ERRO, TRAN, TRAN, cmd_apply_dictionary)
 DEFCMD ("AUTORECODE",             ERRO, ERRO, PROC, PROC, cmd_autorecode)
-DEFCMD ("BEGIN DATA",             ERRO, ERRO, PROC, PROC, cmd_begin_data)
+SPCCMD ("BEGIN DATA",             ERRO, ERRO, PROC, PROC, cmd_begin_data)
 DEFCMD ("BREAK",                  ERRO, INPU, TRAN, TRAN, cmd_break)
 UNIMPL ("CASESTOVARS",           ERRO, ERRO, PROC, PROC)
 DEFCMD ("CLEAR TRANSFORMATIONS",  ERRO, INPU, TRAN, TRAN, cmd_clear_transformations)
@@ -40,11 +39,12 @@ DEFCMD ("CONDESCRIPTIVES",        ERRO, ERRO, PROC, PROC, cmd_descriptives)
 DEFCMD ("COUNT",                  ERRO, INPU, TRAN, TRAN, cmd_count)
 DEFCMD ("CROSSTABS",              ERRO, ERRO, PROC, PROC, cmd_crosstabs)
 DEFCMD ("DATA LIST",              TRAN, INPU, TRAN, TRAN, cmd_data_list)
+DEFCMD ("DEBUG EVALUATE",        INIT, INPU, TRAN, PROC, cmd_debug_evaluate)
 DEFCMD ("DESCRIPTIVES",           ERRO, ERRO, PROC, PROC, cmd_descriptives)
 DEFCMD ("DISPLAY",                ERRO, INPU, TRAN, PROC, cmd_display)
 DEFCMD ("DO IF",                  ERRO, INPU, TRAN, TRAN, cmd_do_if)
 DEFCMD ("DO REPEAT",              ERRO, INPU, TRAN, TRAN, cmd_do_repeat)
-DEFCMD ("DOCUMENT",               ERRO, INPU, TRAN, TRAN, cmd_document)
+SPCCMD ("DOCUMENT",               ERRO, INPU, TRAN, TRAN, cmd_document)
 DEFCMD ("DROP DOCUMENTS",         INIT, INPU, TRAN, PROC, cmd_drop_documents)
 UNIMPL ("EDIT",                   INIT, INPU, TRAN, PROC)
 DEFCMD ("ELSE",                   ERRO, INPU, TRAN, TRAN, cmd_else)
@@ -57,12 +57,11 @@ DEFCMD ("END INPUT PROGRAM",      ERRO, TRAN, ERRO, ERRO, cmd_end_input_program)
 DEFCMD ("END LOOP",               ERRO, INPU, TRAN, TRAN, cmd_end_loop)
 DEFCMD ("END REPEAT",             ERRO, INPU, TRAN, TRAN, cmd_end_repeat)
 DEFCMD ("ERASE",                  INIT, INPU, TRAN, PROC, cmd_erase)
-DEFCMD ("EVALUATE",               INIT, INPU, TRAN, PROC, cmd_evaluate)
 DEFCMD ("EXECUTE",                ERRO, ERRO, PROC, PROC, cmd_execute)
 DEFCMD ("EXIT",                   INIT, INPU, TRAN, PROC, cmd_exit)
 DEFCMD ("EXPORT",                 ERRO, ERRO, PROC, PROC, cmd_export)
 DEFCMD ("FILE HANDLE",            INIT, INPU, TRAN, PROC, cmd_file_handle)
-DEFCMD ("FILE LABEL",             INIT, INPU, TRAN, PROC, cmd_file_label)
+SPCCMD ("FILE LABEL",             INIT, INPU, TRAN, PROC, cmd_file_label)
 DEFCMD ("FILE TYPE",              INPU, ERRO, INPU, INPU, cmd_file_type)
 DEFCMD ("FILTER",                 ERRO, ERRO, TRAN, TRAN, cmd_filter)
 DEFCMD ("FINISH",                 INIT, INPU, TRAN, PROC, cmd_finish)
@@ -87,6 +86,7 @@ DEFCMD ("MEANS",                  ERRO, ERRO, PROC, PROC, cmd_means)
 DEFCMD ("MISSING VALUES",         ERRO, INPU, TRAN, TRAN, cmd_missing_values)
 DEFCMD ("MODIFY VARS",            ERRO, ERRO, TRAN, PROC, cmd_modify_vars)
 DEFCMD ("NEW FILE",               INIT, ERRO, INIT, INIT, cmd_new_file)
+DEFCMD ("N",                      INIT, INPU, TRAN, TRAN, cmd_n_of_cases)
 DEFCMD ("N OF CASES",             INIT, INPU, TRAN, TRAN, cmd_n_of_cases)
 UNIMPL ("NUMBERED",               INIT, INPU, TRAN, PROC)
 DEFCMD ("NUMERIC",                ERRO, INPU, TRAN, TRAN, cmd_numeric)
@@ -105,7 +105,7 @@ DEFCMD ("QUIT",                   INIT, INPU, TRAN, PROC, cmd_exit)
 DEFCMD ("RECODE",                 ERRO, INPU, TRAN, TRAN, cmd_recode)
 DEFCMD ("RECORD TYPE",            ERRO, INPU, ERRO, ERRO, cmd_record_type)
 UNIMPL ("REFORMAT",               ERRO, ERRO, TRAN, TRAN)
-DEFCMD ("REMARK",                 INIT, INPU, TRAN, PROC, cmd_remark)
+SPCCMD ("REMARK",                 INIT, INPU, TRAN, PROC, cmd_remark)
 DEFCMD ("RENAME VARIABLES",       ERRO, INPU, TRAN, PROC, cmd_rename_variables)
 DEFCMD ("REPEATING DATA",         ERRO, INPU, ERRO, ERRO, cmd_repeating_data)
 DEFCMD ("REREAD",                 ERRO, INPU, ERRO, ERRO, cmd_reread)
@@ -115,13 +115,14 @@ DEFCMD ("SAVE",                   ERRO, ERRO, PROC, PROC, cmd_save)
 DEFCMD ("SELECT IF",              ERRO, ERRO, TRAN, TRAN, cmd_select_if)
 DEFCMD ("SET",                    INIT, INPU, TRAN, PROC, cmd_set)
 DEFCMD ("SHOW",                    INIT, INPU, TRAN, PROC, cmd_show)
+DEFCMD ("SORT",                   ERRO, ERRO, PROC, PROC, cmd_sort_cases)
 DEFCMD ("SORT CASES",             ERRO, ERRO, PROC, PROC, cmd_sort_cases)
 DEFCMD ("SPLIT FILE",             ERRO, INPU, TRAN, TRAN, cmd_split_file)
 DEFCMD ("STRING",                 ERRO, INPU, TRAN, TRAN, cmd_string)
-DEFCMD ("SUBTITLE",               INIT, INPU, TRAN, PROC, cmd_subtitle)
+SPCCMD ("SUBTITLE",               INIT, INPU, TRAN, PROC, cmd_subtitle)
 DEFCMD ("SYSFILE INFO",           INIT, INPU, TRAN, PROC, cmd_sysfile_info)
 DEFCMD ("TEMPORARY",              ERRO, ERRO, TRAN, TRAN, cmd_temporary)
-DEFCMD ("TITLE",                  INIT, INPU, TRAN, PROC, cmd_title)
+SPCCMD ("TITLE",                  INIT, INPU, TRAN, PROC, cmd_title)
 DEFCMD ("T-TEST",                 ERRO, ERRO, PROC, PROC, cmd_t_test)
 UNIMPL ("UPDATE",                 TRAN, ERRO, TRAN, TRAN)
 DEFCMD ("VALUE LABELS",           ERRO, INPU, TRAN, TRAN, cmd_value_labels)
index b051a4be1b8773cdc8a218b095c875e2e544ebdf..423a8a30195a9e0802a10f1cf2cc8d4bc6cc648a 100644 (file)
@@ -43,15 +43,17 @@ enum
 extern int pgm_state;
 extern const char *cur_proc;
 
-void cmd_init (void);
 int cmd_parse (void);
 
 /* Prototype all the command functions. */
 #define DEFCMD(NAME, T1, T2, T3, T4, FUNC)     \
        int FUNC (void);
+#define SPCCMD(NAME, T1, T2, T3, T4, FUNC)     \
+       int FUNC (void);
 #define UNIMPL(NAME, T1, T2, T3, T4)
 #include "command.def"
 #undef DEFCMD
+#undef SPCCMD
 #undef UNIMPL
 
 #endif /* !command_h */
index 9c20e0ee781f1999922790eaa421807d01115b72..b08e76feddd9a62f2eb296312b147ab3961a06a9 100644 (file)
@@ -75,8 +75,6 @@ cmd_compute (void)
   struct lvalue *lvalue = NULL;
   struct compute_trns *compute = NULL;
 
-  lex_match_id ("COMPUTE");
-
   lvalue = lvalue_parse ();
   if (lvalue == NULL)
     goto fail;
@@ -232,7 +230,6 @@ cmd_if (void)
   struct compute_trns *compute = NULL;
   struct lvalue *lvalue = NULL;
 
-  lex_match_id ("IF");
   compute = compute_trns_create ();
 
   /* Test expression. */
@@ -442,25 +439,3 @@ lvalue_destroy (struct lvalue *lvalue)
   expr_free (lvalue->element);
   free (lvalue);
 }
-\f
-/* EVALUATE. */
-
-int
-cmd_evaluate (void)
-{
-  struct expression *expr;
-
-  lex_match_id ("EVALUATE");
-  expr = expr_parse (PXP_DUMP);
-  if (!expr)
-    return CMD_FAILURE;
-
-  expr_free (expr);
-  if (token != '.')
-    {
-      msg (SE, _("Extra characters after expression."));
-      return CMD_FAILURE;
-    }
-  
-  return CMD_SUCCESS;
-}
index 5b4fc2b38b7ea45199dcee5c7d37c571b0f2e36e..4c9f74b7f3344f5a5e32fdcbe70045bf679a9c45 100644 (file)
@@ -72,9 +72,6 @@ internal_cmd_correlations (void)
   cor_list = cor_last = NULL;
   matrix_file = NULL;
 
-  lex_match_id ("PEARSON");
-  lex_match_id ("CORRELATIONS");
-
   if (!parse_correlations (&cmd))
     return CMD_FAILURE;
   free_correlations (&cmd);
index 2ab52e250ea82aafdb1efdd7074b65d02b6fa3ac..0fc7370bb8d44c5f660e42c9c3593e769ab649ab 100644 (file)
@@ -134,8 +134,6 @@ cmd_count (void)
   struct count_trns *trns;      /* Transformation. */
   struct cnt_var_info *head;    /* First counting in chain. */
 
-  lex_match_id ("COUNT");
-
   /* Parses each slash-delimited specification. */
   head = cnt = xmalloc (sizeof *cnt);
   for (;;)
index 97db9763d76adfc5df9c8e65cd6e2d7fd006311d..b16cb02c75cb4038d0683556b1b1afc3d02a7764 100644 (file)
@@ -185,7 +185,6 @@ internal_cmd_crosstabs (void)
   pl_tc = pool_create ();
   pl_col = pool_create ();
 
-  lex_match_id ("CROSSTABS");
   if (!parse_crosstabs (&cmd))
     return CMD_FAILURE;
 
index a5ec8da24cbae3ba5eb36a36e7a953995ad3566f..da75d5d3185b13723b762d5b943e9a24b48fe2b3 100644 (file)
@@ -111,9 +111,6 @@ cmd_data_list (void)
   /* 0=print no table, 1=print table.  (TABLE subcommand.)  */
   int table = -1;
 
-  lex_match_id ("DATA");
-  lex_match_id ("LIST");
-
   if (!case_source_is_complex (vfm_source))
     discard_variables ();
 
@@ -237,6 +234,9 @@ cmd_data_list (void)
        dump_free_table (dls);
     }
 
+  if (!dfm_open_for_reading (dls->handle))
+    goto error;
+
   if (vfm_source != NULL)
     {
       struct data_list_pgm *new_pgm;
@@ -783,7 +783,7 @@ dump_fixed_table (const struct dls_var_spec *specs,
                    fmt_to_string (&spec->input));
     }
 
-  filename = fh_handle_name (handle);
+  filename = handle_get_filename (handle);
   if (filename == NULL)
     filename = "";
   buf = local_alloc (strlen (filename) + INT_DIGITS + 80);
@@ -797,7 +797,6 @@ dump_fixed_table (const struct dls_var_spec *specs,
   
   tab_title (t, 0, buf);
   tab_submit (t);
-  fh_handle_name (NULL);
   local_free (buf);
 }
 \f
@@ -915,7 +914,7 @@ dump_free_table (const struct data_list_pgm *dls)
   {
     const char *filename;
 
-    filename = fh_handle_name (dls->handle);
+    filename = handle_get_filename (dls->handle);
     if (filename == NULL)
       filename = "";
     tab_title (t, 1,
@@ -926,7 +925,6 @@ dump_free_table (const struct data_list_pgm *dls)
   }
   
   tab_submit (t);
-  fh_handle_name (NULL);
 }
 \f
 /* Input procedure. */ 
@@ -1322,9 +1320,6 @@ cmd_repeating_data (void)
   /* Bits are set when a particular subcommand has been seen. */
   unsigned seen = 0;
   
-  lex_match_id ("REPEATING");
-  lex_match_id ("DATA");
-
   assert (case_source_is_complex (vfm_source));
 
   rpd = xmalloc (sizeof *rpd);
@@ -1539,9 +1534,9 @@ cmd_repeating_data (void)
 
   /* Calculate starts_end, cont_end if necessary. */
   if (rpd->starts_end.num == 0 && rpd->starts_end.var == NULL)
-    rpd->starts_end.num = fh_record_width (rpd->handle);
+    rpd->starts_end.num = handle_get_record_width (rpd->handle);
   if (rpd->cont_end.num == 0 && rpd->starts_end.var == NULL)
-    rpd->cont_end.num = fh_record_width (rpd->handle);
+    rpd->cont_end.num = handle_get_record_width (rpd->handle);
       
   /* Calculate length if possible. */
   if ((seen & 4) == 0)
diff --git a/src/debug.c b/src/debug.c
new file mode 100644 (file)
index 0000000..441504f
--- /dev/null
@@ -0,0 +1,45 @@
+/* PSPP - computes sample statistics.
+   Copyright (C) 2004 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
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   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. */
+
+#include <config.h>
+#include "command.h"
+#include "error.h"
+#include "expr.h"
+#include "lexer.h"
+#include "var.h"
+
+int
+cmd_debug_evaluate (void)
+{
+  struct expression *expr;
+
+  discard_variables ();
+  expr = expr_parse (PXP_NONE);
+  if (!expr)
+    return CMD_FAILURE;
+
+  expr_free (expr);
+  if (token != '.')
+    {
+      msg (SE, _("Extra characters after expression."));
+      return CMD_FAILURE;
+    }
+  
+  return CMD_SUCCESS;
+}
index 3e5c6a4e427a16be5e2886a2d1956468a0cc3db6..9ac10325fffe72c656be79ff3e28f1609a0644f5 100644 (file)
@@ -193,8 +193,6 @@ cmd_descriptives (void)
   v_variables = NULL;
   n_variables = 0;
 
-  lex_match_id ("DESCRIPTIVES");
-  lex_match_id ("CONDESCRIPTIVES");
   if (!parse_descriptives (&cmd))
     goto lossage;
 
index cec6234f982b94fa33f429c5c01208d54230a520..f9aa574111d38a127bcf436a77404368ba2e663b 100644 (file)
--- a/src/dfm.c
+++ b/src/dfm.c
@@ -41,14 +41,17 @@ struct dfm_fhuser_ext
   {
     struct file_ext file;      /* Associated file. */
 
+    struct file_locator where;  /* Current location in data file. */
     char *line;                        /* Current line, not null-terminated. */
+    size_t size;               /* Number of bytes allocated for line. */
     size_t len;                        /* Length of line. */
 
     char *ptr;                 /* Pointer into line that is returned by
                                   dfm_get_record(). */
-    size_t size;               /* Number of bytes allocated for line. */
     int advance;               /* Nonzero=dfm_get_record() reads a new
                                   record; otherwise returns current record. */
+    int saw_begin_data;         /* For inline_file only, whether we've 
+                                   already read a BEGIN DATA line. */
   };
 
 /* These are defined at the end of this file. */
@@ -72,7 +75,7 @@ dfm_close (struct file_handle *h)
       read_record (h);
       
   msg (VM (2), _("%s: Closing data-file handle %s."),
-       fh_handle_filename (h), fh_handle_name (h));
+       handle_get_filename (h), handle_get_name (h));
   assert (h->class == &dfm_r_class || h->class == &dfm_w_class);
   if (ext->file.file)
     {
@@ -84,152 +87,131 @@ dfm_close (struct file_handle *h)
   free (ext);
 }
 
-/* Initializes EXT properly as an inline data file. */
-static void
-open_inline_file (struct dfm_fhuser_ext *ext)
+/* Opens a file handle for reading as a data file.  Returns
+   nonzero only if successful. */
+int
+dfm_open_for_reading (struct file_handle *h)
 {
-  /* We want to indicate that the file is open, that we are not at
-     eof, and that another line needs to be read in.  */
+  struct dfm_fhuser_ext *ext;
+
+  if (h->class != NULL)
+    {
+      if (h->class == &dfm_r_class)
+        return 1;
+      else
+        {
+          msg (ME, _("Cannot read from file %s already opened for %s."),
+               handle_get_name (h), gettext (h->class->name));
+          return 0;
+        }
+    }
+
+  ext = xmalloc (sizeof *ext);
+  ext->where.filename = handle_get_filename (h);
+  ext->where.line_number = 0;
   ext->file.file = NULL;
   ext->line = xmalloc (128);
-#if !PRODUCTION
-  strcpy (ext->line, _("<<Bug in dfm.c>>"));
-#endif
-  ext->len = strlen (ext->line);
-  ext->ptr = ext->line;
+  ext->len = 0;
+  ext->ptr = NULL;
   ext->size = 128;
   ext->advance = 1;
-}
-
-/* Opens a file handle for reading as a data file. */
-static int
-open_file_r (struct file_handle *h)
-{
-  struct dfm_fhuser_ext ext;
-
-  h->where.line_number = 0;
-  ext.file.file = NULL;
-  ext.line = NULL;
-  ext.len = 0;
-  ext.ptr = NULL;
-  ext.size = 0;
-  ext.advance = 0;
+  ext->saw_begin_data = 0;
 
   msg (VM (1), _("%s: Opening data-file handle %s for reading."),
-       fh_handle_filename (h), fh_handle_name (h));
+       handle_get_filename (h), handle_get_name (h));
   
   assert (h != NULL);
-  if (h == inline_file)
-    {
-      char *s;
-
-      /* WTF can't this just be done with tokens?
-        Is this really a special case?
-        FIXME! */
-      do
-       {
-         char *cp;
-
-         if (!getl_read_line ())
-           {
-             msg (SE, _("BEGIN DATA expected."));
-             err_failure ();
-           }
-
-         /* Skip leading whitespace, separate out first word, so that
-            S points to a single word reduced to lowercase. */
-         s = ds_value (&getl_buf);
-         while (isspace ((unsigned char) *s))
-           s++;
-         for (cp = s; isalpha ((unsigned char) *cp); cp++)
-           *cp = tolower ((unsigned char) (*cp));
-         ds_truncate (&getl_buf, cp - s);
-       }
-      while (*s == '\0');
-
-      if (!lex_id_match_len ("begin", 5, s, strcspn (s, " \t\r\v\n")))
-       {
-         msg (SE, _("BEGIN DATA expected."));
-         err_cond_fail ();
-         lex_preprocess_line ();
-         return 0;
-       }
-      getl_prompt = GETL_PRPT_DATA;
-
-      open_inline_file (&ext);
-    }
-  else
+  if (h != inline_file)
     {
-      ext.file.filename = xstrdup (h->norm_fn);
-      ext.file.mode = "rb";
-      ext.file.file = NULL;
-      ext.file.sequence_no = NULL;
-      ext.file.param = NULL;
-      ext.file.postopen = NULL;
-      ext.file.preclose = NULL;
-      if (!fn_open_ext (&ext.file))
+      ext->file.filename = xstrdup (handle_get_filename (h));
+      ext->file.mode = "rb";
+      ext->file.file = NULL;
+      ext->file.sequence_no = NULL;
+      ext->file.param = NULL;
+      ext->file.postopen = NULL;
+      ext->file.preclose = NULL;
+      if (!fn_open_ext (&ext->file))
        {
-         msg (ME, _("An error occurred while opening \"%s\" for reading "
-              "as a data file: %s."), h->fn, strerror (errno));
-         err_cond_fail ();
-         return 0;
+         msg (ME, _("Could not open \"%s\" for reading "
+                     "as a data file: %s."),
+               handle_get_filename (h), strerror (errno));
+          goto error;
        }
     }
 
   h->class = &dfm_r_class;
-  h->ext = xmalloc (sizeof (struct dfm_fhuser_ext));
-  memcpy (h->ext, &ext, sizeof (struct dfm_fhuser_ext));
-
+  h->ext = ext;
   return 1;
+
+ error:
+  err_cond_fail ();
+  free (ext);
+  return 0;
 }
 
 /* Opens a file handle for writing as a data file. */
-static int
-open_file_w (struct file_handle *h)
+int
+dfm_open_for_writing (struct file_handle *h)
 {
-  struct dfm_fhuser_ext ext;
+  struct dfm_fhuser_ext *ext;
   
-  ext.file.file = NULL;
-  ext.line = NULL;
-  ext.len = 0;
-  ext.ptr = NULL;
-  ext.size = 0;
-  ext.advance = 0;
+  if (h->class != NULL)
+    {
+      if (h->class == &dfm_w_class)
+        return 1;
+      else
+        {
+          msg (ME, _("Cannot write to file %s already opened for %s."),
+               handle_get_name (h), gettext (h->class->name));
+          err_cond_fail ();
+          return 0;
+        }
+    }
 
-  h->where.line_number = 0;
+  ext = xmalloc (sizeof *ext);
+  ext->where.filename = handle_get_filename (h);
+  ext->where.line_number = 0;
+  ext->file.file = NULL;
+  ext->line = NULL;
+  ext->len = 0;
+  ext->ptr = NULL;
+  ext->size = 0;
+  ext->advance = 0;
 
   msg (VM (1), _("%s: Opening data-file handle %s for writing."),
-       fh_handle_filename (h), fh_handle_name (h));
+       handle_get_filename (h), handle_get_name (h));
   
   assert (h != NULL);
   if (h == inline_file)
     {
       msg (ME, _("Cannot open the inline file for writing."));
-      err_cond_fail ();
-      return 0;
+      goto error;
     }
 
-  ext.file.filename = xstrdup (h->norm_fn);
-  ext.file.mode = "wb";
-  ext.file.file = NULL;
-  ext.file.sequence_no = NULL;
-  ext.file.param = NULL;
-  ext.file.postopen = NULL;
-  ext.file.preclose = NULL;
+  ext->file.filename = xstrdup (handle_get_filename (h));
+  ext->file.mode = "wb";
+  ext->file.file = NULL;
+  ext->file.sequence_no = NULL;
+  ext->file.param = NULL;
+  ext->file.postopen = NULL;
+  ext->file.preclose = NULL;
       
-  if (!fn_open_ext (&ext.file))
+  if (!fn_open_ext (&ext->file))
     {
       msg (ME, _("An error occurred while opening \"%s\" for writing "
-          "as a data file: %s."), h->fn, strerror (errno));
-      err_cond_fail ();
-      return 0;
+                 "as a data file: %s."),
+           handle_get_filename (h), strerror (errno));
+      goto error;
     }
 
   h->class = &dfm_w_class;
-  h->ext = xmalloc (sizeof (struct dfm_fhuser_ext));
-  memcpy (h->ext, &ext, sizeof (struct dfm_fhuser_ext));
-
+  h->ext = ext;
   return 1;
+
+ error:
+  free (ext);
+  err_cond_fail ();
+  return 0;
 }
 
 /* Ensures that the line buffer in file handle with extension EXT is
@@ -362,6 +344,44 @@ read_record (struct file_handle *h)
 
   if (h == inline_file)
     {
+      if (!ext->saw_begin_data)
+        {
+          char *s;
+
+          ext->saw_begin_data = 1;
+
+          /* FIXME: WTF can't this just be done with tokens?
+             Is this really a special case? */
+          do
+            {
+              char *cp;
+
+              if (!getl_read_line ())
+                {
+                  msg (SE, _("BEGIN DATA expected."));
+                  err_failure ();
+                }
+
+              /* Skip leading whitespace, separate out first word, so that
+                 S points to a single word reduced to lowercase. */
+              s = ds_value (&getl_buf);
+              while (isspace ((unsigned char) *s))
+                s++;
+              for (cp = s; isalpha ((unsigned char) *cp); cp++)
+                *cp = tolower ((unsigned char) (*cp));
+              ds_truncate (&getl_buf, cp - s);
+            }
+          while (*s == '\0');
+
+          if (!lex_id_match_len ("begin", 5, s, strcspn (s, " \t\r\v\n")))
+            {
+              msg (SE, _("BEGIN DATA expected."));
+              lex_preprocess_line ();
+              goto eof;
+            }
+          getl_prompt = GETL_PRPT_DATA;
+        }
+      
       if (!getl_read_line ())
        {
          msg (SE, _("Unexpected end-of-file while reading data in BEGIN "
@@ -372,7 +392,7 @@ read_record (struct file_handle *h)
          err_failure ();
        }
 
-      h->where.line_number++;
+      ext->where.line_number++;
 
       if (ds_length (&getl_buf) >= 8
          && !strncasecmp (ds_value (&getl_buf), "end data", 8))
@@ -387,7 +407,7 @@ read_record (struct file_handle *h)
     }
   else
     {
-      if (h->recform == FH_RF_VARIABLE)
+      if (handle_get_mode (h) == MODE_TEXT)
        {
          /* PORTME: here you should adapt the routine to your
             system's concept of a "line" of text. */
@@ -398,31 +418,32 @@ read_record (struct file_handle *h)
              if (ferror (ext->file.file))
                {
                  msg (ME, _("Error reading file %s: %s."),
-                      fh_handle_name (h), strerror (errno));
+                      handle_get_name (h), strerror (errno));
                  err_cond_fail ();
                }
              goto eof;
            }
          ext->len = (size_t) read_len;
        }
-      else if (h->recform == FH_RF_FIXED)
+      else if (handle_get_mode (h) == MODE_BINARY)
        {
+          size_t record_width = handle_get_record_width (h);
          size_t amt;
 
-         if (ext->size < h->lrecl)
+         if (ext->size < record_width)
            {
-             ext->size = h->lrecl;
+             ext->size = record_width;
              ext->line = xmalloc (ext->size);
            }
-         amt = fread (ext->line, 1, h->lrecl, ext->file.file);
-         if (h->lrecl != amt)
+         amt = fread (ext->line, 1, record_width, ext->file.file);
+         if (record_width != amt)
            {
              if (ferror (ext->file.file))
                msg (ME, _("Error reading file %s: %s."),
-                    fh_handle_name (h), strerror (errno));
+                    handle_get_name (h), strerror (errno));
              else if (amt != 0)
                msg (ME, _("%s: Partial record at end of file."),
-                    fh_handle_name (h));
+                    handle_get_name (h));
              else
                goto eof;
 
@@ -433,12 +454,12 @@ read_record (struct file_handle *h)
       else
        assert (0);
 
-      h->where.line_number++;
+      ext->where.line_number++;
     }
 
   /* Strip trailing whitespace, I forget why.  But there's a good
      reason, I'm sure.  I'm too scared to eliminate this code.  */
-  if (h->recform == FH_RF_VARIABLE)
+  if (handle_get_mode (h) == MODE_TEXT)
     {
       while (ext->len && isspace ((unsigned char) ext->line[ext->len - 1]))
        ext->len--;
@@ -451,7 +472,7 @@ read_record (struct file_handle *h)
   return;
 
 eof:
-  /*hit eof or an error, clean up everything. */
+  /* Hit eof or an error, clean up everything. */
   if (ext->line)
     free (ext->line);
   ext->size = 0;
@@ -469,50 +490,29 @@ eof:
 char *
 dfm_get_record (struct file_handle *h, int *len)
 {
+  struct dfm_fhuser_ext *ext;
+  
   assert (h != NULL);
+  assert (h->class == &dfm_r_class);
+  assert (h->ext != NULL);
 
-  if (h->class == NULL)
-    {
-      if (!open_file_r (h))
-       return NULL;
-      read_record (h);
-    }
-  else if (h->class != &dfm_r_class)
+  ext = h->ext;
+  if (ext->advance)
     {
-      msg (ME, _("Cannot read from file %s already opened for %s."),
-          fh_handle_name (h), gettext (h->class->name));
-      goto lossage;
-    }
-  else
-    {
-      struct dfm_fhuser_ext *ext = h->ext;
-
-      if (ext->advance)
-       {
-         if (ext->line)
-           read_record (h);
-         else
-           {
-             msg (SE, _("Attempt to read beyond end-of-file on file %s."),
-                  fh_handle_name (h));
-             goto lossage;
-           }
-       }
+      if (ext->line)
+        read_record (h);
+      else
+        {
+          msg (SE, _("Attempt to read beyond end-of-file on file %s."),
+               handle_get_name (h));
+          goto lossage;
+        }
     }
 
-  {
-    struct dfm_fhuser_ext *ext = h->ext;
-
-    if (ext)
-      {
-       ext->advance = 0;
-       if (len)
-         *len = ext->len - (ext->ptr - ext->line);
-       return ext->ptr;
-      }
-  }
-
-  return NULL;
+  ext->advance = 0;
+  if (len)
+    *len = ext->len - (ext->ptr - ext->line);
+  return ext->ptr;
 
 lossage:
   /* Come here on reading beyond eof or reading from a file already
@@ -577,31 +577,21 @@ dfm_get_cur_col (struct file_handle *h)
 int
 dfm_put_record (struct file_handle *h, const char *rec, size_t len)
 {
+  struct dfm_fhuser_ext *ext;
   char *ptr;
   size_t amt;
 
-  if (h->class == NULL)
-    {
-      if (!open_file_w (h))
-       return 0;
-    }
-  else if (h->class != &dfm_w_class)
-    {
-      msg (ME, _("Cannot write to file %s already opened for %s."),
-          fh_handle_name (h), gettext (h->class->name));
-      err_cond_fail ();
-      return 0;
-    }
+  assert (h != NULL);
+  assert (h->class == &dfm_w_class);
+  assert (h->ext != NULL);
 
-  if (h->recform == FH_RF_FIXED && len < h->lrecl)
+  ext = h->ext;
+  if (handle_get_mode (h) == MODE_BINARY && len < handle_get_record_width (h))
     {
-      int ch;
-
-      amt = h->lrecl;
+      amt = handle_get_record_width (h);
       ptr = local_alloc (amt);
       memcpy (ptr, rec, len);
-      ch = h->mode == FH_MD_CHARACTER ? ' ' : 0;
-      memset (&ptr[len], ch, amt - len);
+      memset (&ptr[len], 0, amt - len);
     }
   else
     {
@@ -609,10 +599,10 @@ dfm_put_record (struct file_handle *h, const char *rec, size_t len)
       amt = len;
     }
 
-  if (1 != fwrite (ptr, amt, 1, ((struct dfm_fhuser_ext *) h->ext)->file.file))
+  if (1 != fwrite (ptr, amt, 1, ext->file.file))
     {
-      msg (ME, _("Error writing file %s: %s."), fh_handle_name (h),
-          strerror (errno));
+      msg (ME, _("Error writing file %s: %s."),
+           handle_get_name (h), strerror (errno));
       err_cond_fail ();
       return 0;
     }
@@ -627,16 +617,24 @@ dfm_put_record (struct file_handle *h, const char *rec, size_t len)
 void
 dfm_push (struct file_handle *h)
 {
+  struct dfm_fhuser_ext *ext = h->ext;
+
+  assert (h->class == &dfm_r_class || h->class == &dfm_w_class);
+  assert (ext != NULL);
   if (h != inline_file)
-    err_push_file_locator (&h->where);
+    err_push_file_locator (&ext->where);
 }
 
 /* Pops the filename and line number from the fn/ln stack. */
 void
 dfm_pop (struct file_handle *h)
 {
+  struct dfm_fhuser_ext *ext = h->ext;
+
+  assert (h->class == &dfm_r_class || h->class == &dfm_w_class);
+  assert (ext != NULL);
   if (h != inline_file)
-    err_pop_file_locator (&h->where);
+    err_pop_file_locator (&ext->where);
 }
 \f
 /* BEGIN DATA...END DATA procedure. */
@@ -661,17 +659,16 @@ cmd_begin_data (void)
 
   /* Initialize inline_file. */
   msg (VM (1), _("inline file: Opening for reading."));
-  inline_file->class = &dfm_r_class;
-  inline_file->ext = xmalloc (sizeof (struct dfm_fhuser_ext));
-  open_inline_file (inline_file->ext);
+  dfm_open_for_reading (inline_file);
+  ext = inline_file->ext;
+  ext->saw_begin_data = 1;
 
   /* We don't actually read from the inline file.  The input procedure
      is what reads from it. */
   getl_prompt = GETL_PRPT_DATA;
   procedure (NULL, NULL);
-
+  
   ext = inline_file->ext;
-
   if (ext && ext->line)
     {
       msg (MW, _("Skipping remaining inline data."));
index f561a45eee2592980a30ad0037d57d934656498c..30f12846a808b7869ff134afcb4a25bed2549ed6 100644 (file)
--- a/src/dfm.h
+++ b/src/dfm.h
@@ -30,6 +30,8 @@
 
 /* I/O utilities. */
 struct file_handle;
+int dfm_open_for_reading (struct file_handle *handle);
+int dfm_open_for_writing (struct file_handle *handle);
 char *dfm_get_record (struct file_handle *handle, int *len);
 int dfm_put_record (struct file_handle *handle, const char *rec, size_t len);
 
index 339710696326035de2bf4ec760a9b05dedfe246f..0dd6466a52895ea9c2fe475c4ad2dcab20d34a78 100644 (file)
@@ -155,8 +155,6 @@ cmd_else (void)
 {
   struct do_if_trns *t;
 
-  lex_match_id ("ELSE");
-
   /* Check that we're in a pleasing situation. */
   if (!ctl_stack || ctl_stack->type != CST_DO_IF)
     {
@@ -198,8 +196,6 @@ cmd_end_if (void)
   /* List iterator. */
   struct do_if_trns *iter;
 
-  lex_match_id ("IF");
-
   /* Check that we're in a pleasing situation. */
   if (!ctl_stack || ctl_stack->type != CST_DO_IF)
     {
@@ -252,8 +248,6 @@ parse_do_if (void)
   struct do_if_trns *t;
   struct expression *e;
 
-  lex_match_id ("IF");
-
   e = expr_parse (PXP_BOOLEAN);
   if (!e)
     return NULL;
index 3dadab42464d624bb9a429f54ef47b6c027045fe..65a7b0f10a2bf3c035068387c4138c153e936c77 100644 (file)
@@ -102,6 +102,8 @@ msg (int class, const char *format, ...)
     e.text = buf.string;
     err_vmsg (&e);
   }
+
+  ds_destroy (&buf);
 }
 
 /* Terminate due to fatal error in input. */
index 62a9f6b2eae6b9768c6d990111f829fb7ff40932..d031eff6a0e6fbc687c9f6021b5df276a9e6bf53 100644 (file)
@@ -1167,6 +1167,7 @@ expr_evaluate (struct expression *e, const struct ccase *c, int case_num,
                sp->f = SYSMIS;
                break;
              }
+            assert (c != NULL);
            sp->f = c->data[v->var[rindx - 1]->fv].f;
          }
          break;
@@ -1195,6 +1196,7 @@ expr_evaluate (struct expression *e, const struct ccase *c, int case_num,
            v = vect->var[rindx - 1];
            sp->c = pool_alloc (e->pool, v->width + 1);
            sp->c[0] = v->width;
+            assert (c != NULL);
            memcpy (&sp->c[1], c->data[v->fv].s, v->width);
          }
          break;
@@ -1212,6 +1214,7 @@ expr_evaluate (struct expression *e, const struct ccase *c, int case_num,
          break;
        case OP_NUM_VAR:
          sp++;
+          assert (c != NULL);
          sp->f = c->data[(*vars)->fv].f;
          if (is_num_user_missing (sp->f, *vars))
            sp->f = SYSMIS;
@@ -1224,6 +1227,7 @@ expr_evaluate (struct expression *e, const struct ccase *c, int case_num,
            sp++;
            sp->c = pool_alloc (e->pool, width + 1);
            sp->c[0] = width;
+            assert (c != NULL);
            memcpy (&sp->c[1], &c->data[(*vars)->fv], width);
            vars++;
          }
@@ -1263,15 +1267,18 @@ expr_evaluate (struct expression *e, const struct ccase *c, int case_num,
          break;
        case OP_NUM_SYS:
          sp++;
+          assert (c != NULL);
          sp->f = c->data[*op++].f == SYSMIS;
          break;
        case OP_STR_MIS:
          sp++;
+          assert (c != NULL);
          sp->f = is_str_user_missing (c->data[(*vars)->fv].s, *vars);
          vars++;
          break;
        case OP_NUM_VAL:
          sp++;
+          assert (c != NULL);
          sp->f = c->data[*op++].f;
          break;
        case OP_CASENUM:
index fee00a3e93e1525917485f15cf7726c3a0245f8b..701347894d31cb749304f3a271b4204ad29f2c6c 100644 (file)
@@ -120,10 +120,7 @@ expr_parse (int flags)
 
   /* If we're debugging or the user requested it, print the postfix
      representation. */
-#if GLOBAL_DEBUGGING
-#if !DEBUGGING
-  if (flags & PXP_DUMP)
-#endif
+#if DEBUGGING
     debug_print_postfix (e);
 #endif
 
index 5a1da2aef94f9b9ff28cf2b0f2dac6378af0ebd7..e2cc9e3657f25e880550f3c4ec9434e6e4ae3a42 100644 (file)
@@ -24,8 +24,6 @@
 enum
   {
     PXP_NONE = 000,            /* No flags. */
-    PXP_DUMP = 001,            /* Dump postfix representation to screen;
-                                  only for use by EVALUATE. */
 
     /* Specify expression type. */
     PXP_BOOLEAN = 002,         /* Coerce return value to Boolean. */
index c7b455053592a7fde5efcb8a39a2225799528add..145d520228cb644f3308014299b3040a8e24f15d 100644 (file)
 #include <stddef.h>
 #include "error.h"
 
-/* Record formats. */
-enum
-  {
-    FH_RF_FIXED,               /* Fixed length records. */
-    FH_RF_VARIABLE,            /* Variable length records. */
-    FH_RF_SPANNED              /* ? */
-  };
-
-/* File modes. */
-enum
-  {
-    FH_MD_CHARACTER,           /* Character data. */
-    FH_MD_IMAGE,               /* ? */
-    FH_MD_BINARY,              /* Character and/or binary data. */
-    FH_MD_MULTIPUNCH,          /* Column binary data (not supported). */
-    FH_MD_360                  /* ? */
-  };
-
 struct file_handle;
 
 /* Services that fhusers provide to fhp. */
@@ -56,28 +38,24 @@ struct fh_ext_class
     int magic;                 /* Magic identifier for fhuser. */
     const char *name;          /* String identifier for fhuser. */
 
-    void (*close) (struct file_handle *);
-                               /* Closes any associated file, etc. */
+    void (*close) (struct file_handle *); /* Closes the file. */
   };
 
-/* Opaque structure.  The `ext' member is an exception for use by
-   subclasses.  `where.ln' is also acceptable. */
+/* Mostly-opaque structure. */
 struct file_handle
   {
-    /* name must be the first member. */
-    const char *name;          /* File handle identifier. */
-    char *norm_fn;             /* Normalized filename. */
-    char *fn;                  /* Filename as provided by user. */
-    struct file_locator where; /* Used for reporting error messages. */
-
-    int recform;               /* One of FH_RF_*. */
-    size_t lrecl;              /* Length of records for FH_RF_FIXED. */
-    int mode;                  /* One of FH_MD_*. */
-
-    struct fh_ext_class *class;        /* Polymorphism support. */
+    struct private_file_handle *private;
+    const struct fh_ext_class *class;  /* Polymorphism support. */
     void *ext;                 /* Extension struct for fhuser use. */
   };
 
+/* File modes. */
+enum file_handle_mode
+  {
+    MODE_TEXT,                  /* New-line delimited lines. */
+    MODE_BINARY                 /* Fixed-length records. */
+  };
+
 /* Pointer to the file handle that corresponds to data in the command
    file entered via BEGIN DATA/END DATA. */
 extern struct file_handle *inline_file;
@@ -86,14 +64,13 @@ extern struct file_handle *inline_file;
 void fh_init_files (void);
 
 /* Opening and closing handles. */
-struct file_handle *fh_get_handle_by_name (const char name[9]);
-struct file_handle *fh_get_handle_by_filename (const char *filename);
 struct file_handle *fh_parse_file_handle (void);
 void fh_close_handle (struct file_handle *handle);
 
 /* Handle info. */
-const char *fh_handle_name (const struct file_handle *handle);
-char *fh_handle_filename (struct file_handle *handle);
-size_t fh_record_width (struct file_handle *handle);
+const char *handle_get_name (const struct file_handle *handle);
+const char *handle_get_filename (const struct file_handle *handle);
+enum file_handle_mode handle_get_mode (const struct file_handle *);
+size_t handle_get_record_width (const struct file_handle *);
 
 #endif /* !file_handle.h */
index 77291a45e42836595c071150a754ab3691a0fa2d..dc1e9383c60abfa16260cae8d38694ef7f5ff908 100644 (file)
@@ -25,7 +25,6 @@
 #include "alloc.h"
 #include "filename.h"
 #include "command.h"
-#include "hash.h"
 #include "lexer.h"
 #include "getline.h"
 #include "error.h"
 #include "var.h"
 /* (headers) */
 
-#include "debug-print.h"
-
-static struct hsh_table *files;
+/* File handle private data. */
+struct private_file_handle 
+  {
+    char *name;                 /* File handle identifier. */
+    char *filename;            /* Filename as provided by user. */
+    struct file_identity *identity; /* For checking file identity. */
+    struct file_locator where; /* Used for reporting error messages. */
+    enum file_handle_mode mode;        /* File mode. */
+    size_t length;             /* Length of fixed-format records. */
+  };
+
+/* Linked list of file handles. */
+struct file_handle_list 
+  {
+    struct file_handle *handle;
+    struct file_handle_list *next;
+  };
+
+static struct file_handle_list *file_handles;
 struct file_handle *inline_file;
 
-static void init_file_handle (struct file_handle * handle);
+static struct file_handle *create_file_handle (const char *handle_name,
+                                               const char *filename);
 
 /* (specification)
    "FILE HANDLE" (fh_):
@@ -50,29 +66,65 @@ static void init_file_handle (struct file_handle * handle);
 /* (declarations) */
 /* (functions) */
 
+static struct file_handle *
+get_handle_with_name (const char *handle_name) 
+{
+  struct file_handle_list *iter;
+
+  for (iter = file_handles; iter != NULL; iter = iter->next)
+    if (!strcmp (handle_name, iter->handle->private->name))
+      return iter->handle;
+  return NULL;
+}
+
+static struct file_handle *
+get_handle_for_filename (const char *filename)
+{
+  struct file_identity *identity;
+  struct file_handle_list *iter;
+      
+  /* First check for a file with the same identity. */
+  identity = fn_get_identity (filename);
+  if (identity != NULL) 
+    {
+      for (iter = file_handles; iter != NULL; iter = iter->next)
+        if (iter->handle->private->identity != NULL
+            && !fn_compare_file_identities (identity,
+                                         iter->handle->private->identity)) 
+          {
+            fn_free_identity (identity);
+            return iter->handle; 
+          }
+      fn_free_identity (identity);
+    }
+
+  /* Then check for a file with the same name. */
+  for (iter = file_handles; iter != NULL; iter = iter->next)
+    if (!strcmp (filename, iter->handle->private->filename))
+      return iter->handle; 
+
+  return NULL;
+}
+
 int
 cmd_file_handle (void)
 {
   char handle_name[9];
-  char *handle_name_p = handle_name;
 
   struct cmd_file_handle cmd;
-  struct file_handle *fp;
+  struct file_handle *handle;
 
-  lex_get ();
   if (!lex_force_id ())
     return CMD_FAILURE;
   strcpy (handle_name, tokid);
 
-  fp = NULL;
-  if (files)
-    fp = hsh_find (files, &handle_name_p);
-  if (fp)
+  handle = get_handle_with_name (handle_name);
+  if (handle != NULL)
     {
-      msg (SE, _("File handle %s had already been defined to refer to "
-                "file %s.  It is not possible to redefine a file "
-                "handle within a session."),
-          tokid, fp->fn);
+      msg (SE, _("File handle %s already refers to "
+                "file %s.  File handle cannot be redefined within a "
+                 "session."),
+          tokid, handle->private->filename);
       return CMD_FAILURE;
     }
 
@@ -96,68 +148,34 @@ cmd_file_handle (void)
       goto lossage;
     }
 
-  fp = xmalloc (sizeof *fp);
-  init_file_handle (fp);
-
-  switch (cmd.recform)
+  handle = create_file_handle (handle_name, cmd.s_name);
+  switch (cmd.mode)
     {
-    case FH_FIXED:
+    case FH_CHARACTER:
+      handle->private->mode = MODE_TEXT;
+      break;
+    case FH_IMAGE:
+      handle->private->mode = MODE_BINARY;
       if (cmd.n_lrecl == NOT_LONG)
        {
-         msg (SE, _("Fixed length records were specified on /RECFORM, but "
-              "record length was not specified on /LRECL.  80-character "
-              "records will be assumed."));
-         cmd.n_lrecl = 80;
+         msg (SE, _("Fixed-length records were specified on /RECFORM, but "
+                     "record length was not specified on /LRECL.  "
+                     "Assuming 1024-character records."));
+          handle->private->length = 1024;
        }
       else if (cmd.n_lrecl < 1)
        {
          msg (SE, _("Record length (%ld) must be at least one byte.  "
-                    "80-character records will be assumed."), cmd.n_lrecl);
-         cmd.n_lrecl = 80;
+                    "1-character records will be assumed."), cmd.n_lrecl);
+          handle->private->length = 1;
        }
-      fp->recform = FH_RF_FIXED;
-      fp->lrecl = cmd.n_lrecl;
-      break;
-    case FH_VARIABLE:
-      fp->recform = FH_RF_VARIABLE;
-      break;
-    case FH_SPANNED:
-      msg (SE, 
-          _("%s is not implemented, as the author doesn't know what it is supposed to do.  Send a note to %s.") ,
-          "/RECFORM SPANNED",PACKAGE_BUGREPORT);
-      break;
-    default:
-      assert (0);
-    }
-
-  switch (cmd.mode)
-    {
-    case FH_CHARACTER:
-      fp->mode = FH_MD_CHARACTER;
-      break;
-    case FH_IMAGE:
-      msg (SE, 
-          _("%s is not implemented, as the author doesn't know what it is supposed to do.  Send a note to %s.") ,
-          "/MODE IMAGE",PACKAGE_BUGREPORT);
-      break;
-    case FH_BINARY:
-      fp->mode = FH_MD_BINARY;
-      break;
-    case FH_MULTIPUNCH:
-      msg (SE, _("%s is not implemented.  If you care, complain."),"/MODE MULTIPUNCH");
-      break;
-    case FH__360:
-      msg (SE, _("%s is not implemented.  If you care, complain."),"/MODE 360");
+      else
+        handle->private->length = cmd.n_lrecl;
       break;
     default:
       assert (0);
     }
 
-  fp->name = xstrdup (handle_name);
-  fp->norm_fn = fn_normalize (cmd.s_name);
-  fp->where.filename = fp->fn = cmd.s_name;
-  hsh_force_insert (files, fp);
-
   return CMD_SUCCESS;
 
  lossage:
@@ -167,103 +185,35 @@ cmd_file_handle (void)
 \f
 /* File handle functions. */
 
-/* Sets up some fields in H; caller should fill in
-   H->{NAME,NORM_FN,FN}. */
-static void
-init_file_handle (struct file_handle *h)
+/* Creates and returns a new file handle with the given values
+   and defaults for other values.  Adds the created file handle
+   to the global list. */
+static struct file_handle *
+create_file_handle (const char *handle_name, const char *filename)
 {
-  h->recform = FH_RF_VARIABLE;
-  h->mode = FH_MD_CHARACTER;
-  h->ext = NULL;
-  h->class = NULL;
-}
-
-/* Returns the handle corresponding to FILENAME.  Creates the handle
-   if no handle exists for that file.  All filenames are normalized
-   first, so different filenames referring to the same file will
-   return the same file handle. */
-struct file_handle *
-fh_get_handle_by_filename (const char *filename)
-{
-  struct file_handle f, *fp;
-  char *fn;
-  char *name;
-  int len;
-
-  /* Get filename. */
-  fn = fn_normalize (filename);
-  len = strlen (fn);
-
-  /* Create handle name with invalid identifier character to prevent
-     conflicts with handles created with FILE HANDLE. */
-  name = xmalloc (len + 2);
-  name[0] = '*';
-  strcpy (&name[1], fn);
-
-  f.name = name;
-  fp = hsh_find (files, &f);
-  if (!fp)
-    {
-      fp = xmalloc (sizeof *fp);
-      init_file_handle (fp);
-      fp->name = name;
-      fp->norm_fn = fn;
-      fp->where.filename = fp->fn = xstrdup (filename);
-      hsh_force_insert (files, fp);
-    }
-  else
-    {
-      free (fn);
-      free (name);
-    }
-  return fp;
-}
-
-/* Returns the handle with identifier NAME, if it exists; otherwise
-   reports error to user and returns NULL. */
-struct file_handle *
-fh_get_handle_by_name (const char name[9])
-{
-  struct file_handle f, *fp;
-  f.name = (char *) name;
-  fp = hsh_find (files, &f);
-
-  if (!fp)
-    msg (SE, _("File handle `%s' has not been previously declared on "
-        "FILE HANDLE."), name);
-  return fp;
-}
-
-/* Returns the identifier of file HANDLE.  If HANDLE was created by
-   referring to a filename (i.e., DATA LIST FILE='yyy' instead of FILE
-   HANDLE XXX='yyy'), returns the filename, enclosed in double quotes.
-   Return value is in a static buffer.
-
-   Useful for printing error messages about use of file handles.  */
-const char *
-fh_handle_name (const struct file_handle *h)
-{
-  static char *buf = NULL;
-
-  if (buf)
-    {
-      free (buf);
-      buf = NULL;
-    }
-  if (!h)
-    return NULL;
-
-  if (h->name[0] == '*')
-    {
-      int len = strlen (h->fn);
+  struct file_handle *handle;
+  struct file_handle_list *list;
+
+  /* Create and initialize file handle. */
+  handle = xmalloc (sizeof *handle);
+  handle->private = xmalloc (sizeof *handle->private);
+  handle->private->name = xstrdup (handle_name);
+  handle->private->filename = xstrdup (filename);
+  handle->private->identity = fn_get_identity (filename);
+  handle->private->where.filename = handle->private->filename;
+  handle->private->where.line_number = 0;
+  handle->private->mode = MODE_TEXT;
+  handle->private->length = 1024;
+  handle->ext = NULL;
+  handle->class = NULL;
+
+  /* Add file handle to global list. */
+  list = xmalloc (sizeof *list);
+  list->handle = handle;
+  list->next = file_handles;
+  file_handles = list;
 
-      buf = xmalloc (len + 3);
-      strcpy (&buf[1], h->fn);
-      buf[0] = buf[len + 1] = '"';
-      buf[len + 2] = 0;
-      return buf;
-    }
-  return h->name;
+  return handle;
 }
 
 /* Closes the stdio FILE associated with handle H.  Frees internal
@@ -275,50 +225,22 @@ fh_close_handle (struct file_handle *h)
   if (h == NULL)
     return;
 
-  debug_printf (("Closing %s%s.\n", fh_handle_name (h),
-                h->class == NULL ? " (already closed)" : ""));
-
-  if (h->class)
+  if (h->class != NULL)
     h->class->close (h);
   h->class = NULL;
   h->ext = NULL;
 }
 
-/* Hashes the name of file handle H. */
-static unsigned
-hash_file_handle (const void *handle_, void *param UNUSED)
-{
-  const struct file_handle *handle = handle_;
-
-  return hsh_hash_string (handle->name);
-}
-
-/* Compares names of file handles A and B. */
-static int
-cmp_file_handle (const void *a_, const void *b_, void *foo UNUSED)
-{
-  const struct file_handle *a = a_;
-  const struct file_handle *b = b_;
-
-  return strcmp (a->name, b->name);
-}
-
 /* Initialize the hash of file handles; inserts the "inline file"
    inline_file. */
 void
 fh_init_files (void)
 {
-  /* Create hash. */
-  files = hsh_create (4, cmp_file_handle, hash_file_handle, NULL, NULL);
-
-  /* Insert inline file. */
-  inline_file = xmalloc (sizeof *inline_file);
-  init_file_handle (inline_file);
-  inline_file->name = "INLINE";
-  inline_file->where.filename
-    = inline_file->fn = inline_file->norm_fn = (char *) _("<Inline File>");
-  inline_file->where.line_number = 0;
-  hsh_force_insert (files, inline_file);
+  if (inline_file == NULL) 
+    {
+      inline_file = create_file_handle ("INLINE", _("<Inline File>"));
+      inline_file->private->length = 80; 
+    }
 }
 
 /* Parses a file handle name, which may be a filename as a string or
@@ -329,40 +251,65 @@ fh_parse_file_handle (void)
 {
   struct file_handle *handle;
 
-  if (token == T_ID)
-    handle = fh_get_handle_by_name (tokid);
-  else if (token == T_STRING)
-    handle = fh_get_handle_by_filename (ds_value (&tokstr));
-  else
+  if (token != T_ID && token != T_STRING)
     {
-      lex_error (_("expecting a file name or handle"));
+      lex_error (_("expecting a file name or handle name"));
       return NULL;
     }
 
-  if (!handle)
-    return NULL;
+  /* Check for named handles first, then go by filename. */
+  handle = NULL;
+  if (token == T_ID) 
+    handle = get_handle_with_name (tokid);
+  if (handle == NULL)
+    handle = get_handle_for_filename (ds_value (&tokstr));
+  if (handle == NULL) 
+    {
+      char *filename = ds_value (&tokstr);
+      char *handle_name = xmalloc (strlen (filename) + 3);
+      sprintf (handle_name, "\"%s\"", filename);
+      handle = create_file_handle (handle_name, filename);
+      free (handle_name);
+    }
+
   lex_get ();
 
   return handle;
 }
 
-/* Returns the (normalized) filename associated with file handle H. */
-char *
-fh_handle_filename (struct file_handle * h)
+/* Returns the identifier of file HANDLE.  If HANDLE was created
+   by referring to a filename instead of a handle name, returns
+   the filename, enclosed in double quotes.  Return value is
+   owned by the file handle. 
+
+   Useful for printing error messages about use of file handles.  */
+const char *
+handle_get_name (const struct file_handle *handle)
+{
+  return handle->private->name;
+}
+
+/* Returns the name of the file associated with HANDLE. */
+const char *
+handle_get_filename (const struct file_handle *handle) 
+{
+  return handle->private->filename;
+}
+
+/* Returns the mode of HANDLE. */
+enum file_handle_mode
+handle_get_mode (const struct file_handle *handle) 
 {
-  return h->norm_fn;
+  assert (handle != NULL);
+  return handle->private->mode;
 }
 
-/* Returns the width of a logical record on file handle H. */
+/* Returns the width of a logical record on HANDLE. */
 size_t
-fh_record_width (struct file_handle *h)
+handle_get_record_width (const struct file_handle *handle)
 {
-  if (h == inline_file)
-    return 80;
-  else if (h->recform == FH_RF_FIXED)
-    return h->lrecl;
-  else
-    return 1024;
+  assert (handle != NULL);
+  return handle->private->length;
 }
 
 /*
index e5e3d81e9fde266feb938c8637abadcc4b598bb8..89a97938668b283793bd2821b404a4eb0c817106 100644 (file)
@@ -109,7 +109,6 @@ cmd_file_type (void)
   fty->had_rec_type = 0;
   fty->recs_head = fty->recs_tail = NULL;
 
-  lex_match_id ("TYPE");
   if (lex_match_id ("MIXED"))
     fty->type = FTY_MIXED;
   else if (lex_match_id ("GROUPED"))
@@ -270,6 +269,8 @@ cmd_file_type (void)
        }
     }
 
+  if (!dfm_open_for_reading (fty->handle))
+    goto error;
   default_handle = fty->handle;
 
   create_col_var (&fty->record);
@@ -423,9 +424,6 @@ cmd_record_type (void)
        }
     }
 
-  lex_match_id ("RECORD");
-  lex_match_id ("TYPE");
-
   /* Parse record type values. */
   if (lex_match_id ("OTHER"))
     rct->flags |= RCT_OTHER;
@@ -582,8 +580,6 @@ cmd_end_file_type (void)
   fty = vfm_source->aux;
   fty->case_size = dict_get_case_size (default_dict);
 
-  lex_match_id ("TYPE");
-
   if (fty->recs_tail)
     {
       fty->recs_tail->lt = n_trns - 1;
index a56918f334c4686443c0028843233798ae66d0ab..f666674b31886e76c2e3496437146a8686ab4e6e 100644 (file)
@@ -854,3 +854,93 @@ fn_close_ext (struct file_ext *f)
     }
   return 1;
 }
+
+#ifdef unix
+/* A file's identity. */
+struct file_identity 
+  {
+    dev_t device;               /* Device number. */
+    ino_t inode;                /* Inode number. */
+  };
+
+/* Returns a pointer to a dynamically allocated structure whose
+   value can be used to tell whether two files are actually the
+   same file.  Returns a null pointer if no information about the
+   file is available, perhaps because it does not exist.  The
+   caller is responsible for freeing the structure with
+   fn_free_identity() when finished. */  
+struct file_identity *
+fn_get_identity (const char *filename) 
+{
+  struct stat s;
+
+  if (stat (filename, &s) == 0) 
+    {
+      struct file_identity *identity = xmalloc (sizeof *identity);
+      identity->device = s.st_dev;
+      identity->inode = s.st_ino;
+      return identity;
+    }
+  else
+    return NULL;
+}
+
+/* Frees IDENTITY obtained from fn_get_identity(). */
+void
+fn_free_identity (struct file_identity *identity) 
+{
+  free (identity);
+}
+
+/* Compares A and B, returning a strcmp()-type result. */
+int
+fn_compare_file_identities (const struct file_identity *a,
+                            const struct file_identity *b) 
+{
+  assert (a != NULL);
+  assert (b != NULL);
+  if (a->device != b->device)
+    return a->device < b->device ? -1 : 1;
+  else
+    return a->inode < b->inode ? -1 : a->inode > b->inode;
+}
+#else /* not unix */
+/* A file's identity. */
+struct file_identity 
+  {
+    char *normalized_filename;  /* File's normalized name. */
+  };
+
+/* Returns a pointer to a dynamically allocated structure whose
+   value can be used to tell whether two files are actually the
+   same file.  Returns a null pointer if no information about the
+   file is available, perhaps because it does not exist.  The
+   caller is responsible for freeing the structure with
+   fn_free_identity() when finished. */  
+struct file_identity *
+fn_get_identity (const char *filename) 
+{
+  struct file_identity *identity = xmalloc (sizeof *identity);
+  identity->normalized_filename = fn_normalize (filename);
+  return identity;
+}
+
+/* Frees IDENTITY obtained from fn_get_identity(). */
+void
+fn_free_identity (struct file_identity *identity) 
+{
+  if (identity != NULL) 
+    {
+      free (identity->normalized_filename);
+      free (identity);
+    }
+}
+
+/* Compares A and B, returning a strcmp()-type result. */
+int
+fn_compare_file_identities (const struct file_identity *a,
+                            const struct file_identity *b) 
+{
+  return strcmp (a->normalized_filename, b->normalized_filename);
+}
+#endif /* not unix */
index 499e693bc42ce370b02fb2dbcbbfe6dbfaa93795..9b3f5ab80fa38cce85ade4aa6d7f93491c13b258 100644 (file)
@@ -48,6 +48,11 @@ const char *fn_getenv_default (const char *variable, const char *def);
 
 FILE *fn_open (const char *fn, const char *mode);
 int fn_close (const char *fn, FILE *file);
+
+struct file_identity *fn_get_identity (const char *filename);
+void fn_free_identity (struct file_identity *);
+int fn_compare_file_identities (const struct file_identity *,
+                                const struct file_identity *);
 \f
 /* Extended file routines. */
 struct file_ext;
index 5fd1dea30fa15fdd908446e20e01e15dd66c83cd..6bd6a243907f6632712fd64aa48419764a56e67e 100644 (file)
@@ -87,7 +87,6 @@ cmd_flip (void)
   flip->new_names_tail = NULL;
   flip->file = NULL;
 
-  lex_match_id ("FLIP");
   lex_match ('/');
   if (lex_match_id ("VARIABLES"))
     {
index 9198b0ad35ce7dbdb0843d364361098cae921f64..36c019c01d07d50f15c7019a9a007718c0f4260c 100644 (file)
@@ -45,21 +45,18 @@ static int internal_cmd_formats (int);
 int
 cmd_print_formats (void)
 {
-  lex_match_id ("FORMATS");
   return internal_cmd_formats (FORMATS_PRINT);
 }
 
 int
 cmd_write_formats (void)
 {
-  lex_match_id ("FORMATS");
   return internal_cmd_formats (FORMATS_WRITE);
 }
 
 int
 cmd_formats (void)
 {
-  lex_match_id ("FORMATS");
   return internal_cmd_formats (FORMATS_PRINT | FORMATS_WRITE);
 }
 
index e46bb1dc3839415d9d03bde87de3367b47e4321c..37862b5ac50938445b8ec3003d78c3791cd552a0 100644 (file)
@@ -211,7 +211,6 @@ internal_cmd_frequencies (void)
   for (i = 0; i < dict_get_var_cnt (default_dict); i++)
     dict_get_var(default_dict, i)->p.frq.used = 0;
 
-  lex_match_id ("FREQUENCIES");
   if (!parse_frequencies (&cmd))
     return CMD_FAILURE;
 
index c33680fd5a4c11f939c03d9274f68cc84af7cfb5..17722ce664b984e51109a6aaa79f36830deca0d0 100644 (file)
--- a/src/get.c
+++ b/src/get.c
@@ -79,7 +79,6 @@ cmd_get (void)
   struct get_pgm *pgm;
   int options = GTSV_OPT_NONE;
 
-  lex_match_id ("GET");
   discard_variables ();
 
   lex_match ('/');
@@ -150,8 +149,6 @@ cmd_save_internal (enum save_cmd save_cmd)
 
   int i;
 
-  lex_match_id ("SAVE");
-
   lex_match ('/');
   if (lex_match_id ("OUTFILE"))
     lex_match ('=');
@@ -586,9 +583,6 @@ cmd_match_files (void)
   
   int seen = 0;
   
-  lex_match_id ("MATCH");
-  lex_match_id ("FILES");
-
   mtf.head = mtf.tail = NULL;
   mtf.by = NULL;
   mtf.by_cnt = 0;
@@ -826,7 +820,7 @@ cmd_match_files (void)
              if (iter->by[i] == NULL)
                {
                  msg (SE, _("File %s lacks BY variable %s."),
-                      iter->handle ? fh_handle_name (iter->handle) : "*",
+                      iter->handle ? handle_get_name (iter->handle) : "*",
                       mtf.by[i]->name);
                  goto lossage;
                }
@@ -1341,7 +1335,7 @@ mtf_merge_dictionary (struct dictionary *const m, struct mtf_file *f)
            msg (SE, _("Variable %s in file %s (%s) has different "
                       "type or width from the same variable in "
                       "earlier file (%s)."),
-                dv->name, fh_handle_name (f->handle),
+                dv->name, handle_get_name (f->handle),
                 var_type_description (dv), var_type_description (mv));
            return 0;
          }
@@ -1364,8 +1358,6 @@ cmd_import (void)
   int options = GTSV_OPT_NONE;
   int type;
 
-  lex_match_id ("IMPORT");
-
   for (;;)
     {
       lex_match ('/');
@@ -1479,8 +1471,6 @@ cmd_export (void)
 
   int i;
 
-  lex_match_id ("EXPORT");
-
   lex_match ('/');
   if (lex_match_id ("OUTFILE"))
     lex_match ('=');
index 78557bdd3777c07141369ee543a31a3c218af80f..19f5ca1b8f6f645219725e6993821d04fe788a53 100644 (file)
 #include "str.h"
 
 int
-cmd_include_at (void)
+cmd_include (void)
 {
-  char *incfn, *s, *bp, *ep;
-
-  s = bp = lex_entire_line ();
-  while (isspace ((unsigned char) *bp))
-    bp++;
-  bp++;                                /* skip `@' */
-  while (isspace ((unsigned char) *bp))
-    bp++;
-  if (*bp == '\'')
-    bp++;
-
-  ep = bp + strlen (bp);
-  while (isspace ((unsigned char) *--ep));
-  if (*ep != '\'')
-    ep++;
+  /* Skip optional FILE=. */
+  if (lex_match_id ("FILE"))
+    lex_match ('=');
 
-  if (ep <= bp)
+  /* Filename can be identifier or string. */
+  if (token != T_ID && token != T_STRING) 
     {
-      msg (SE, _("Unrecognized filename format."));
+      lex_error (_("expecting filename")); 
       return CMD_FAILURE;
     }
-
-  /* Now the filename is trapped between bp and ep. */
-  incfn = xmalloc (ep - bp + 1);
-  strncpy (incfn, bp, ep - bp);
-  incfn[ep - bp] = 0;
-  getl_include (incfn);
-  free (incfn);
-
-  return CMD_SUCCESS;
-}
-
-int
-cmd_include (void)
-{
-  lex_get ();
-
-  if (!lex_force_string ())
-    return CMD_SUCCESS;
   getl_include (ds_value (&tokstr));
 
   lex_get ();
index dc08f346a9704b7d4dc60f593aa40f1195f5a417..ee2fd7cb1302c0a495a0ef26ed59a00a9e68314f 100644 (file)
@@ -59,8 +59,6 @@ static trns_free_func reread_trns_free;
 int
 cmd_input_program (void)
 {
-  lex_match_id ("INPUT");
-  lex_match_id ("PROGRAM");
   discard_variables ();
 
   /* FIXME: we shouldn't do this here, but I'm afraid that other
@@ -77,10 +75,6 @@ cmd_end_input_program (void)
   struct input_program_pgm *inp;
   size_t i;
 
-  lex_match_id ("END");
-  lex_match_id ("INPUT");
-  lex_match_id ("PROGRAM");
-
   if (!case_source_is_class (vfm_source, &input_program_source_class))
     {
       msg (SE, _("No matching INPUT PROGRAM command."));
@@ -287,9 +281,6 @@ cmd_end_case (void)
 {
   struct trns_header *t;
 
-  lex_match_id ("END");
-  lex_match_id ("CASE");
-
   if (!case_source_is_class (vfm_source, &input_program_source_class))
     {
       msg (SE, _("This command may only be executed between INPUT PROGRAM "
@@ -336,8 +327,6 @@ cmd_reread (void)
   /* Created transformation. */
   struct reread_trns *t;
 
-  lex_match_id ("REREAD");
-
   h = default_handle;
   e = NULL;
   while (token != '.')
@@ -360,14 +349,8 @@ cmd_reread (void)
       else if (lex_match_id ("FILE"))
        {
          lex_match ('=');
-         if (token != T_ID)
-           {
-             lex_error (_("expecting file handle name"));
-             expr_free (e);
-             return CMD_FAILURE;
-           }
-         h = fh_get_handle_by_name (tokid);
-         if (!h)
+          h = fh_parse_file_handle ();
+         if (h == NULL)
            {
              expr_free (e);
              return CMD_FAILURE;
@@ -430,9 +413,6 @@ cmd_end_file (void)
 {
   struct trns_header *t;
 
-  lex_match_id ("END");
-  lex_match_id ("FILE");
-
   if (!case_source_is_class (vfm_source, &input_program_source_class))
     {
       msg (SE, _("This command may only be executed between INPUT PROGRAM "
index 3d171716b9afc3af7053f9ba6f33325a24fe99bb..34abe3981e423ae473aae946d7eface3875c5ef6 100644 (file)
@@ -23,6 +23,7 @@
 #include <assert.h>
 #include "levene.h"
 #include "hash.h"
+#include "str.h"
 #include "var.h"
 #include "vfm.h"
 #include "alloc.h"
index 5b1b39415393548b4619dc16873a09bfaa28c48f..91712bf2650552f61ababddfde500d89f0cac435 100644 (file)
@@ -76,7 +76,9 @@ static int eof;
 
 /* If nonzero, next token returned by lex_get().
    Used only in exceptional circumstances. */
-static int put;                        
+static int put_token;
+static struct string put_tokstr;
+static double put_tokval;
 
 static void unexpected_eof (void);
 static inline int check_id (const char *id, size_t len);
@@ -93,22 +95,46 @@ static void dump_token (void);
 void
 lex_init (void)
 {
+  ds_init (NULL, &put_tokstr, 64);
   if (!lex_get_line ())
     unexpected_eof ();
 }
 \f
 /* Common functions. */
 
+/* Copies put_token, put_tokstr, put_tokval into token, tokstr,
+   tokval, respectively, and sets tokid appropriately. */
+static void
+restore_token (void) 
+{
+  assert (put_token != 0);
+  token = put_token;
+  ds_replace (&tokstr, ds_value (&put_tokstr));
+  strncpy (tokid, ds_value (&put_tokstr), 8);
+  tokid[8] = 0;
+  tokval = put_tokval;
+  put_token = 0;
+}
+
+/* Copies token, tokstr, tokval into put_token, put_tokstr,
+   put_tokval respectively. */
+static void
+save_token (void) 
+{
+  put_token = token;
+  ds_replace (&put_tokstr, ds_value (&tokstr));
+  put_tokval = tokval;
+}
+
 /* Parses a single token, setting appropriate global variables to
    indicate the token's attributes. */
 void
 lex_get (void)
 {
   /* If a token was pushed ahead, return it. */
-  if (put)
+  if (put_token)
     {
-      token = put;
-      put = 0;
+      restore_token ();
 #if DUMP_TOKENS
       dump_token ();
 #endif
@@ -150,10 +176,9 @@ lex_get (void)
              return;
            }
 
-         if (put)
+         if (put_token)
            {
-             token = put;
-             put = 0;
+              restore_token ();
 #if DUMP_TOKENS
              dump_token ();
 #endif
@@ -615,8 +640,8 @@ lex_id_match (const char *kw, const char *tok)
 int
 lex_look_ahead (void)
 {
-  if (put)
-    return put;
+  if (put_token)
+    return put_token;
 
   for (;;)
     {
@@ -635,8 +660,8 @@ lex_look_ahead (void)
          else if (!lex_get_line ())
            unexpected_eof ();
 
-         if (put)
-           return put;
+         if (put_token) 
+           return put_token;
        }
 
       if ((toupper ((unsigned char) *prog) == 'X'
@@ -653,15 +678,20 @@ lex_look_ahead (void)
 void
 lex_put_back (int t)
 {
-  put = token;
+  save_token ();
   token = t;
 }
 
-/* Makes T the next token read. */
+/* Makes the current token become the next token to be read; the
+   current token is set to the identifier ID. */
 void
-lex_put_forward (int t)
+lex_put_back_id (const char *id)
 {
-  put = t;
+  save_token ();
+  token = T_ID;
+  ds_replace (&tokstr, id);
+  strncpy (tokid, ds_value (&tokstr), 8);
+  tokid[8] = 0;
 }
 \f
 /* Weird line processing functions. */
@@ -703,7 +733,7 @@ lex_discard_line (void)
 
   ds_clear (&getl_buf);
   prog = ds_value (&getl_buf);
-  dot = put = 0;
+  dot = put_token = 0;
 }
 
 /* Sets the current position in the current line to P, which must be
@@ -817,7 +847,7 @@ lex_preprocess_line (void)
       if (s[0] == '+' || s[0] == '-' || s[0] == '.')
        s[0] = ' ';
       else if (s[0] && !isspace ((unsigned char) s[0]))
-       lex_put_forward ('.');
+       put_token = '.';
     }
 
   prog = ds_value (&getl_buf);
@@ -929,10 +959,11 @@ lex_negative_to_dash (void)
 {
   if (token == T_NUM && tokval < 0.0)
     {
-      token = '-';
+      token = T_NUM;
       tokval = -tokval;
       ds_replace (&tokstr, ds_value (&tokstr) + 1);
-      lex_put_forward (T_NUM);
+      save_token ();
+      token = '-';
     }
 }
    
@@ -950,7 +981,7 @@ lex_skip_comment (void)
   for (;;)
     {
       lex_get_line ();
-      if (put == '.')
+      if (put_token == '.')
        break;
 
       prog = ds_end (&getl_buf);
@@ -1175,40 +1206,40 @@ dump_token (void)
 
     getl_location (&curfn, &curln);
     if (curfn)
-      printf ("%s:%d\t", curfn, curln);
+      fprintf (stderr, "%s:%d\t", curfn, curln);
   }
   
   switch (token)
     {
     case T_ID:
-      printf ("ID\t%s\n", tokid);
+      fprintf (stderr, "ID\t%s\n", tokid);
       break;
 
     case T_NUM:
-      printf ("NUM\t%f\n", tokval);
+      fprintf (stderr, "NUM\t%f\n", tokval);
       break;
 
     case T_STRING:
-      printf ("STRING\t\"%s\"\n", ds_value (&tokstr));
+      fprintf (stderr, "STRING\t\"%s\"\n", ds_value (&tokstr));
       break;
 
     case T_STOP:
-      printf ("STOP\n");
+      fprintf (stderr, "STOP\n");
       break;
 
     case T_EXP:
-      puts ("MISC\tEXP");
+      fprintf (stderr, "MISC\tEXP\"");
       break;
 
     case 0:
-      puts ("MISC\tEOF");
+      fprintf (stderr, "MISC\tEOF\n");
       break;
 
     default:
       if (token >= T_FIRST_KEYWORD && token <= T_LAST_KEYWORD)
-       printf ("KEYWORD\t%s\n", lex_token_name (token));
+       fprintf (stderr, "KEYWORD\t%s\n", lex_token_name (token));
       else
-       printf ("PUNCT\t%c\n", token);
+       fprintf (stderr, "PUNCT\t%c\n", token);
       break;
     }
 }
index cf7451582106aa3ef066d0bf4db216e637b4c3e6..2dd7da06273cfb11e2d11ddf745158385c588108 100644 (file)
@@ -111,7 +111,7 @@ int lex_id_match (const char *keyword_string, const char *token_string);
 /* Weird token functions. */
 int lex_look_ahead (void);
 void lex_put_back (int);
-void lex_put_forward (int);
+void lex_put_back_id (const char *tokid);
 
 /* Weird line processing functions. */
 char *lex_entire_line (void);
index c875e6f53a17d81136879c37db39a109db956974..10d2baad38df3999a9b458222781eda4dc78604c 100644 (file)
@@ -125,7 +125,6 @@ cmd_list (void)
 {
   struct variable casenum_var;
 
-  lex_match_id ("LIST");
   if (!parse_list (&cmd))
     return CMD_FAILURE;
   
index 7a31234c4f681629c7f9baf37abafc9618a9c9d1..7f8aa87559cbfacc32029715426623aa45c988c0 100644 (file)
@@ -166,8 +166,6 @@ internal_cmd_loop (void)
   /* Name of indexing variable if applicable. */
   char name[9];
 
-  lex_match_id ("LOOP");
-
   /* Create and initialize transformations to facilitate
      error-handling. */
   two = xmalloc (sizeof *two);
@@ -502,8 +500,6 @@ cmd_break (void)
   /* New transformation. */
   struct break_trns *t;
 
-  lex_match_id ("BREAK");
-
   for (loop = ctl_stack; loop; loop = loop->down)
     if (loop->type == CST_LOOP)
       break;
index d69e661d74422f0960aedf698c76b745a10a01eb..b20f8a24414ad7887483cc5bd0da636c55f31ba3 100644 (file)
@@ -71,7 +71,6 @@ main (int argc, char **argv)
     msg (FE, _("Error initializing output drivers."));
 
   lex_init ();
-  cmd_init ();
 
   /* Execution. */
   parse_script ();
index 277cde38232dbf4e7a118fb50683cd04fcfc7e20..5835e8229286d7072039ec9935cc2a8b0bcbcf32 100644 (file)
@@ -153,9 +153,6 @@ cmd_matrix_data (void)
   
   unsigned seen = 0;
   
-  lex_match_id ("MATRIX");
-  lex_match_id ("DATA");
-
   discard_variables ();
 
   pool = pool_create ();
@@ -600,6 +597,9 @@ cmd_matrix_data (void)
   debug_print ();
 #endif
 
+  if (!dfm_open_for_reading (mx->data_file))
+    goto lossage;
+
   if (mx->explicit_rowtype)
     read_matrices_with_rowtype (mx);
   else
index a8921b38bf89e0a7db43365748c671227e2af2e6..bf7b19765e63d998ffe4258d11b9b02e29cfbb7e 100644 (file)
@@ -73,7 +73,6 @@ cmd_means (void)
   v_dim = NULL;
   v_var = NULL;
 
-  lex_match_id ("MEANS");
   if (!parse_means (&cmd))
     goto free;
 
index 1e07fcfd54b2deffff98f5d66eaf0aa9c708c544..210d2389f81fe25e803b6f424100c6fa7dac63f9 100644 (file)
@@ -56,8 +56,6 @@ cmd_missing_values (void)
 {
   int i;
 
-  lex_match_id ("MISSING");
-  lex_match_id ("VALUES");
   while (token != '.')
     {
       if (!parse_varnames ())
index 46fe644d105b7bd0c7520449e4ff415606ce8eb3..f12cb7ed63e30e32c27f4df0fb833460ce99c686 100644 (file)
@@ -90,9 +90,6 @@ cmd_modify_vars (void)
       cancel_temporary (); 
     }
 
-  lex_match_id ("MODIFY");
-  lex_match_id ("VARS");
-
   vm.reorder_vars = NULL;
   vm.reorder_cnt = 0;
   vm.rename_vars = NULL;
index b97410a51bc234ffb826e06d6705f339ea56e6eb..8031d65d2070954aad0cad8b538c9cd1f94727fe 100644 (file)
@@ -42,7 +42,6 @@ cmd_numeric (void)
      be used. */
   struct fmt_spec f;
 
-  lex_match_id ("NUMERIC");
   do
     {
       if (!parse_DATA_LIST_vars (&v, &nv, PV_NONE))
@@ -116,7 +115,6 @@ cmd_string (void)
   /* Width of variables to create. */
   int width;
 
-  lex_match_id ("STRING");
   do
     {
       if (!parse_DATA_LIST_vars (&v, &nv, PV_NONE))
@@ -188,7 +186,6 @@ cmd_leave (void)
 
   int i;
 
-  lex_match_id ("LEAVE");
   if (!parse_variables (default_dict, &v, &nv, PV_NONE))
     return CMD_FAILURE;
   for (i = 0; i < nv; i++)
index 8f19f1ba8779df7343b32b491f0861ea7c128313..8f9e9e4ec4617349e18b8448721acd5435f2983a 100644 (file)
@@ -82,12 +82,14 @@ corrupt_msg (struct file_handle *h, const char *format, ...)
   {
     char *title;
     struct error e;
+    const char *filename;
 
     e.class = ME;
     getl_location (&e.where.filename, &e.where.line_number);
-    e.title = title = local_alloc (strlen (h->fn) + 80);
+    filename = handle_get_filename (h);
+    e.title = title = local_alloc (strlen (filename) + 80);
     sprintf (title, _("portable file %s corrupt at offset %ld: "),
-            h->fn, ftell (ext->file) - (82 - (long) (ext->bp - ext->buf)));
+            filename, ftell (ext->file) - (82 - (long) (ext->bp - ext->buf)));
     e.text = buf;
 
     err_vmsg (&e);
@@ -100,12 +102,13 @@ corrupt_msg (struct file_handle *h, const char *format, ...)
 
 /* Closes a portable file after we're done with it. */
 static void
-pfm_close (struct file_handle * h)
+pfm_close (struct file_handle *h)
 {
   struct pfm_fhuser_ext *ext = h->ext;
 
   if (EOF == fclose (ext->file))
-    msg (ME, _("%s: Closing portable file: %s."), h->fn, strerror (errno));
+    msg (ME, _("%s: Closing portable file: %s."),
+         handle_get_filename (h), strerror (errno));
   free (ext->vars);
   free (ext->trans);
   free (h->ext);
@@ -220,20 +223,21 @@ pfm_read_dictionary (struct file_handle *h, struct pfm_read_info *inf)
     {
       msg (ME, _("Cannot read file %s as portable file: already opened "
                 "for %s."),
-          fh_handle_name (h), h->class->name);
+          handle_get_name (h), h->class->name);
       return NULL;
     }
 
   msg (VM (1), _("%s: Opening portable-file handle %s for reading."),
-       fh_handle_filename (h), fh_handle_name (h));
+       handle_get_filename (h), handle_get_name (h));
 
   /* Open the physical disk file. */
   ext = xmalloc (sizeof (struct pfm_fhuser_ext));
-  ext->file = fopen (h->norm_fn, "rb");
+  ext->file = fopen (handle_get_filename (h), "rb");
   if (ext->file == NULL)
     {
       msg (ME, _("An error occurred while opening \"%s\" for reading "
-          "as a portable file: %s."), h->fn, strerror (errno));
+                 "as a portable file: %s."),
+           handle_get_filename (h), strerror (errno));
       err_cond_fail ();
       free (ext);
       return NULL;
index 054621fea3335dba01d08c8add37a40e38ddac89..e229072ea5578678e0bfe51c3ac2042e7872c2e5 100644 (file)
@@ -70,22 +70,23 @@ pfm_write_dictionary (struct file_handle *handle, struct dictionary *dict)
     {
       msg (ME, _("Cannot write file %s as portable file: already opened "
                 "for %s."),
-          fh_handle_name (handle), handle->class->name);
+          handle_get_name (handle), handle->class->name);
       return 0;
     }
 
   msg (VM (1), _("%s: Opening portable-file handle %s for writing."),
-       fh_handle_filename (handle), fh_handle_name (handle));
+       handle_get_filename (handle), handle_get_name (handle));
   
   /* Open the physical disk file. */
   handle->class = &pfm_w_class;
   handle->ext = ext = xmalloc (sizeof (struct pfm_fhuser_ext));
-  ext->file = fopen (handle->norm_fn, "wb");
+  ext->file = fopen (handle_get_filename (handle), "wb");
   ext->lc = 0;
   if (ext->file == NULL)
     {
       msg (ME, _("An error occurred while opening \"%s\" for writing "
-          "as a portable file: %s."), handle->fn, strerror (errno));
+          "as a portable file: %s."),
+           handle_get_filename (handle), strerror (errno));
       err_cond_fail ();
       free (ext);
       return 0;
@@ -166,7 +167,8 @@ bufwrite (struct file_handle *h, const void *buf_, size_t nbytes)
 
  lossage:
   abort ();
-  msg (ME, _("%s: Writing portable file: %s."), h->fn, strerror (errno));
+  msg (ME, _("%s: Writing portable file: %s."),
+       handle_get_filename (h), strerror (errno));
   return 0;
 }
 
@@ -499,7 +501,8 @@ pfm_close (struct file_handle *h)
   }
 
   if (EOF == fclose (ext->file))
-    msg (ME, _("%s: Closing portable file: %s."), h->fn, strerror (errno));
+    msg (ME, _("%s: Closing portable file: %s."),
+         handle_get_filename (h), strerror (errno));
 
   free (ext->vars);
   free (ext);
index 17c0eab2376c9ba146af38c28c3448f796e06e21..7f93f13f717296d31d11530a05011f7ba1030002 100644 (file)
@@ -34,8 +34,6 @@
 #include "tab.h"
 #include "var.h"
 
-#include "debug-print.h"
-
 /* Describes what to do when an output field is encountered. */
 enum
   {
@@ -104,10 +102,6 @@ static int parse_specs (void);
 static void dump_table (void);
 static void append_var_spec (struct prt_out_spec *spec);
 static void alloc_line (void);
-
-#if DEBUGGING
-void debug_print (void);
-#endif
 \f
 /* Basic parsing. */
 
@@ -115,7 +109,6 @@ void debug_print (void);
 int
 cmd_print (void)
 {
-  lex_match_id ("PRINT");
   return internal_cmd_print (PRT_PRINT);
 }
 
@@ -123,7 +116,6 @@ cmd_print (void)
 int
 cmd_print_eject (void)
 {
-  lex_match_id ("EJECT");
   return internal_cmd_print (PRT_PRINT | PRT_EJECT);
 }
 
@@ -131,7 +123,6 @@ cmd_print_eject (void)
 int
 cmd_write (void)
 {
-  lex_match_id ("WRITE");
   return internal_cmd_print (PRT_WRITE);
 }
 
@@ -194,6 +185,9 @@ internal_cmd_print (int f)
   if (!parse_specs ())
     goto lossage;
   
+  if (prt.handle != NULL && !dfm_open_for_writing (prt.handle))
+    goto lossage;
+
   /* Output the variable table if requested. */
   if (table)
     dump_table ();
@@ -207,10 +201,6 @@ internal_cmd_print (int f)
   memcpy (trns, &prt, sizeof *trns);
   add_transformation ((struct trns_header *) trns);
 
-#if 0 && DEBUGGING
-  debug_print ();
-#endif
-
   return CMD_SUCCESS;
 
  lossage:
@@ -787,7 +777,6 @@ static void
 dump_table (void)
 {
   struct prt_out_spec *spec;
-  const char *filename;
   struct tab_table *t;
   int recno;
   int nspec;
@@ -841,13 +830,12 @@ dump_table (void)
        assert (0);
       }
 
-  filename = fh_handle_name (prt.handle);
-  tab_title (t, 1, (prt.handle != NULL
-                   ? _("Writing %3d records to file %s.")
-                   : _("Writing %3d records to the listing file.")),
-            recno, filename);
+  if (prt.handle != NULL)
+    tab_title (t, 1, _("Writing %d record(s) to file %s."),
+               recno, handle_get_filename (prt.handle));
+  else
+    tab_title (t, 1, _("Writing %d record(s) to the listing file."), recno);
   tab_submit (t);
-  fh_handle_name (NULL);
 }
 
 /* PORTME: The number of characters in a line terminator. */
@@ -937,7 +925,7 @@ print_trns_proc (struct trns_header * trns, struct ccase * c,
        else
          {
            if ((t->options & PRT_CMD_MASK) == PRT_PRINT
-               || t->handle->mode != FH_MD_BINARY)
+               || handle_get_mode (t->handle) != MODE_BINARY)
              {
                /* PORTME: Line ends. */
 #ifdef __MSDOS__
@@ -1028,23 +1016,12 @@ cmd_print_space (void)
   struct file_handle *handle;
   struct expression *e;
 
-  lex_match_id ("SPACE");
   if (lex_match_id ("OUTFILE"))
     {
       lex_match ('=');
 
-      if (token == T_ID)
-       handle = fh_get_handle_by_name (tokid);
-      else if (token == T_STRING)
-       handle = fh_get_handle_by_filename (tokid);
-      else
-       {
-         msg (SE, _("A file name or handle was expected in the "
-                    "OUTFILE subcommand."));
-         return CMD_FAILURE;
-       }
-      
-      if (!handle)
+      handle = fh_parse_file_handle ();
+      if (handle == NULL)
        return CMD_FAILURE;
       lex_get ();
     }
@@ -1064,6 +1041,12 @@ cmd_print_space (void)
   else
     e = NULL;
 
+  if (handle != NULL && !dfm_open_for_writing (handle))
+    {
+      expr_free (e);
+      return CMD_FAILURE;
+    }
+
   t = xmalloc (sizeof *t);
   t->h.proc = print_space_trns_proc;
   if (e)
@@ -1128,45 +1111,3 @@ print_space_trns_free (struct trns_header * trns)
 {
   expr_free (((struct print_space_trns *) trns)->e);
 }
-\f
-/* Debugging code. */
-
-#if 0 && DEBUGGING
-void
-debug_print (void)
-{
-  struct prt_out_spec *p;
-
-  if (prt.handle == NULL)
-    {
-      printf ("PRINT");
-      if (prt.eject)
-       printf (" EJECT");
-    }
-  else
-    printf ("WRITE OUTFILE=%s", handle_name (prt.handle));
-  printf (" MAX_WIDTH=%d", prt.max_width);
-  printf (" /");
-  for (p = prt.spec; p; p = p->next)
-    switch (p->type)
-      {
-      case PRT_ERROR:
-       printf (_("<ERROR>"));
-       break;
-      case PRT_NEWLINE:
-       printf ("\n /");
-       break;
-      case PRT_CONST:
-       printf (" \"%s\" %d-%d", p->u.c, p->fc + 1, p->fc + strlen (p->u.c));
-       break;
-      case PRT_VAR:
-       printf (" %s %d %d-%d (%s)", p->u.v.v->name, p->u.v.v->fv, p->fc + 1,
-               p->fc + p->u.v.v->print.w, fmt_to_string (&p->u.v.v->print));
-       break;
-      case PRT_SPACE:
-       printf (" \" \" %d", p->fc + 1);
-       break;
-      }
-  printf (".\n");
-}
-#endif /* DEBUGGING */
index 34342a1e185895df394e55f17ab48e127fc491b1..e2df650f26ecc25fd59312970f4aa0a03ef7a337 100644 (file)
@@ -142,8 +142,6 @@ cmd_recode (void)
   struct variable **v;
   int nv;
 
-  lex_match_id ("RECODE");
-
   /* Parses each specification between slashes. */
   head = rcd = xmalloc (sizeof *rcd);
   v = NULL;
index 21b80432cd38ffaa3e59c4514c90544cbd6ca1b8..4b81f90484c69bd83f6c112705e915dd1093640e 100644 (file)
@@ -49,9 +49,6 @@ cmd_rename_variables (void)
       cancel_temporary (); 
     }
 
-  lex_match_id ("RENAME");
-  lex_match_id ("VARIABLES");
-
   do
     {
       int prev_nv_1 = rename_cnt;
index 9141684c82de5262ce306f34c2a25eeeb0c9008c..c3236744a298b6dfd402207dfac404aaa7e28fff 100644 (file)
@@ -138,9 +138,6 @@ internal_cmd_do_repeat (void)
   int print;
 
   /* The first step is parsing the DO REPEAT command itself. */
-  lex_match_id ("DO");
-  lex_match_id ("REPEAT");
-
   count = 0;
   line_buf_head = NULL;
   do
index 3f887935598ef8d7cbd7d723208563c7702ae45b..67523b3d80ff62e65cd5185de4ce70ce26df7777 100644 (file)
@@ -59,8 +59,6 @@ cmd_sample (void)
   int a, b;
   unsigned frac;
 
-  lex_match_id ("SAMPLE");
-
   if (!lex_force_num ())
     return CMD_FAILURE;
   if (!lex_integer_p ())
index f686a9ddf57ed9180f815a1965daa17ead0c909b..330ae4371af1e0498fc4cc90d4d107144789a8e1 100644 (file)
@@ -43,9 +43,6 @@ cmd_select_if (void)
   struct expression *e;
   struct select_if_trns *t;
 
-  lex_match_id ("SELECT");
-  lex_match_id ("IF");
-
   e = expr_parse (PXP_BOOLEAN);
   if (!e)
     return CMD_FAILURE;
@@ -86,8 +83,6 @@ select_if_free (struct trns_header * t)
 int
 cmd_filter (void)
 {
-  lex_match_id ("FILTER");
-
   if (lex_match_id ("OFF"))
     dict_set_filter (default_dict, NULL);
   else
@@ -125,9 +120,6 @@ cmd_process_if (void)
 {
   struct expression *e;
 
-  lex_match_id ("PROCESS");
-  lex_match_id ("IF");
-
   e = expr_parse (PXP_BOOLEAN);
   if (!e)
     return CMD_FAILURE;
index f297bc847d77231e6a4ab666bf97727023639ef3..e9f3ddedee4965517acdd222a42e1ae82a976d2c 100644 (file)
--- a/src/set.q
+++ b/src/set.q
@@ -358,8 +358,6 @@ int
 cmd_set (void)
 {
 
-  lex_match_id ("SET");
-
   if (!parse_set (&cmd))
     return CMD_FAILURE;
 
@@ -981,7 +979,7 @@ stc_custom_workdev (struct cmd_set *cmd UNUSED)
 
 
 static void 
-set_viewport(void)
+set_viewport(int sig_num UNUSED)
 {
 #if HAVE_LIBTERMCAP
   static char term_buffer[16384];
@@ -1112,8 +1110,8 @@ init_settings(void)
 
   if ( ! long_view )
     {
-      set_viewport();
-      signal (SIGWINCH,set_viewport);
+      set_viewport (0);
+      signal (SIGWINCH, set_viewport);
     }
 
 }
index 03b6d5ab55c04805cb7b825c350ae4ce1d79072b..01f6330f19ca0403ebf9623eecf279d856284416 100644 (file)
@@ -156,14 +156,15 @@ corrupt_msg (int class, const char *format,...)
 
 /* Closes a system file after we're done with it. */
 static void
-sfm_close (struct file_handle * h)
+sfm_close (struct file_handle *h)
 {
   struct sfm_fhuser_ext *ext = h->ext;
 
   ext->opened--;
   assert (ext->opened == 0);
-  if (EOF == fn_close (h->fn, ext->file))
-    msg (ME, _("%s: Closing system file: %s."), h->fn, strerror (errno));
+  if (EOF == fn_close (handle_get_filename (h), ext->file))
+    msg (ME, _("%s: Closing system file: %s."),
+         handle_get_filename (h), strerror (errno));
   free (ext->buf);
   free (h->ext);
 }
@@ -237,20 +238,21 @@ sfm_read_dictionary (struct file_handle * h, struct sfm_read_info * inf)
   else if (h->class != NULL)
     {
       msg (ME, _("Cannot read file %s as system file: already opened for %s."),
-          fh_handle_name (h), h->class->name);
+          handle_get_name (h), h->class->name);
       return NULL;
     }
 
   msg (VM (1), _("%s: Opening system-file handle %s for reading."),
-       fh_handle_filename (h), fh_handle_name (h));
+       handle_get_filename (h), handle_get_name (h));
   
   /* Open the physical disk file. */
   ext = xmalloc (sizeof (struct sfm_fhuser_ext));
-  ext->file = fn_open (h->norm_fn, "rb");
+  ext->file = fn_open (handle_get_filename (h), "rb");
   if (ext->file == NULL)
     {
       msg (ME, _("An error occurred while opening \"%s\" for reading "
-          "as a system file: %s."), h->fn, strerror (errno));
+                 "as a system file: %s."),
+           handle_get_filename (h), strerror (errno));
       err_cond_fail ();
       free (ext);
       return NULL;
@@ -284,10 +286,10 @@ sfm_read_dictionary (struct file_handle * h, struct sfm_read_info * inf)
 
       if (wv == NULL)
        lose ((ME, _("%s: Weighting variable may not be a continuation of "
-              "a long string variable."), h->fn));
+              "a long string variable."), handle_get_filename (h)));
       else if (wv->type == ALPHA)
        lose ((ME, _("%s: Weighting variable may not be a string variable."),
-              h->fn));
+              handle_get_filename (h)));
 
       dict_set_weight (ext->dict, wv);
     }
@@ -312,8 +314,9 @@ sfm_read_dictionary (struct file_handle * h, struct sfm_read_info * inf)
 
        case 4:
          lose ((ME, _("%s: Orphaned variable index record (type 4).  Type 4 "
-                "records must always immediately follow type 3 records."),
-                h->fn));
+                       "records must always immediately follow type 3 "
+                       "records."),
+                handle_get_filename (h)));
 
        case 6:
          if (!read_documents (h))
@@ -340,13 +343,6 @@ sfm_read_dictionary (struct file_handle * h, struct sfm_read_info * inf)
                bswap_int32 (&data.count);
              }
 
-           /*if(data.size != sizeof(int32) && data.size != sizeof(flt64))
-              lose((ME, "%s: Element size in record type 7, subtype %d, is "
-              "not either the size of IN (%d) or OBS (%d); actual value "
-              "is %d.",
-              h->fn, data.subtype, sizeof(int32), sizeof(flt64),
-              data.size)); */
-
            switch (data.subtype)
              {
              case 3:
@@ -367,7 +363,8 @@ sfm_read_dictionary (struct file_handle * h, struct sfm_read_info * inf)
 
              default:
                msg (MW, _("%s: Unrecognized record type 7, subtype %d "
-                    "encountered in system file."), h->fn, data.subtype);
+                           "encountered in system file."),
+                     handle_get_filename (h), data.subtype);
                skip = 1;
              }
 
@@ -390,7 +387,8 @@ sfm_read_dictionary (struct file_handle * h, struct sfm_read_info * inf)
          }
 
        default:
-         lose ((ME, _("%s: Unrecognized record type %d."), h->fn, rec_type));
+         lose ((ME, _("%s: Unrecognized record type %d."),
+                 handle_get_filename (h), rec_type));
        }
     }
 
@@ -409,7 +407,7 @@ lossage:
   msg (VM (1), _("Error reading system-file header."));
   
   free (var_by_index);
-  fn_close (h->fn, ext->file);
+  fn_close (handle_get_filename (h), ext->file);
   if (ext && ext->dict)
     dict_destroy (ext->dict);
   free (ext);
@@ -431,8 +429,8 @@ read_machine_int32_info (struct file_handle * h, int size, int count)
 
   if (size != sizeof (int32) || count != 8)
     lose ((ME, _("%s: Bad size (%d) or count (%d) field on record type 7, "
-          "subtype 3.  Expected size %d, count 8."),
-          h->fn, size, count, sizeof (int32)));
+                 "subtype 3.   Expected size %d, count 8."),
+          handle_get_filename (h), size, count, sizeof (int32)));
 
   assertive_bufread (h, data, sizeof data, 0);
   if (ext->reverse_endian)
@@ -444,7 +442,8 @@ read_machine_int32_info (struct file_handle * h, int size, int count)
   if (data[4] != 1)
     lose ((ME, _("%s: Floating-point representation in system file is not "
                  "IEEE-754.  PSPP cannot convert between floating-point "
-                 "formats."), h->fn));
+                 "formats."),
+           handle_get_filename (h)));
 #endif
 
   /* PORTME: Check recorded file endianness against intuited file
@@ -458,16 +457,19 @@ read_machine_int32_info (struct file_handle * h, int size, int count)
     file_bigendian ^= 1;
   if (file_bigendian ^ (data[6] == 1))
     lose ((ME, _("%s: File-indicated endianness (%s) does not match endianness "
-          "intuited from file header (%s)."),
-          h->fn, file_bigendian ? _("big-endian") : _("little-endian"),
+                 "intuited from file header (%s)."),
+          handle_get_filename (h),
+           file_bigendian ? _("big-endian") : _("little-endian"),
           data[6] == 1 ? _("big-endian") : (data[6] == 2 ? _("little-endian")
                                          : _("unknown"))));
 
   /* PORTME: Character representation code. */
   if (data[7] != 2 && data[7] != 3)
     lose ((ME, _("%s: File-indicated character representation code (%s) is not "
-          "ASCII."), h->fn,
-       data[7] == 1 ? "EBCDIC" : (data[7] == 4 ? _("DEC Kanji") : _("Unknown"))));
+                 "ASCII."),
+           handle_get_filename (h),
+           (data[7] == 1 ? "EBCDIC"
+            : (data[7] == 4 ? _("DEC Kanji") : _("Unknown")))));
 
   return 1;
 
@@ -487,8 +489,8 @@ read_machine_flt64_info (struct file_handle * h, int size, int count)
 
   if (size != sizeof (flt64) || count != 3)
     lose ((ME, _("%s: Bad size (%d) or count (%d) field on record type 7, "
-          "subtype 4.  Expected size %d, count 8."),
-          h->fn, size, count, sizeof (flt64)));
+                 "subtype 4.   Expected size %d, count 8."),
+          handle_get_filename (h), size, count, sizeof (flt64)));
 
   assertive_bufread (h, data, sizeof data, 0);
   if (ext->reverse_endian)
@@ -505,7 +507,7 @@ read_machine_flt64_info (struct file_handle * h, int size, int count)
                 "for at least one of the three system values.  SYSMIS: "
                 "indicated %g, expected %g; HIGHEST: %g, %g; LOWEST: "
                 "%g, %g."),
-          h->fn, (double) data[0], (double) SYSMIS,
+          handle_get_filename (h), (double) data[0], (double) SYSMIS,
           (double) data[1], (double) FLT64_MAX,
           (double) data[2], (double) second_lowest_flt64);
     }
@@ -534,7 +536,7 @@ read_header (struct file_handle * h, struct sfm_read_info * inf)
   if (0 != strncmp ("$FL2", hdr.rec_type, 4))
     lose ((ME, _("%s: Bad magic.  Proper system files begin with "
                 "the four characters `$FL2'. This file will not be read."),
-          h->fn));
+          handle_get_filename (h)));
 
   /* Check eye-catcher string. */
   memcpy (prod_name, hdr.prod_name, sizeof hdr.prod_name);
@@ -576,8 +578,8 @@ read_header (struct file_handle * h, struct sfm_read_info * inf)
       bswap_int32 (&hdr.layout_code);
       if (hdr.layout_code != 2)
        lose ((ME, _("%s: File layout code has unexpected value %d.  Value "
-              "should be 2, in big-endian or little-endian format."),
-              h->fn, hdr.layout_code));
+                     "should be 2, in big-endian or little-endian format."),
+              handle_get_filename (h), hdr.layout_code));
 
       ext->reverse_endian = 1;
       bswap_int32 (&hdr.case_size);
@@ -592,25 +594,28 @@ read_header (struct file_handle * h, struct sfm_read_info * inf)
   if (hdr.case_size <= 0 || ext->case_size > (INT_MAX
                                              / (int) sizeof (union value) / 2))
     lose ((ME, _("%s: Number of elements per case (%d) is not between 1 "
-          "and %d."), h->fn, hdr.case_size, INT_MAX / sizeof (union value) / 2));
+                 "and %d."),
+           handle_get_filename (h), hdr.case_size,
+           INT_MAX / sizeof (union value) / 2));
 
   ext->compressed = hdr.compressed;
 
   ext->weight_index = hdr.weight_index - 1;
   if (hdr.weight_index < 0 || hdr.weight_index > hdr.case_size)
     lose ((ME, _("%s: Index of weighting variable (%d) is not between 0 "
-          "and number of elements per case (%d)."),
-          h->fn, hdr.weight_index, ext->case_size));
+                 "and number of elements per case (%d)."),
+          handle_get_filename (h), hdr.weight_index, ext->case_size));
 
   ext->ncases = hdr.ncases;
   if (ext->ncases < -1 || ext->ncases > INT_MAX / 2)
     lose ((ME, _("%s: Number of cases in file (%ld) is not between -1 and "
-          "%d."), h->fn, (long) ext->ncases, INT_MAX / 2));
+          "%d."), handle_get_filename (h), (long) ext->ncases, INT_MAX / 2));
 
   ext->bias = hdr.bias;
   if (ext->bias != 100.0)
     corrupt_msg (MW, _("%s: Compression bias (%g) is not the usual "
-                "value of 100."), h->fn, ext->bias);
+                       "value of 100."),
+                 handle_get_filename (h), ext->bias);
 
   /* Make a file label only on the condition that the given label is
      not all spaces or nulls. */
@@ -703,7 +708,8 @@ read_variables (struct file_handle * h, struct variable *** var_by_index)
 
       if (sv.rec_type != 2)
        lose ((ME, _("%s: position %d: Bad record type (%d); "
-              "the expected value was 2."), h->fn, i, sv.rec_type));
+                     "the expected value was 2."),
+               handle_get_filename (h), i, sv.rec_type));
 
       /* If there was a long string previously, make sure that the
         continuations are present; otherwise make sure there aren't
@@ -712,7 +718,8 @@ read_variables (struct file_handle * h, struct variable *** var_by_index)
        {
          if (sv.type != -1)
            lose ((ME, _("%s: position %d: String variable does not have "
-                        "proper number of continuation records."), h->fn, i));
+                        "proper number of continuation records."),
+                   handle_get_filename (h), i));
 
          (*var_by_index)[i] = NULL;
          long_string_count--;
@@ -720,32 +727,36 @@ read_variables (struct file_handle * h, struct variable *** var_by_index)
        }
       else if (sv.type == -1)
        lose ((ME, _("%s: position %d: Superfluous long string continuation "
-              "record."), h->fn, i));
+                     "record."),
+               handle_get_filename (h), i));
 
       /* Check fields for validity. */
       if (sv.type < 0 || sv.type > 255)
        lose ((ME, _("%s: position %d: Bad variable type code %d."),
-              h->fn, i, sv.type));
+              handle_get_filename (h), i, sv.type));
       if (sv.has_var_label != 0 && sv.has_var_label != 1)
        lose ((ME, _("%s: position %d: Variable label indicator field is not "
-              "0 or 1."), h->fn, i));
+              "0 or 1."), handle_get_filename (h), i));
       if (sv.n_missing_values < -3 || sv.n_missing_values > 3
          || sv.n_missing_values == -1)
        lose ((ME, _("%s: position %d: Missing value indicator field is not "
-                    "-3, -2, 0, 1, 2, or 3."), h->fn, i));
+                    "-3, -2, 0, 1, 2, or 3."), handle_get_filename (h), i));
 
       /* Copy first character of variable name. */
       if (!isalpha ((unsigned char) sv.name[0])
          && sv.name[0] != '@' && sv.name[0] != '#')
        lose ((ME, _("%s: position %d: Variable name begins with invalid "
-              "character."), h->fn, i));
+                     "character."),
+               handle_get_filename (h), i));
       if (islower ((unsigned char) sv.name[0]))
        msg (MW, _("%s: position %d: Variable name begins with lowercase letter "
-            "%c."), h->fn, i, sv.name[0]);
+                   "%c."),
+             handle_get_filename (h), i, sv.name[0]);
       if (sv.name[0] == '#')
        msg (MW, _("%s: position %d: Variable name begins with octothorpe "
                   "(`#').  Scratch variables should not appear in system "
-                  "files."), h->fn, i);
+                  "files."),
+             handle_get_filename (h), i);
       name[0] = toupper ((unsigned char) (sv.name[0]));
 
       /* Copy remaining characters of variable name. */
@@ -758,7 +769,8 @@ read_variables (struct file_handle * h, struct variable *** var_by_index)
          else if (islower (c))
            {
              msg (MW, _("%s: position %d: Variable name character %d is "
-                  "lowercase letter %c."), h->fn, i, j + 1, sv.name[j]);
+                         "lowercase letter %c."),
+                   handle_get_filename (h), i, j + 1, sv.name[j]);
              name[j] = toupper ((unsigned char) (c));
            }
          else if (isalnum (c) || c == '.' || c == '@'
@@ -766,7 +778,8 @@ read_variables (struct file_handle * h, struct variable *** var_by_index)
            name[j] = c;
          else
            lose ((ME, _("%s: position %d: character `\\%03o' (%c) is not valid in a "
-                  "variable name."), h->fn, i, c, c));
+                         "variable name."),
+                   handle_get_filename (h), i, c, c));
        }
       name[j] = 0;
 
@@ -774,7 +787,7 @@ read_variables (struct file_handle * h, struct variable *** var_by_index)
       vv = (*var_by_index)[i] = dict_create_var (dict, name, sv.type);
       if (vv == NULL) 
         lose ((ME, _("%s: Duplicate variable name `%s' within system file."),
-               h->fn, name));
+               handle_get_filename (h), name));
 
       /* Case reading data. */
       vv->get.fv = next_value;
@@ -799,7 +812,8 @@ read_variables (struct file_handle * h, struct variable *** var_by_index)
          /* Check len. */
          if (len < 0 || len > 255)
            lose ((ME, _("%s: Variable %s indicates variable label of invalid "
-                  "length %d."), h->fn, vv->name, len));
+                         "length %d."),
+                   handle_get_filename (h), vv->name, len));
 
          /* Read label into variable structure. */
          vv->label = bufread (h, NULL, ROUND_UP (len, sizeof (int32)), len + 1);
@@ -815,7 +829,8 @@ read_variables (struct file_handle * h, struct variable *** var_by_index)
 
          if (vv->width > MAX_SHORT_STRING)
            lose ((ME, _("%s: Long string variable %s may not have missing "
-                  "values."), h->fn, vv->name));
+                         "values."),
+                   handle_get_filename (h), vv->name));
 
          assertive_bufread (h, mv, sizeof *mv * abs (sv.n_missing_values), 0);
 
@@ -839,7 +854,8 @@ read_variables (struct file_handle * h, struct variable *** var_by_index)
 
              if (vv->type == ALPHA)
                lose ((ME, _("%s: String variable %s may not have missing "
-                      "values specified as a range."), h->fn, vv->name));
+                             "values specified as a range."),
+                       handle_get_filename (h), vv->name));
 
              if (mv[0] == ext->lowest)
                {
@@ -876,10 +892,12 @@ read_variables (struct file_handle * h, struct variable *** var_by_index)
   /* Some consistency checks. */
   if (long_string_count != 0)
     lose ((ME, _("%s: Long string continuation records omitted at end of "
-          "dictionary."), h->fn));
+                 "dictionary."),
+           handle_get_filename (h)));
   if (next_value != ext->case_size)
     lose ((ME, _("%s: System file header indicates %d variable positions but "
-          "%d were read from file."), h->fn, ext->case_size, next_value));
+                 "%d were read from file."),
+           handle_get_filename (h), ext->case_size, next_value));
 
   return 1;
 
@@ -898,7 +916,7 @@ parse_format_spec (struct file_handle *h, int32 s, struct fmt_spec *v, struct va
   v->type = translate_fmt ((s >> 16) & 0xff);
   if (v->type == -1)
     lose ((ME, _("%s: Bad format specifier byte (%d)."),
-          h->fn, (s >> 16) & 0xff));
+          handle_get_filename (h), (s >> 16) & 0xff));
   v->w = (s >> 8) & 0xff;
   v->d = s & 0xff;
 
@@ -906,10 +924,11 @@ parse_format_spec (struct file_handle *h, int32 s, struct fmt_spec *v, struct va
 
   if (v->type == -1)
     lose ((ME, _("%s: Bad format specifier byte (%d)."),
-          h->fn, (s >> 16) & 0xff));
+          handle_get_filename (h), (s >> 16) & 0xff));
   if ((vv->type == ALPHA) ^ ((formats[v->type].cat & FCAT_STRING) != 0))
     lose ((ME, _("%s: %s variable %s has %s format specifier %s."),
-          h->fn, vv->type == ALPHA ? _("String") : _("Numeric"),
+          handle_get_filename (h),
+           vv->type == ALPHA ? _("String") : _("Numeric"),
           vv->name,
           formats[v->type].cat & FCAT_STRING ? _("string") : _("numeric"),
           formats[v->type].name));
@@ -988,7 +1007,8 @@ read_value_labels (struct file_handle * h, struct variable ** var_by_index)
     
     if (rec_type != 4)
       lose ((ME, _("%s: Variable index record (type 4) does not immediately "
-            "follow value label record (type 3) as it should."), h->fn));
+                   "follow value label record (type 3) as it should."),
+             handle_get_filename (h)));
   }
 
   /* Read number of variables associated with value label from type 4
@@ -998,8 +1018,8 @@ read_value_labels (struct file_handle * h, struct variable ** var_by_index)
     bswap_int32 (&n_vars);
   if (n_vars < 1 || n_vars > dict_get_var_cnt (ext->dict))
     lose ((ME, _("%s: Number of variables associated with a value label (%d) "
-          "is not between 1 and the number of variables (%d)."),
-          h->fn, n_vars, dict_get_var_cnt (ext->dict)));
+                 "is not between 1 and the number of variables (%d)."),
+          handle_get_filename (h), n_vars, dict_get_var_cnt (ext->dict)));
 
   /* Read the list of variables. */
   var = xmalloc (n_vars * sizeof *var);
@@ -1014,18 +1034,20 @@ read_value_labels (struct file_handle * h, struct variable ** var_by_index)
        bswap_int32 (&var_index);
       if (var_index < 1 || var_index > ext->case_size)
        lose ((ME, _("%s: Variable index associated with value label (%d) is "
-              "not between 1 and the number of values (%d)."),
-              h->fn, var_index, ext->case_size));
+                     "not between 1 and the number of values (%d)."),
+              handle_get_filename (h), var_index, ext->case_size));
 
       /* Make sure it's a real variable. */
       v = var_by_index[var_index - 1];
       if (v == NULL)
        lose ((ME, _("%s: Variable index associated with value label (%d) "
                      "refers to a continuation of a string variable, not to "
-                     "an actual variable."), h->fn, var_index));
+                     "an actual variable."),
+               handle_get_filename (h), var_index));
       if (v->type == ALPHA && v->width > MAX_SHORT_STRING)
        lose ((ME, _("%s: Value labels are not allowed on long string "
-                     "variables (%s)."), h->fn, v->name));
+                     "variables (%s)."),
+               handle_get_filename (h), v->name));
 
       /* Add it to the list of variables. */
       var[i] = v;
@@ -1035,8 +1057,9 @@ read_value_labels (struct file_handle * h, struct variable ** var_by_index)
   for (i = 1; i < n_vars; i++)
     if (var[i]->type != var[0]->type)
       lose ((ME, _("%s: Variables associated with value label are not all of "
-            "identical type.  Variable %s has %s type, but variable %s has "
-            "%s type."), h->fn,
+                   "identical type.  Variable %s has %s type, but variable "
+                   "%s has %s type."),
+             handle_get_filename (h),
             var[0]->name, var[0]->type == ALPHA ? _("string") : _("numeric"),
             var[i]->name, var[i]->type == ALPHA ? _("string") : _("numeric")));
 
@@ -1075,11 +1098,12 @@ read_value_labels (struct file_handle * h, struct variable ** var_by_index)
 
          if (var[0]->type == NUMERIC)
            msg (MW, _("%s: File contains duplicate label for value %g for "
-                "variable %s."), h->fn, label->value.f, v->name);
+                       "variable %s."),
+                 handle_get_filename (h), label->value.f, v->name);
          else
            msg (MW, _("%s: File contains duplicate label for value `%.*s' "
-                "for variable %s."),
-                 h->fn, v->width, label->value.s, v->name);
+                       "for variable %s."),
+                 handle_get_filename (h), v->width, label->value.s, v->name);
        }
     }
 
@@ -1114,9 +1138,11 @@ bufread (struct file_handle * h, void *buf, size_t nbytes, size_t minalloc)
   if (1 != fread (buf, nbytes, 1, ext->file))
     {
       if (ferror (ext->file))
-       msg (ME, _("%s: Reading system file: %s."), h->fn, strerror (errno));
+       msg (ME, _("%s: Reading system file: %s."),
+             handle_get_filename (h), strerror (errno));
       else
-       corrupt_msg (ME, _("%s: Unexpected end of file."), h->fn);
+       corrupt_msg (ME, _("%s: Unexpected end of file."),
+                     handle_get_filename (h));
       return NULL;
     }
   return buf;
@@ -1134,13 +1160,15 @@ read_documents (struct file_handle * h)
   char *documents;
 
   if (dict_get_documents (dict) != NULL)
-    lose ((ME, _("%s: System file contains multiple type 6 (document) records."),
-          h->fn));
+    lose ((ME, _("%s: System file contains multiple "
+                 "type 6 (document) records."),
+          handle_get_filename (h)));
 
   assertive_bufread (h, &n_lines, sizeof n_lines, 0);
   if (n_lines <= 0)
-    lose ((ME, _("%s: Number of document lines (%ld) must be greater than 0."),
-          h->fn, (long) n_lines));
+    lose ((ME, _("%s: Number of document lines (%ld) "
+                 "must be greater than 0."),
+          handle_get_filename (h), (long) n_lines));
 
   documents = bufread (h, NULL, 80 * n_lines, n_lines * 80 + 1);
   /* FIXME?  Run through asciify. */
@@ -1251,7 +1279,8 @@ buffer_input (struct file_handle * h)
   amt = fread (ext->buf, sizeof *ext->buf, 128, ext->file);
   if (ferror (ext->file))
     {
-      msg (ME, _("%s: Error reading file: %s."), h->fn, strerror (errno));
+      msg (ME, _("%s: Error reading file: %s."),
+           handle_get_filename (h), strerror (errno));
       return 0;
     }
   ext->ptr = ext->buf;
@@ -1290,7 +1319,8 @@ read_compressed_data (struct file_handle * h, flt64 * temp)
            /* Code 252 is end of file. */
            if (temp_beg != temp)
              lose ((ME, _("%s: Compressed data is corrupted.  Data ends "
-                    "partway through a case."), h->fn));
+                    "in partial case."),
+                     handle_get_filename (h)));
            goto lossage;
          case 253:
            /* Code 253 indicates that the value is stored explicitly
@@ -1298,7 +1328,8 @@ read_compressed_data (struct file_handle * h, flt64 * temp)
            if (ext->ptr == NULL || ext->ptr >= ext->end)
              if (!buffer_input (h))
                {
-                 lose ((ME, _("%s: Unexpected end of file."), h->fn));
+                 lose ((ME, _("%s: Unexpected end of file."),
+                         handle_get_filename (h)));
                  goto lossage;
                }
            memcpy (temp++, ext->ptr++, sizeof *temp);
@@ -1339,7 +1370,8 @@ read_compressed_data (struct file_handle * h, flt64 * temp)
        if (!buffer_input (h))
          {
            if (temp_beg != temp)
-             lose ((ME, _("%s: Unexpected end of file."), h->fn));
+             lose ((ME, _("%s: Unexpected end of file."),
+                     handle_get_filename (h)));
            goto lossage;
          }
       memcpy (ext->x, ext->ptr++, sizeof *temp);
@@ -1389,9 +1421,11 @@ sfm_read_case (struct file_handle * h, union value * perm, struct dictionary * d
       if (amt != nbytes)
        {
          if (ferror (ext->file))
-           msg (ME, _("%s: Reading system file: %s."), h->fn, strerror (errno));
+           msg (ME, _("%s: Reading system file: %s."),
+                 handle_get_filename (h), strerror (errno));
          else if (amt != 0)
-           msg (ME, _("%s: Partial record at end of system file."), h->fn);
+           msg (ME, _("%s: Partial record at end of system file."),
+                 handle_get_filename (h));
          goto lossage;
        }
     }
index fd500f45c00b42062240d2eeb7bdf24813e083b7..64d364abb6cd753c760b327e03d48278d6a3a0c6 100644 (file)
@@ -92,23 +92,25 @@ sfm_write_dictionary (struct sfm_write_info *inf)
 
   if (inf->h->class != NULL)
     {
-      msg (ME, _("Cannot write file %s as system file: already opened for %s."),
-          fh_handle_name (inf->h), inf->h->class->name);
+      msg (ME, _("Cannot write file %s as system file: "
+                 "already opened for %s."),
+          handle_get_name (inf->h), inf->h->class->name);
       return 0;
     }
 
   msg (VM (1), _("%s: Opening system-file handle %s for writing."),
-       fh_handle_filename (inf->h), fh_handle_name (inf->h));
+       handle_get_filename (inf->h), handle_get_name (inf->h));
   
   /* Open the physical disk file. */
   inf->h->class = &sfm_w_class;
   inf->h->ext = ext = xmalloc (sizeof (struct sfm_fhuser_ext));
-  ext->file = fopen (inf->h->norm_fn, "wb");
+  ext->file = fopen (handle_get_filename (inf->h), "wb");
   ext->elem_type = NULL;
   if (ext->file == NULL)
     {
       msg (ME, _("An error occurred while opening \"%s\" for writing "
-          "as a system file: %s."), inf->h->fn, strerror (errno));
+                 "as a system file: %s."),
+           handle_get_filename (inf->h), strerror (errno));
       err_cond_fail ();
       free (ext);
       return 0;
@@ -600,7 +602,8 @@ bufwrite (struct file_handle * h, const void *buf, size_t nbytes)
   assert (buf);
   if (1 != fwrite (buf, nbytes, 1, ext->file))
     {
-      msg (ME, _("%s: Writing system file: %s."), h->fn, strerror (errno));
+      msg (ME, _("%s: Writing system file: %s."),
+           handle_get_filename (h), strerror (errno));
       return 0;
     }
   return 1;
@@ -736,7 +739,8 @@ sfm_close (struct file_handle * h)
     }
 
   if (EOF == fclose (ext->file))
-    msg (ME, _("%s: Closing system file: %s."), h->fn, strerror (errno));
+    msg (ME, _("%s: Closing system file: %s."),
+         handle_get_filename (h), strerror (errno));
   free (ext->buf);
 
   free (ext->elem_type);
index ac70da11814c3a92b659c40a86e918def89e65f5..cc0a833f696348459585c48ec56458baad1a8ec4 100644 (file)
@@ -69,8 +69,6 @@ cmd_sort_cases (void)
   struct sort_cases_pgm *scp;
   int success;
 
-  lex_match_id ("SORT");
-  lex_match_id ("CASES");
   lex_match (T_BY);
 
   scp = parse_sort ();
index bffcd5b18007d1c135b76e0e77467794fa233560..6eba150b9928032db393430dbcd0c9083a4e0fda 100644 (file)
@@ -29,9 +29,6 @@
 int
 cmd_split_file (void)
 {
-  lex_match_id ("SPLIT");
-  lex_match_id ("FILE");
-
   if (lex_match_id ("OFF"))
     dict_set_split_vars (default_dict, NULL, 0);
   else
index e4a2dce720762c0e22ccc37615aee998e81941b0..c67c184e2d037767e7ef0d31a3e945fb56db91dc 100644 (file)
@@ -77,9 +77,6 @@ cmd_sysfile_info (void)
   int r, nr;
   int i;
 
-  lex_match_id ("SYSFILE");
-  lex_match_id ("INFO");
-
   lex_match_id ("FILE");
   lex_match ('=');
 
@@ -95,7 +92,7 @@ cmd_sysfile_info (void)
   t = tab_create (2, 9, 0);
   tab_vline (t, TAL_1 | TAL_SPACING, 1, 0, 8);
   tab_text (t, 0, 0, TAB_LEFT, _("File:"));
-  tab_text (t, 1, 0, TAB_LEFT, fh_handle_filename (h));
+  tab_text (t, 1, 0, TAB_LEFT, handle_get_filename (h));
   tab_text (t, 0, 1, TAB_LEFT, _("Label:"));
   {
     const char *label = dict_get_label (d);
@@ -180,8 +177,6 @@ cmd_display (void)
   int n;
   struct variable **vl;
 
-  lex_match_id ("DISPLAY");
-
   if (lex_match_id ("MACROS"))
     display_macros ();
   else if (lex_match_id ("DOCUMENTS"))
index c76bd2d66937bc2801b74b5c5cc525fb240e40a8..8cef9053b1880250157b62934b7810fae71a4b4e 100644 (file)
@@ -213,12 +213,6 @@ cmd_t_test(void)
   struct ssbox stat_summary_box;
   struct trbox test_results_box;
 
-  if (!lex_force_match_id ("T"))
-    return CMD_FAILURE;
-
-  lex_match ('-');
-  lex_match_id ("TEST");
-
   if ( !parse_t_test(&cmd) )
     return CMD_FAILURE;
 
index 090ceafea1a986734f02038e85dc5b6a244f79fa..70d86cab285e2b3f3b0fd9a8f4db806e2b83fa40 100644 (file)
@@ -39,8 +39,6 @@ int temp_trns;
 int
 cmd_temporary (void)
 {
-  lex_match_id ("TEMPORARY");
-
   /* TEMPORARY is not allowed inside DO IF or LOOP. */
   if (ctl_stack)
     {
index dca7b4760777b96e267808719b6dcf3930f41c38..50a065b9d846bbd1c5483f138a572da9b7e638ed 100644 (file)
@@ -171,9 +171,6 @@ cmd_document (void)
 int
 cmd_drop_documents (void)
 {
-  lex_match_id ("DROP");
-  lex_match_id ("DOCUMENTS");
-
   dict_set_documents (default_dict, NULL);
 
   return lex_end_of_command ();
index 9d289cbce50f7c707637092332d1f53ae59b5fdc..882f26e625933b7364510bb112ef57f2e0edf2af 100644 (file)
@@ -41,17 +41,12 @@ static int get_label (struct variable **vars, int var_cnt);
 int
 cmd_value_labels (void)
 {
-  lex_match_id ("VALUE");
-  lex_match_id ("LABELS");
   return do_value_labels (1);
 }
 
 int
 cmd_add_value_labels (void)
 {
-  lex_match_id ("ADD");
-  lex_match_id ("VALUE");
-  lex_match_id ("LABELS");
   return do_value_labels (0);
 }
 \f
@@ -82,6 +77,7 @@ do_value_labels (int erase)
 
       free (vars);
     }
+  free (vars);
 
   if (token != '.')
     {
index bc22439669c49b919def5785a67af970e7b5d344..ee9f4b786d763f6a5b65f2664a7099b7b0b680c9 100644 (file)
@@ -41,8 +41,6 @@ cmd_variable_labels (void)
 
   int i;
 
-  lex_match_id ("VARIABLE");
-  lex_match_id ("LABELS");
   lex_match ('/');
   do
     {
index 2296672dc22363be9e0641f009c2744b0e2efe85..99b3423af1467ff1aea250bd73221749bb3e88bc 100644 (file)
@@ -43,8 +43,6 @@ cmd_vector (void)
   /* Maximum allocated position for vecnames, plus one position. */
   char *endp = NULL;
 
-  lex_match_id ("VECTOR");
-
   cp = vecnames = xmalloc (256);
   endp = &vecnames[256];
   do
index 0c152c09f78bb17cf551182d6e9aa563f47c5847..b5d2a8d3564e76641e692bace61df3fe3befcf76 100644 (file)
--- a/src/vfm.c
+++ b/src/vfm.c
@@ -435,8 +435,12 @@ close_active_file (void)
   /* Old data sink becomes new data source. */
   if (vfm_sink->class->make_source != NULL)
     vfm_source = vfm_sink->class->make_source (vfm_sink);
-  else
-    vfm_source = NULL;
+  else 
+    {
+      if (vfm_sink->class->destroy != NULL)
+        vfm_sink->class->destroy (vfm_sink);
+      vfm_source = NULL; 
+    }
   free_case_sink (vfm_sink);
   vfm_sink = NULL;
 
index 41dc33f65562becfde277be97d86165e320a50e1..66b7e615ac0aa7ca49f6143793c4be2d174450c0 100644 (file)
@@ -37,8 +37,6 @@ struct weight_trns
 int
 cmd_weight (void)
 {
-  lex_match_id ("WEIGHT");
-
   if (lex_match_id ("OFF"))
     dict_set_weight (default_dict, NULL);
   else
index 447cb20be77f284ea9a3d1af68a0214c2be2a8d6..559bda0838ceadf235ad5a53c3573f1b86539cf4 100644 (file)
@@ -1,3 +1,11 @@
+Sat Mar 20 18:11:15 2004  Ben Pfaff  <blp@gnu.org>
+
+       * command/list.sh: Update output.
+
+       * command/print.sh: Ditto.
+
+       * command/weight.sh: Ditto.
+
 Sun Mar 14 23:04:14 2004  Ben Pfaff  <blp@gnu.org>
 
        * command/sort.sh: Use numeric, not string, data to avoid spurious
index c82dd27346c8b951b405bb69cac191ecdb67f0b4..33297eb00753813869e9499edf32f26c85260fc0 100755 (executable)
@@ -85,7 +85,7 @@ diff -b -B $TEMPDIR/pspp.list - <<EOF
 Testing use of LIST in single-line cases.
 ----------------------------------------------------------------------
 
-1.1 DATA LIST.  Reading 1 record from file "$top_srcdir/tests/weighting.data".
+1.1 DATA LIST.  Reading 1 record from file $top_srcdir/tests/weighting.data.
 +--------+------+-------+------+
 |Variable|Record|Columns|Format|
 #========#======#=======#======#
index f408a0fa2f8e8ff7173329860567ce9adadb6575..8e058c68c2d6702a1c5171468d83040ae32f62f3 100755 (executable)
@@ -121,7 +121,7 @@ rest of the tests give it a pretty good workout.
 Testing use of DATA LIST FREE.
 ----------------------------------------------------------------------
 
-1.1 DATA LIST.  Reading free-form data from file "$TEMPDIR/data-list.data".
+1.1 DATA LIST.  Reading free-form data from file $TEMPDIR/data-list.data.
 +--------+------+
 |Variable|Format|
 #========#======#
@@ -131,7 +131,7 @@ Testing use of DATA LIST FREE.
 |D       |F8.0  |
 +--------+------+
 
-2.1 PRINT.  Writing   1 records to file "foo".
+2.1 PRINT.  Writing 1 record(s) to file foo.
 +--------+------+-------+-------+
 |Variable|Record|Columns| Format|
 #========#======#=======#=======#
@@ -158,7 +158,7 @@ Testing use of DATA LIST FREE.
 Testing use of DATA LIST LIST.
 ----------------------------------------------------------------------
 
-3.1 DATA LIST.  Reading free-form data from file "$TEMPDIR/data-list.data".
+3.1 DATA LIST.  Reading free-form data from file $TEMPDIR/data-list.data.
 +--------+------+
 |Variable|Format|
 #========#======#
@@ -168,7 +168,7 @@ Testing use of DATA LIST LIST.
 |D       |F8.0  |
 +--------+------+
 
-4.1 PRINT.  Writing   1 records to the listing file.
+4.1 PRINT.  Writing 1 record(s) to the listing file.
 +--------+------+-------+------+
 |Variable|Record|Columns|Format|
 #========#======#=======#======#
index 826a9a1cc089fb70d75185b45c1be2646fc08f10..df34b49935da4637bb496af2cf26beda0ad1dde2 100755 (executable)
@@ -63,7 +63,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare results"
 diff -B -b $TEMPDIR/pspp.list - <<EOF
-1.1 DATA LIST.  Reading 1 record from file "$top_srcdir/tests/weighting.data".
+1.1 DATA LIST.  Reading 1 record from file $top_srcdir/tests/weighting.data.
 +--------+------+-------+------+
 |Variable|Record|Columns|Format|
 #========#======#=======#======#