X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Fcommand.c;h=a465aa0dad7c7f4692ec465782990f3592e9c7e3;hb=8c8b1ba6eadf4cf533b5cce513a21b48ae06c402;hp=7b903ab1a29f64a916d7f3891b960a2c3b6c4952;hpb=7a2039fb1ebfd48013ab259b28091e74e7f50588;p=pspp-builds.git diff --git a/src/language/command.c b/src/language/command.c index 7b903ab1..a465aa0d 100644 --- a/src/language/command.c +++ b/src/language/command.c @@ -32,7 +32,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -96,7 +98,8 @@ enum flags { F_ENHANCED = 0x10, /* Allowed only in enhanced syntax mode. */ F_TESTING = 0x20, /* Allowed only in testing mode. */ - F_KEEP_FINAL_TOKEN = 0x40 /* Don't skip final token in command name. */ + F_KEEP_FINAL_TOKEN = 0x40,/* Don't skip final token in command name. */ + F_ABBREV = 0x80 /* Not a candidate for name completion. */ }; /* A single command. */ @@ -120,8 +123,10 @@ static const struct command commands[] = static const size_t command_cnt = sizeof commands / sizeof *commands; -static bool verify_valid_command (const struct command *, enum cmd_state); +static bool in_correct_state (const struct command *, enum cmd_state); +static bool report_state_mismatch (const struct command *, enum cmd_state); static const struct command *find_command (const char *name); +static void set_completion_state (enum cmd_state); /* Command parser. */ @@ -156,9 +161,18 @@ do_parse_command (enum cmd_state state) const struct command *command; enum cmd_result result; - /* Null commands can result from extra empty lines. */ - if (token == '.') - return CMD_SUCCESS; + /* Read the command's first token. */ + getl_set_prompt_style (GETL_PROMPT_FIRST); + set_completion_state (state); + lex_get (); + if (token == T_STOP) + return CMD_EOF; + else if (token == '.') + { + /* Null commands can result from extra empty lines. */ + return CMD_SUCCESS; + } + getl_set_prompt_style (GETL_PROMPT_LATER); /* Parse the command name. */ command = parse_command_name (); @@ -177,8 +191,11 @@ do_parse_command (enum cmd_state state) command->name); return CMD_FAILURE; } - else if (!verify_valid_command (command, state)) - return CMD_FAILURE; + else if (!in_correct_state (command, state)) + { + report_state_mismatch (command, state); + return CMD_FAILURE; + } /* Execute command. */ msg_set_command_name (command->name); @@ -405,7 +422,7 @@ find_command (const char *name) for (cmd = commands; cmd < commands + command_cnt; cmd++) if (!strcmp (cmd->name, name)) return cmd; - abort (); + NOT_REACHED (); } /* Frees the WORD_CNT words in WORDS. */ @@ -430,15 +447,15 @@ unknown_command_error (char *const words[], size_t word_cnt) struct string s; size_t i; - ds_init (&s); + ds_init_empty (&s); for (i = 0; i < word_cnt; i++) { if (i != 0) - ds_putc (&s, ' '); - ds_puts (&s, words[i]); + ds_put_char (&s, ' '); + ds_put_cstr (&s, words[i]); } - msg (SE, _("Unknown command %s."), ds_c_str (&s)); + msg (SE, _("Unknown command %s."), ds_cstr (&s)); ds_destroy (&s); } @@ -467,7 +484,7 @@ parse_command_name (void) assert (word_cnt < sizeof words / sizeof *words); if (token == T_ID) { - words[word_cnt] = xstrdup (ds_c_str (&tokstr)); + words[word_cnt] = ds_xstrdup (&tokstr); str_uppercase (words[word_cnt]); } else if (token == '-') @@ -539,19 +556,23 @@ parse_command_name (void) } /* Returns true if COMMAND is allowed in STATE, - false otherwise. - If COMMAND is not allowed, emits an appropriate error - message. */ + false otherwise. */ static bool -verify_valid_command (const struct command *command, enum cmd_state state) +in_correct_state (const struct command *command, enum cmd_state state) { - if ((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 true; + 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)); +} +/* Emits an appropriate error message for trying to invoke + COMMAND in STATE. */ +static bool +report_state_mismatch (const struct command *command, enum cmd_state state) +{ + assert (!in_correct_state (command, state)); if (state == CMD_STATE_INITIAL || state == CMD_STATE_DATA) { const char *allowed[3]; @@ -575,7 +596,7 @@ verify_valid_command (const struct command *command, enum cmd_state state) else if (allowed_cnt == 3) s = xasprintf (_("%s, %s, or %s"), allowed[0], allowed[1], allowed[2]); else - abort (); + NOT_REACHED (); msg (SE, _("%s is allowed only %s."), command->name, s); @@ -589,51 +610,37 @@ verify_valid_command (const struct command *command, enum cmd_state state) return false; } -/* Readline command name completion. */ +/* Command name completion. */ -#if HAVE_READLINE -static char *command_generator (const char *text, int state); - -/* Returns a set of completions for TEXT. - This is of the proper form for assigning to - rl_attempted_completion_function. */ -char ** -pspp_attempted_completion_function (const char *text, - int start, int end UNUSED) +static enum cmd_state completion_state = CMD_STATE_INITIAL; + +static void +set_completion_state (enum cmd_state state) { - if (start == 0) - { - /* Complete command name at start of line. */ - return rl_completion_matches (text, command_generator); - } - else - { - /* Otherwise don't do any completion. */ - rl_attempted_completion_over = 1; - return NULL; - } + completion_state = state; } -/* If STATE is 0, returns the first command name matching TEXT. - Otherwise, returns the next command name matching TEXT. - Returns a null pointer when no matches are left. */ -static char * -command_generator (const char *text, int state) +/* Returns the next possible completion of a command name that + begins with PREFIX, in the current command state, or a null + pointer if no completions remain. + Before calling the first time, set *CMD to a null pointer. */ +const char * +cmd_complete (const char *prefix, const struct command **cmd) { - static const struct command *cmd; - - if (!state) - cmd = commands; - - for (; cmd < commands + command_cnt; cmd++) - if (!memcasecmp (cmd->name, text, strlen (text)) - && (!(cmd->flags & F_TESTING) || get_testing_mode ()) - && (!(cmd->flags & F_ENHANCED) || get_syntax () == ENHANCED)) - return xstrdup (cmd++->name); + if (*cmd == NULL) + *cmd = commands; + + for (; *cmd < commands + command_cnt; (*cmd)++) + if (!memcasecmp ((*cmd)->name, prefix, strlen (prefix)) + && (!((*cmd)->flags & F_TESTING) || get_testing_mode ()) + && (!((*cmd)->flags & F_ENHANCED) || get_syntax () == ENHANCED) + && !((*cmd)->flags & F_ABBREV) + && ((*cmd)->function != NULL) + && in_correct_state (*cmd, completion_state)) + return (*cmd)++->name; return NULL; } -#endif /* HAVE_READLINE */ /* Simple commands. */ @@ -686,10 +693,10 @@ cmd_erase (void) if (!lex_force_string ()) return CMD_FAILURE; - if (remove (ds_c_str (&tokstr)) == -1) + if (remove (ds_cstr (&tokstr)) == -1) { msg (SW, _("Error removing `%s': %s."), - ds_c_str (&tokstr), strerror (errno)); + ds_cstr (&tokstr), strerror (errno)); return CMD_FAILURE; } @@ -767,7 +774,7 @@ run_command (void) lex_get (); if (!lex_force_string ()) return CMD_FAILURE; - cmd = ds_c_str (&tokstr); + cmd = ds_cstr (&tokstr); string = 1; } else