1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2009, 2010 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "language/command.h"
26 #include "data/casereader.h"
27 #include "data/dictionary.h"
28 #include "data/procedure.h"
29 #include "data/settings.h"
30 #include "data/variable.h"
31 #include "language/lexer/command-name.h"
32 #include "language/lexer/lexer.h"
33 #include "language/prompt.h"
34 #include "libpspp/assertion.h"
35 #include "libpspp/compiler.h"
36 #include "libpspp/message.h"
37 #include "libpspp/str.h"
38 #include "libpspp/getl.h"
39 #include "output/text-item.h"
45 #define _(msgid) gettext (msgid)
46 #define N_(msgid) msgid
48 /* Returns true if RESULT is a valid "enum cmd_result",
51 cmd_result_is_valid (enum cmd_result result)
53 return (result == CMD_SUCCESS || result == CMD_EOF || result == CMD_FINISH
54 || (result >= CMD_PRIVATE_FIRST && result <= CMD_PRIVATE_LAST)
55 || result == CMD_FAILURE || result == CMD_NOT_IMPLEMENTED
56 || result == CMD_CASCADING_FAILURE);
59 /* Returns true if RESULT indicates success,
62 cmd_result_is_success (enum cmd_result result)
64 assert (cmd_result_is_valid (result));
68 /* Returns true if RESULT indicates failure,
71 cmd_result_is_failure (enum cmd_result result)
73 assert (cmd_result_is_valid (result));
77 /* Command processing states. */
80 S_INITIAL = 0x01, /* Allowed before active file defined. */
81 S_DATA = 0x02, /* Allowed after active file defined. */
82 S_INPUT_PROGRAM = 0x04, /* Allowed in INPUT PROGRAM. */
83 S_FILE_TYPE = 0x08, /* Allowed in FILE TYPE. */
84 S_ANY = 0x0f /* Allowed anywhere. */
87 /* Other command requirements. */
90 F_ENHANCED = 0x10, /* Allowed only in enhanced syntax mode. */
91 F_TESTING = 0x20, /* Allowed only in testing mode. */
92 F_KEEP_FINAL_TOKEN = 0x40,/* Don't skip final token in command name. */
93 F_ABBREV = 0x80 /* Not a candidate for name completion. */
96 /* A single command. */
99 enum states states; /* States in which command is allowed. */
100 enum flags flags; /* Other command requirements. */
101 const char *name; /* Command name. */
102 int (*function) (struct lexer *, struct dataset *); /* Function to call. */
105 /* Define the command array. */
106 #define DEF_CMD(STATES, FLAGS, NAME, FUNCTION) {STATES, FLAGS, NAME, FUNCTION},
107 #define UNIMPL_CMD(NAME, DESCRIPTION) {S_ANY, 0, NAME, NULL},
108 static const struct command commands[] =
110 #include "command.def"
115 static const size_t command_cnt = sizeof commands / sizeof *commands;
117 static bool in_correct_state (const struct command *, enum cmd_state);
118 static bool report_state_mismatch (const struct command *, enum cmd_state);
119 static void set_completion_state (enum cmd_state);
121 /* Command parser. */
123 static const struct command *parse_command_name (struct lexer *lexer);
124 static enum cmd_result do_parse_command (struct lexer *, struct dataset *, enum cmd_state);
126 /* Parses an entire command, from command name to terminating
127 dot. On failure, skips to the terminating dot.
128 Returns the command's success or failure result. */
130 cmd_parse_in_state (struct lexer *lexer, struct dataset *ds,
131 enum cmd_state state)
135 result = do_parse_command (lexer, ds, state);
137 assert (!proc_is_open (ds));
138 unset_cmd_algorithm ();
139 dict_clear_aux (dataset_dict (ds));
140 if (!dataset_end_of_command (ds))
141 result = CMD_CASCADING_FAILURE;
147 cmd_parse (struct lexer *lexer, struct dataset *ds)
149 const struct dictionary *dict = dataset_dict (ds);
150 return cmd_parse_in_state (lexer, ds,
151 proc_has_active_file (ds) &&
152 dict_get_var_cnt (dict) > 0 ?
153 CMD_STATE_DATA : CMD_STATE_INITIAL);
157 /* Parses an entire command, from command name to terminating
159 static enum cmd_result
160 do_parse_command (struct lexer *lexer,
161 struct dataset *ds, enum cmd_state state)
163 const struct command *command = NULL;
164 enum cmd_result result;
167 /* Read the command's first token. */
168 prompt_set_style (PROMPT_FIRST);
169 set_completion_state (state);
171 if (lex_token (lexer) == T_STOP)
176 else if (lex_token (lexer) == T_ENDCMD)
178 /* Null commands can result from extra empty lines. */
179 result = CMD_SUCCESS;
183 prompt_set_style (PROMPT_LATER);
185 /* Parse the command name. */
186 command = parse_command_name (lexer);
189 result = CMD_FAILURE;
192 text_item_submit (text_item_create (TEXT_ITEM_COMMAND_OPEN, command->name));
195 if (command->function == NULL)
197 msg (SE, _("%s is not yet implemented."), command->name);
198 result = CMD_NOT_IMPLEMENTED;
200 else if ((command->flags & F_TESTING) && !settings_get_testing_mode ())
202 msg (SE, _("%s may be used only in testing mode."), command->name);
203 result = CMD_FAILURE;
205 else if ((command->flags & F_ENHANCED) && settings_get_syntax () != ENHANCED)
207 msg (SE, _("%s may be used only in enhanced syntax mode."),
209 result = CMD_FAILURE;
211 else if (!in_correct_state (command, state))
213 report_state_mismatch (command, state);
214 result = CMD_FAILURE;
218 /* Execute command. */
219 result = command->function (lexer, ds);
222 assert (cmd_result_is_valid (result));
225 if (cmd_result_is_failure (result))
227 lex_discard_rest_of_command (lexer);
228 if (source_stream_current_error_mode (
229 lex_get_source_stream (lexer)) == ERRMODE_STOP )
231 msg (MW, _("Error encountered while ERROR=STOP is effective."));
232 result = CMD_CASCADING_FAILURE;
237 text_item_submit (text_item_create (TEXT_ITEM_COMMAND_CLOSE,
244 find_best_match (struct substring s, const struct command **matchp)
246 const struct command *cmd;
247 struct command_matcher cm;
250 command_matcher_init (&cm, s);
251 for (cmd = commands; cmd < &commands[command_cnt]; cmd++)
252 command_matcher_add (&cm, ss_cstr (cmd->name), CONST_CAST (void *, cmd));
254 *matchp = command_matcher_get_match (&cm);
255 missing_words = command_matcher_get_missing_words (&cm);
257 command_matcher_destroy (&cm);
259 return missing_words;
262 /* Parse the command name and return a pointer to the corresponding
263 struct command if successful.
264 If not successful, return a null pointer. */
265 static const struct command *
266 parse_command_name (struct lexer *lexer)
268 const struct command *command;
272 if (lex_token (lexer) == T_EXP
273 || lex_token (lexer) == T_ASTERISK
274 || lex_token (lexer) == T_LBRACK)
276 static const struct command c = { S_ANY, 0, "COMMENT", cmd_comment };
285 if (lex_token (lexer) == T_DASH)
286 ds_put_byte (&s, '-');
287 else if (lex_token (lexer) == T_ID)
289 if (!ds_is_empty (&s) && ds_last (&s) != '-')
290 ds_put_byte (&s, ' ');
291 ds_put_cstr (&s, lex_tokcstr (lexer));
293 else if (lex_is_integer (lexer) && lex_integer (lexer) >= 0)
295 if (!ds_is_empty (&s) && ds_last (&s) != '-')
296 ds_put_byte (&s, ' ');
297 ds_put_format (&s, "%ld", lex_integer (lexer));
302 missing_words = find_best_match (ds_ss (&s), &command);
303 if (missing_words <= 0)
309 if (command == NULL && missing_words > 0)
311 ds_put_cstr (&s, " .");
312 missing_words = find_best_match (ds_ss (&s), &command);
313 ds_truncate (&s, ds_length (&s) - 2);
318 if (ds_is_empty (&s))
319 lex_error (lexer, _("expecting command name"));
321 msg (SE, _("Unknown command `%s'."), ds_cstr (&s));
323 else if (missing_words == 0)
325 if (!(command->flags & F_KEEP_FINAL_TOKEN))
328 else if (missing_words < 0)
330 assert (missing_words == -1);
331 assert (!(command->flags & F_KEEP_FINAL_TOKEN));
338 /* Returns true if COMMAND is allowed in STATE,
341 in_correct_state (const struct command *command, enum cmd_state state)
343 return ((state == CMD_STATE_INITIAL && command->states & S_INITIAL)
344 || (state == CMD_STATE_DATA && command->states & S_DATA)
345 || (state == CMD_STATE_INPUT_PROGRAM
346 && command->states & S_INPUT_PROGRAM)
347 || (state == CMD_STATE_FILE_TYPE && command->states & S_FILE_TYPE));
350 /* Emits an appropriate error message for trying to invoke
353 report_state_mismatch (const struct command *command, enum cmd_state state)
355 assert (!in_correct_state (command, state));
356 if (state == CMD_STATE_INITIAL || state == CMD_STATE_DATA)
358 switch (command->states)
360 /* One allowed state. */
362 msg (SE, _("%s is allowed only before the active file has "
363 "been defined."), command->name);
366 msg (SE, _("%s is allowed only after the active file has "
367 "been defined."), command->name);
369 case S_INPUT_PROGRAM:
370 msg (SE, _("%s is allowed only inside INPUT PROGRAM."),
374 msg (SE, _("%s is allowed only inside FILE TYPE."), command->name);
377 /* Two allowed states. */
378 case S_INITIAL | S_DATA:
380 case S_INITIAL | S_INPUT_PROGRAM:
381 msg (SE, _("%s is allowed only before the active file has "
382 "been defined or inside INPUT PROGRAM."), command->name);
384 case S_INITIAL | S_FILE_TYPE:
385 msg (SE, _("%s is allowed only before the active file has "
386 "been defined or inside FILE TYPE."), command->name);
388 case S_DATA | S_INPUT_PROGRAM:
389 msg (SE, _("%s is allowed only after the active file has "
390 "been defined or inside INPUT PROGRAM."), command->name);
392 case S_DATA | S_FILE_TYPE:
393 msg (SE, _("%s is allowed only after the active file has "
394 "been defined or inside FILE TYPE."), command->name);
396 case S_INPUT_PROGRAM | S_FILE_TYPE:
397 msg (SE, _("%s is allowed only inside INPUT PROGRAM "
398 "or inside FILE TYPE."), command->name);
401 /* Three allowed states. */
402 case S_DATA | S_INPUT_PROGRAM | S_FILE_TYPE:
403 msg (SE, _("%s is allowed only after the active file has "
404 "been defined, inside INPUT PROGRAM, or inside "
405 "FILE TYPE."), command->name);
407 case S_INITIAL | S_INPUT_PROGRAM | S_FILE_TYPE:
408 msg (SE, _("%s is allowed only before the active file has "
409 "been defined, inside INPUT PROGRAM, or inside "
410 "FILE TYPE."), command->name);
412 case S_INITIAL | S_DATA | S_FILE_TYPE:
414 case S_INITIAL | S_DATA | S_INPUT_PROGRAM:
417 /* Four allowed states. */
418 case S_INITIAL | S_DATA | S_INPUT_PROGRAM | S_FILE_TYPE:
425 else if (state == CMD_STATE_INPUT_PROGRAM)
426 msg (SE, _("%s is not allowed inside %s."), command->name, "INPUT PROGRAM" );
427 else if (state == CMD_STATE_FILE_TYPE)
428 msg (SE, _("%s is not allowed inside %s."), command->name, "FILE TYPE");
433 /* Command name completion. */
435 static enum cmd_state completion_state = CMD_STATE_INITIAL;
438 set_completion_state (enum cmd_state state)
440 completion_state = state;
443 /* Returns the next possible completion of a command name that
444 begins with PREFIX, in the current command state, or a null
445 pointer if no completions remain.
446 Before calling the first time, set *CMD to a null pointer. */
448 cmd_complete (const char *prefix, const struct command **cmd)
453 for (; *cmd < commands + command_cnt; (*cmd)++)
454 if (!memcasecmp ((*cmd)->name, prefix, strlen (prefix))
455 && (!((*cmd)->flags & F_TESTING) || settings_get_testing_mode ())
456 && (!((*cmd)->flags & F_ENHANCED) || settings_get_syntax () == ENHANCED)
457 && !((*cmd)->flags & F_ABBREV)
458 && ((*cmd)->function != NULL)
459 && in_correct_state (*cmd, completion_state))
460 return (*cmd)++->name;
465 /* Simple commands. */
467 /* Parse and execute FINISH command. */
469 cmd_finish (struct lexer *lexer UNUSED, struct dataset *ds UNUSED)
474 /* Parses the N command. */
476 cmd_n_of_cases (struct lexer *lexer, struct dataset *ds)
481 if (!lex_force_int (lexer))
483 x = lex_integer (lexer);
485 if (!lex_match_id (lexer, "ESTIMATED"))
486 dict_set_case_limit (dataset_dict (ds), x);
488 return lex_end_of_command (lexer);
491 /* Parses, performs the EXECUTE procedure. */
493 cmd_execute (struct lexer *lexer, struct dataset *ds)
495 bool ok = casereader_destroy (proc_open (ds));
496 if (!proc_commit (ds) || !ok)
497 return CMD_CASCADING_FAILURE;
498 return lex_end_of_command (lexer);
501 /* Parses, performs the ERASE command. */
503 cmd_erase (struct lexer *lexer, struct dataset *ds UNUSED)
505 if (settings_get_safer_mode ())
507 msg (SE, _("This command not allowed when the SAFER option is set."));
511 if (!lex_force_match_id (lexer, "FILE"))
513 lex_match (lexer, T_EQUALS);
514 if (!lex_force_string (lexer))
517 if (remove (lex_tokcstr (lexer)) == -1)
519 msg (SW, _("Error removing `%s': %s."),
520 lex_tokcstr (lexer), strerror (errno));
527 /* Parses, performs the NEW FILE command. */
529 cmd_new_file (struct lexer *lexer, struct dataset *ds)
531 proc_discard_active_file (ds);
533 return lex_end_of_command (lexer);
536 /* Parses a comment. */
538 cmd_comment (struct lexer *lexer, struct dataset *ds UNUSED)
540 lex_skip_comment (lexer);