+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
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 \
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 (;;)
{
int i;
- lex_match_id ("APPLY");
- lex_match_id ("DICTIONARY");
-
lex_match_id ("FROM");
lex_match ('=');
handle = fh_parse_file_handle ();
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,
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);
}
#if HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
-
-#include "debug-print.h"
\f
/* Global variables. */
/* 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;
&& 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."));
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
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;
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 ();
const char *prev_proc;
prev_proc = cur_proc;
- cur_proc = cp->cmd;
+ cur_proc = cp->name;
result = cp->func ();
cur_proc = prev_proc;
}
}
}
-#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. */
/* 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 ();
int
cmd_execute (void)
{
- lex_match_id ("EXECUTE");
procedure (NULL, NULL);
return lex_end_of_command ();
}
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 ('=');
return CMD_FAILURE;
}
- lex_match_id ("HOST");
-
#ifdef unix
/* Figure out whether to invoke an interactive shell or to execute a
single shell command. */
int
cmd_new_file (void)
{
- lex_match_id ("NEW");
- lex_match_id ("FILE");
-
discard_variables ();
return lex_end_of_command ();
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."));
}
cancel_transformations ();
+ /* FIXME: what about variables created by transformations?
+ They need to be properly initialized. */
return CMD_SUCCESS;
}
#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)
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)
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)
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)
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)
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)
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 */
struct lvalue *lvalue = NULL;
struct compute_trns *compute = NULL;
- lex_match_id ("COMPUTE");
-
lvalue = lvalue_parse ();
if (lvalue == NULL)
goto fail;
struct compute_trns *compute = NULL;
struct lvalue *lvalue = NULL;
- lex_match_id ("IF");
compute = compute_trns_create ();
/* Test expression. */
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;
-}
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);
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 (;;)
pl_tc = pool_create ();
pl_col = pool_create ();
- lex_match_id ("CROSSTABS");
if (!parse_crosstabs (&cmd))
return CMD_FAILURE;
/* 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 ();
dump_free_table (dls);
}
+ if (!dfm_open_for_reading (dls->handle))
+ goto error;
+
if (vfm_source != NULL)
{
struct data_list_pgm *new_pgm;
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);
tab_title (t, 0, buf);
tab_submit (t);
- fh_handle_name (NULL);
local_free (buf);
}
\f
{
const char *filename;
- filename = fh_handle_name (dls->handle);
+ filename = handle_get_filename (dls->handle);
if (filename == NULL)
filename = "";
tab_title (t, 1,
}
tab_submit (t);
- fh_handle_name (NULL);
}
\f
/* Input procedure. */
/* 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);
/* 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)
--- /dev/null
+/* 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;
+}
v_variables = NULL;
n_variables = 0;
- lex_match_id ("DESCRIPTIVES");
- lex_match_id ("CONDESCRIPTIVES");
if (!parse_descriptives (&cmd))
goto lossage;
{
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. */
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)
{
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
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 "
err_failure ();
}
- h->where.line_number++;
+ ext->where.line_number++;
if (ds_length (&getl_buf) >= 8
&& !strncasecmp (ds_value (&getl_buf), "end data", 8))
}
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. */
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;
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--;
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;
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
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
{
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;
}
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. */
/* 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."));
/* 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);
{
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)
{
/* 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)
{
struct do_if_trns *t;
struct expression *e;
- lex_match_id ("IF");
-
e = expr_parse (PXP_BOOLEAN);
if (!e)
return NULL;
e.text = buf.string;
err_vmsg (&e);
}
+
+ ds_destroy (&buf);
}
/* Terminate due to fatal error in input. */
sp->f = SYSMIS;
break;
}
+ assert (c != NULL);
sp->f = c->data[v->var[rindx - 1]->fv].f;
}
break;
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;
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;
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++;
}
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:
/* 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
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. */
#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. */
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;
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 */
#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_):
/* (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;
}
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:
\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
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
{
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;
}
/*
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"))
}
}
+ if (!dfm_open_for_reading (fty->handle))
+ goto error;
default_handle = fty->handle;
create_col_var (&fty->record);
}
}
- lex_match_id ("RECORD");
- lex_match_id ("TYPE");
-
/* Parse record type values. */
if (lex_match_id ("OTHER"))
rct->flags |= RCT_OTHER;
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;
}
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 */
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;
flip->new_names_tail = NULL;
flip->file = NULL;
- lex_match_id ("FLIP");
lex_match ('/');
if (lex_match_id ("VARIABLES"))
{
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);
}
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;
struct get_pgm *pgm;
int options = GTSV_OPT_NONE;
- lex_match_id ("GET");
discard_variables ();
lex_match ('/');
int i;
- lex_match_id ("SAVE");
-
lex_match ('/');
if (lex_match_id ("OUTFILE"))
lex_match ('=');
int seen = 0;
- lex_match_id ("MATCH");
- lex_match_id ("FILES");
-
mtf.head = mtf.tail = NULL;
mtf.by = NULL;
mtf.by_cnt = 0;
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;
}
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;
}
int options = GTSV_OPT_NONE;
int type;
- lex_match_id ("IMPORT");
-
for (;;)
{
lex_match ('/');
int i;
- lex_match_id ("EXPORT");
-
lex_match ('/');
if (lex_match_id ("OUTFILE"))
lex_match ('=');
#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 ();
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
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."));
{
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 "
/* Created transformation. */
struct reread_trns *t;
- lex_match_id ("REREAD");
-
h = default_handle;
e = NULL;
while (token != '.')
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;
{
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 "
#include <assert.h>
#include "levene.h"
#include "hash.h"
+#include "str.h"
#include "var.h"
#include "vfm.h"
#include "alloc.h"
/* 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);
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
return;
}
- if (put)
+ if (put_token)
{
- token = put;
- put = 0;
+ restore_token ();
#if DUMP_TOKENS
dump_token ();
#endif
int
lex_look_ahead (void)
{
- if (put)
- return put;
+ if (put_token)
+ return put_token;
for (;;)
{
else if (!lex_get_line ())
unexpected_eof ();
- if (put)
- return put;
+ if (put_token)
+ return put_token;
}
if ((toupper ((unsigned char) *prog) == 'X'
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. */
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
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);
{
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 = '-';
}
}
for (;;)
{
lex_get_line ();
- if (put == '.')
+ if (put_token == '.')
break;
prog = ds_end (&getl_buf);
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;
}
}
/* 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);
{
struct variable casenum_var;
- lex_match_id ("LIST");
if (!parse_list (&cmd))
return CMD_FAILURE;
/* 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);
/* New transformation. */
struct break_trns *t;
- lex_match_id ("BREAK");
-
for (loop = ctl_stack; loop; loop = loop->down)
if (loop->type == CST_LOOP)
break;
msg (FE, _("Error initializing output drivers."));
lex_init ();
- cmd_init ();
/* Execution. */
parse_script ();
unsigned seen = 0;
- lex_match_id ("MATRIX");
- lex_match_id ("DATA");
-
discard_variables ();
pool = pool_create ();
debug_print ();
#endif
+ if (!dfm_open_for_reading (mx->data_file))
+ goto lossage;
+
if (mx->explicit_rowtype)
read_matrices_with_rowtype (mx);
else
v_dim = NULL;
v_var = NULL;
- lex_match_id ("MEANS");
if (!parse_means (&cmd))
goto free;
{
int i;
- lex_match_id ("MISSING");
- lex_match_id ("VALUES");
while (token != '.')
{
if (!parse_varnames ())
cancel_temporary ();
}
- lex_match_id ("MODIFY");
- lex_match_id ("VARS");
-
vm.reorder_vars = NULL;
vm.reorder_cnt = 0;
vm.rename_vars = NULL;
be used. */
struct fmt_spec f;
- lex_match_id ("NUMERIC");
do
{
if (!parse_DATA_LIST_vars (&v, &nv, PV_NONE))
/* Width of variables to create. */
int width;
- lex_match_id ("STRING");
do
{
if (!parse_DATA_LIST_vars (&v, &nv, PV_NONE))
int i;
- lex_match_id ("LEAVE");
if (!parse_variables (default_dict, &v, &nv, PV_NONE))
return CMD_FAILURE;
for (i = 0; i < nv; i++)
{
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);
/* 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);
{
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;
{
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;
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;
}
}
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);
#include "tab.h"
#include "var.h"
-#include "debug-print.h"
-
/* Describes what to do when an output field is encountered. */
enum
{
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. */
int
cmd_print (void)
{
- lex_match_id ("PRINT");
return internal_cmd_print (PRT_PRINT);
}
int
cmd_print_eject (void)
{
- lex_match_id ("EJECT");
return internal_cmd_print (PRT_PRINT | PRT_EJECT);
}
int
cmd_write (void)
{
- lex_match_id ("WRITE");
return internal_cmd_print (PRT_WRITE);
}
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 ();
memcpy (trns, &prt, sizeof *trns);
add_transformation ((struct trns_header *) trns);
-#if 0 && DEBUGGING
- debug_print ();
-#endif
-
return CMD_SUCCESS;
lossage:
dump_table (void)
{
struct prt_out_spec *spec;
- const char *filename;
struct tab_table *t;
int recno;
int nspec;
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. */
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__
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 ();
}
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)
{
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 */
struct variable **v;
int nv;
- lex_match_id ("RECODE");
-
/* Parses each specification between slashes. */
head = rcd = xmalloc (sizeof *rcd);
v = NULL;
cancel_temporary ();
}
- lex_match_id ("RENAME");
- lex_match_id ("VARIABLES");
-
do
{
int prev_nv_1 = rename_cnt;
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
int a, b;
unsigned frac;
- lex_match_id ("SAMPLE");
-
if (!lex_force_num ())
return CMD_FAILURE;
if (!lex_integer_p ())
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;
int
cmd_filter (void)
{
- lex_match_id ("FILTER");
-
if (lex_match_id ("OFF"))
dict_set_filter (default_dict, NULL);
else
{
struct expression *e;
- lex_match_id ("PROCESS");
- lex_match_id ("IF");
-
e = expr_parse (PXP_BOOLEAN);
if (!e)
return CMD_FAILURE;
cmd_set (void)
{
- lex_match_id ("SET");
-
if (!parse_set (&cmd))
return CMD_FAILURE;
static void
-set_viewport(void)
+set_viewport(int sig_num UNUSED)
{
#if HAVE_LIBTERMCAP
static char term_buffer[16384];
if ( ! long_view )
{
- set_viewport();
- signal (SIGWINCH,set_viewport);
+ set_viewport (0);
+ signal (SIGWINCH, set_viewport);
}
}
/* 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);
}
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;
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);
}
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))
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:
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;
}
}
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));
}
}
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);
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)
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
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;
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)
"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);
}
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);
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);
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. */
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
{
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--;
}
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. */
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 == '@'
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;
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;
/* 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);
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);
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)
{
/* 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;
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;
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));
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
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);
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;
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")));
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);
}
}
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;
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. */
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;
/* 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
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);
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);
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;
}
}
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;
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;
}
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);
struct sort_cases_pgm *scp;
int success;
- lex_match_id ("SORT");
- lex_match_id ("CASES");
lex_match (T_BY);
scp = parse_sort ();
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
int r, nr;
int i;
- lex_match_id ("SYSFILE");
- lex_match_id ("INFO");
-
lex_match_id ("FILE");
lex_match ('=');
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);
int n;
struct variable **vl;
- lex_match_id ("DISPLAY");
-
if (lex_match_id ("MACROS"))
display_macros ();
else if (lex_match_id ("DOCUMENTS"))
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;
int
cmd_temporary (void)
{
- lex_match_id ("TEMPORARY");
-
/* TEMPORARY is not allowed inside DO IF or LOOP. */
if (ctl_stack)
{
int
cmd_drop_documents (void)
{
- lex_match_id ("DROP");
- lex_match_id ("DOCUMENTS");
-
dict_set_documents (default_dict, NULL);
return lex_end_of_command ();
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
free (vars);
}
+ free (vars);
if (token != '.')
{
int i;
- lex_match_id ("VARIABLE");
- lex_match_id ("LABELS");
lex_match ('/');
do
{
/* Maximum allocated position for vecnames, plus one position. */
char *endp = NULL;
- lex_match_id ("VECTOR");
-
cp = vecnames = xmalloc (256);
endp = &vecnames[256];
do
/* 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;
int
cmd_weight (void)
{
- lex_match_id ("WEIGHT");
-
if (lex_match_id ("OFF"))
dict_set_weight (default_dict, NULL);
else
+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
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|
#========#======#=======#======#
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|
#========#======#
|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|
#========#======#=======#=======#
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|
#========#======#
|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|
#========#======#=======#======#
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|
#========#======#=======#======#