X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Fcommand.c;h=bffd13ebb0d74b119de6d296b7e4f4fe3ba91f60;hb=39df27f80745cf9622ac5e916a098c17961c2585;hp=ff2b030ce0e206f3af47c48f090368027dd60e4c;hpb=fe8dc2171009e90d2335f159d05f7e6660e24780;p=pspp diff --git a/src/language/command.c b/src/language/command.c index ff2b030ce0..bffd13ebb0 100644 --- a/src/language/command.c +++ b/src/language/command.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2009, 2010, 2011 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc. 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 @@ -36,9 +36,9 @@ #include "libpspp/i18n.h" #include "libpspp/message.h" #include "libpspp/str.h" -#include "output/text-item.h" +#include "output/driver.h" +#include "output/output-item.h" -#include "xalloc.h" #include "xmalloca.h" #include "gettext.h" @@ -50,10 +50,19 @@ static inline bool cmd_result_is_valid (enum cmd_result result) { - return (result == CMD_SUCCESS || result == CMD_EOF || result == CMD_FINISH - || (result >= CMD_PRIVATE_FIRST && result <= CMD_PRIVATE_LAST) - || result == CMD_FAILURE || result == CMD_NOT_IMPLEMENTED - || result == CMD_CASCADING_FAILURE); + switch (result) + { + case CMD_SUCCESS: + case CMD_EOF: + case CMD_FINISH: + case CMD_FAILURE: + case CMD_NOT_IMPLEMENTED: + case CMD_CASCADING_FAILURE: + return true; + + default: + return false; + } } /* Returns true if RESULT indicates success, @@ -77,19 +86,23 @@ cmd_result_is_failure (enum cmd_result result) /* Command processing states. */ enum states { - S_INITIAL = 0x01, /* Allowed before active dataset defined. */ - S_DATA = 0x02, /* Allowed after active dataset defined. */ - S_INPUT_PROGRAM = 0x04, /* Allowed in INPUT PROGRAM. */ - S_FILE_TYPE = 0x08, /* Allowed in FILE TYPE. */ - S_ANY = 0x0f /* Allowed anywhere. */ + S_INITIAL = 1 << CMD_STATE_INITIAL, + S_DATA = 1 << CMD_STATE_DATA, + S_INPUT_PROGRAM = 1 << CMD_STATE_INPUT_PROGRAM, + S_FILE_TYPE = 1 << CMD_STATE_FILE_TYPE, + S_NESTED_DATA = 1 << CMD_STATE_NESTED_DATA, + S_NESTED_INPUT_PROGRAM = 1 << CMD_STATE_NESTED_INPUT_PROGRAM, + + S_NESTED_ANY = S_NESTED_DATA | S_NESTED_INPUT_PROGRAM, + S_ANY = S_INITIAL | S_DATA | S_INPUT_PROGRAM | S_FILE_TYPE | S_NESTED_ANY, }; /* Other command requirements. */ enum flags { - F_ENHANCED = 0x10, /* Allowed only in enhanced syntax mode. */ - F_TESTING = 0x20, /* Allowed only in testing mode. */ - F_ABBREV = 0x80 /* Not a candidate for name completion. */ + F_ENHANCED = 1 << 0, /* Allowed only in enhanced syntax mode. */ + F_TESTING = 1 << 1, /* Allowed only in testing mode. */ + F_ABBREV = 1 << 2 /* Not a candidate for name completion. */ }; /* A single command. */ @@ -111,10 +124,10 @@ static const struct command commands[] = #undef DEF_CMD #undef UNIMPL_CMD -static const size_t command_cnt = sizeof commands / sizeof *commands; +static const size_t n_commands = sizeof commands / sizeof *commands; static bool in_correct_state (const struct command *, enum cmd_state); -static bool report_state_mismatch (const struct command *, enum cmd_state); +static void report_state_mismatch (const struct command *, enum cmd_state); static void set_completion_state (enum cmd_state); /* Command parser. */ @@ -138,7 +151,6 @@ cmd_parse_in_state (struct lexer *lexer, struct dataset *ds, ds = session_active_dataset (session); assert (!proc_is_open (ds)); unset_cmd_algorithm (); - dict_clear_aux (dataset_dict (ds)); if (!dataset_end_of_command (ds)) result = CMD_CASCADING_FAILURE; @@ -151,7 +163,7 @@ cmd_parse (struct lexer *lexer, struct dataset *ds) const struct dictionary *dict = dataset_dict (ds); return cmd_parse_in_state (lexer, ds, dataset_has_source (ds) && - dict_get_var_cnt (dict) > 0 ? + dict_get_n_vars (dict) > 0 ? CMD_STATE_DATA : CMD_STATE_INITIAL); } @@ -163,8 +175,8 @@ do_parse_command (struct lexer *lexer, struct dataset *ds, enum cmd_state state) { const struct command *command = NULL; + size_t nesting_level = SIZE_MAX; enum cmd_result result; - bool opened = false; int n_tokens; /* Read the command's first token. */ @@ -188,8 +200,10 @@ do_parse_command (struct lexer *lexer, result = CMD_FAILURE; goto finish; } - text_item_submit (text_item_create (TEXT_ITEM_COMMAND_OPEN, command->name)); - opened = true; + + nesting_level = output_open_group (group_item_create_nocopy ( + utf8_to_title (command->name), + utf8_to_title (command->name))); if (command->function == NULL) { @@ -231,12 +245,12 @@ finish: result = lex_end_of_command (lexer); lex_discard_rest_of_command (lexer); - while (lex_token (lexer) == T_ENDCMD) - lex_get (lexer); + if (result != CMD_EOF && result != CMD_FINISH) + while (lex_token (lexer) == T_ENDCMD) + lex_get (lexer); - if (opened) - text_item_submit (text_item_create (TEXT_ITEM_COMMAND_CLOSE, - command->name)); + if (nesting_level != SIZE_MAX) + output_close_groups (nesting_level); return result; } @@ -249,7 +263,7 @@ find_best_match (struct substring s, const struct command **matchp) int missing_words; command_matcher_init (&cm, s); - for (cmd = commands; cmd < &commands[command_cnt]; cmd++) + for (cmd = commands; cmd < &commands[n_commands]; cmd++) command_matcher_add (&cm, ss_cstr (cmd->name), CONST_CAST (void *, cmd)); *matchp = command_matcher_get_match (&cm); @@ -347,22 +361,22 @@ parse_command_name (struct lexer *lexer, int *n_tokens) static bool in_correct_state (const struct command *command, enum cmd_state state) { - return ((state == CMD_STATE_INITIAL && command->states & S_INITIAL) - || (state == CMD_STATE_DATA && command->states & S_DATA) - || (state == CMD_STATE_INPUT_PROGRAM - && command->states & S_INPUT_PROGRAM) - || (state == CMD_STATE_FILE_TYPE && command->states & S_FILE_TYPE)); + return command->states & (1 << state); } /* Emits an appropriate error message for trying to invoke COMMAND in STATE. */ -static bool +static void report_state_mismatch (const struct command *command, enum cmd_state state) { assert (!in_correct_state (command, state)); - if (state == CMD_STATE_INITIAL || state == CMD_STATE_DATA) + + switch (state) { - switch (command->states) + case CMD_STATE_INITIAL: + case CMD_STATE_DATA: + switch ((int) command->states + & (S_INITIAL | S_DATA | S_INPUT_PROGRAM | S_FILE_TYPE)) { /* One allowed state. */ case S_INITIAL: @@ -374,35 +388,35 @@ report_state_mismatch (const struct command *command, enum cmd_state state) "been defined."), command->name); break; case S_INPUT_PROGRAM: - msg (SE, _("%s is allowed only inside INPUT PROGRAM."), - command->name); + msg (SE, _("%s is allowed only inside %s."), + command->name, "INPUT PROGRAM"); break; case S_FILE_TYPE: - msg (SE, _("%s is allowed only inside FILE TYPE."), command->name); + msg (SE, _("%s is allowed only inside %s."), command->name, "FILE TYPE"); break; /* Two allowed states. */ case S_INITIAL | S_DATA: NOT_REACHED (); case S_INITIAL | S_INPUT_PROGRAM: - msg (SE, _("%s is allowed only before the active dataset has " - "been defined or inside INPUT PROGRAM."), command->name); + msg (SE, _("%s is allowed only before the active dataset has been defined or inside %s."), + command->name, "INPUT PROGRAM"); break; case S_INITIAL | S_FILE_TYPE: - msg (SE, _("%s is allowed only before the active dataset has " - "been defined or inside FILE TYPE."), command->name); + msg (SE, _("%s is allowed only before the active dataset has been defined or inside %s."), + command->name, "FILE TYPE"); break; case S_DATA | S_INPUT_PROGRAM: - msg (SE, _("%s is allowed only after the active dataset has " - "been defined or inside INPUT PROGRAM."), command->name); + msg (SE, _("%s is allowed only after the active dataset has been defined or inside %s."), + command->name, "INPUT PROGRAM"); break; case S_DATA | S_FILE_TYPE: - msg (SE, _("%s is allowed only after the active dataset has " - "been defined or inside FILE TYPE."), command->name); + msg (SE, _("%s is allowed only after the active dataset has been defined or inside %s."), + command->name, "FILE TYPE"); break; case S_INPUT_PROGRAM | S_FILE_TYPE: - msg (SE, _("%s is allowed only inside INPUT PROGRAM " - "or inside FILE TYPE."), command->name); + msg (SE, _("%s is allowed only inside %s or inside %s."), command->name, + "INPUT PROGRAM", "FILE TYPE"); break; /* Three allowed states. */ @@ -428,14 +442,35 @@ report_state_mismatch (const struct command *command, enum cmd_state state) default: NOT_REACHED (); } - } - else if (state == CMD_STATE_INPUT_PROGRAM) - msg (SE, _("%s is not allowed inside %s."), - command->name, "INPUT PROGRAM" ); - else if (state == CMD_STATE_FILE_TYPE) - msg (SE, _("%s is not allowed inside %s."), command->name, "FILE TYPE"); + break; + + case CMD_STATE_INPUT_PROGRAM: + msg (SE, _("%s is not allowed inside %s."), + command->name, "INPUT PROGRAM"); + break; - return false; + case CMD_STATE_FILE_TYPE: + msg (SE, _("%s is not allowed inside %s."), command->name, "FILE TYPE"); + break; + + case CMD_STATE_NESTED_DATA: + case CMD_STATE_NESTED_INPUT_PROGRAM: + switch ((int) command->states & S_NESTED_ANY) + { + case 0: + msg (SE, _("%s is not allowed inside DO IF or LOOP."), command->name); + break; + + case S_NESTED_DATA: + msg (SE, _("In INPUT PROGRAM, " + "%s is not allowed inside DO IF or LOOP."), command->name); + break; + + default: + NOT_REACHED (); + } + break; + } } /* Command name completion. */ @@ -458,7 +493,7 @@ cmd_complete (const char *prefix, const struct command **cmd) if (*cmd == NULL) *cmd = commands; - for (; *cmd < commands + command_cnt; (*cmd)++) + for (; *cmd < commands + n_commands; (*cmd)++) if (!memcasecmp ((*cmd)->name, prefix, strlen (prefix)) && (!((*cmd)->flags & F_TESTING) || settings_get_testing_mode ()) && (!((*cmd)->flags & F_ENHANCED) || settings_get_syntax () == ENHANCED) @@ -483,15 +518,12 @@ cmd_finish (struct lexer *lexer UNUSED, struct dataset *ds UNUSED) int cmd_n_of_cases (struct lexer *lexer, struct dataset *ds) { - /* Value for N. */ - int x; - - if (!lex_force_int (lexer)) + if (!lex_force_int_range (lexer, "N OF CASES", 1, LONG_MAX)) return CMD_FAILURE; - x = lex_integer (lexer); + long n = lex_integer (lexer); lex_get (lexer); if (!lex_match_id (lexer, "ESTIMATED")) - dict_set_case_limit (dataset_dict (ds), x); + dict_set_case_limit (dataset_dict (ds), n); return CMD_SUCCESS; } @@ -515,7 +547,7 @@ cmd_erase (struct lexer *lexer, struct dataset *ds UNUSED) if (settings_get_safer_mode ()) { - msg (SE, _("This command not allowed when the SAFER option is set.")); + msg (SE, _("This command not allowed when the %s option is set."), "SAFER"); return CMD_FAILURE; }