1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3 Written by Ben Pfaff <blp@gnu.org>.
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
28 #include "dictionary.h"
49 /* Global variables. */
51 /* A STATE_* constant giving the current program state. */
54 /* The name of the procedure currently executing, if any. */
57 /* Static variables. */
59 /* A single command. */
62 const char *name; /* Command name. */
63 int transition[4]; /* Transitions to make from each state. */
64 int (*func) (void); /* Function to call. */
65 int skip_entire_name; /* If zero, we don't skip the
66 final token in the command name. */
67 short debug; /* Set if this cmd available only in test mode*/
70 /* Define the command array. */
71 #define DEFCMD(NAME, T1, T2, T3, T4, FUNC) \
72 {NAME, {T1, T2, T3, T4}, FUNC, 1, 0},
73 #define DBGCMD(NAME, T1, T2, T3, T4, FUNC) \
74 {NAME, {T1, T2, T3, T4}, FUNC, 1, 1},
75 #define SPCCMD(NAME, T1, T2, T3, T4, FUNC) \
76 {NAME, {T1, T2, T3, T4}, FUNC, 0, 0},
77 #define UNIMPL(NAME, T1, T2, T3, T4, DESC) \
78 {NAME, {T1, T2, T3, T4}, NULL, 1, 0},
79 static const struct command commands[] =
81 #include "command.def"
88 /* Complete the line using the name of a command,
89 * based upon the current prg_state
92 pspp_completion_function (const char *text, int state)
95 const struct command *cmd = 0;
99 if ( state + skip >= sizeof(commands)/ sizeof(struct command))
105 cmd = &commands[state + skip];
107 if ( cmd->transition[pgm_state] == STATE_ERROR || ( cmd->debug && ! test_mode ) )
113 if ( text == 0 || 0 == strncasecmp (cmd->name, text, strlen(text)))
122 return xstrdup(cmd->name);
128 #define COMMAND_CNT (sizeof commands / sizeof *commands)
130 /* Command parser. */
132 static const struct command *parse_command_name (void);
134 /* Determines whether command C is appropriate to call in this
135 part of a FILE TYPE structure. */
137 FILE_TYPE_okay (const struct command *c UNUSED)
142 if (c->func != cmd_record_type
143 && c->func != cmd_data_list
144 && c->func != cmd_repeating_data
145 && c->func != cmd_end_file_type)
146 msg (SE, _("%s not allowed inside FILE TYPE/END FILE TYPE."), c->name);
148 else if (c->func == cmd_repeating_data && fty.type == FTY_GROUPED)
149 msg (SE, _("%s not allowed inside FILE TYPE GROUPED/END FILE TYPE."),
151 else if (!fty.had_rec_type && c->func != cmd_record_type)
152 msg (SE, _("RECORD TYPE must be the first command inside a "
153 "FILE TYPE structure."));
157 if (c->func == cmd_record_type)
158 fty.had_rec_type = 1;
168 /* Parses an entire PSPP command. This includes everything from the
169 command name to the terminating dot. Does most of its work by
170 passing it off to the respective command dispatchers. Only called
171 by parse() in main.c. */
175 const struct command *cp; /* Iterator used to find the proper command. */
178 /* The generic alloca package performs garbage collection when it is
179 called with an argument of zero. */
181 #endif /* C_ALLOCA */
183 /* Null commands can result from extra empty lines. */
187 /* Parse comments. */
188 if ((token == T_ID && !strcasecmp (tokid, "COMMENT"))
189 || token == T_EXP || token == '*' || token == '[')
195 /* Otherwise the line must begin with a command name, which is
196 always an ID token. */
199 lex_error (_("expecting command name"));
203 /* Parse the command name. */
204 cp = parse_command_name ();
207 if (cp->func == NULL)
209 msg (SE, _("%s is not yet implemented."), cp->name);
210 while (token && token != '.')
215 /* If we're in a FILE TYPE structure, only certain commands can be
217 if (pgm_state == STATE_INPUT
218 && case_source_is_class (vfm_source, &file_type_source_class)
219 && !FILE_TYPE_okay (cp))
222 /* Certain state transitions are not allowed. Check for these. */
223 assert (pgm_state >= 0 && pgm_state < STATE_ERROR);
224 if (cp->transition[pgm_state] == STATE_ERROR)
226 static const char *state_name[4] =
228 N_("%s is not allowed (1) before a command to specify the "
229 "input program, such as DATA LIST, (2) between FILE TYPE "
230 "and END FILE TYPE, (3) between INPUT PROGRAM and END "
232 N_("%s is not allowed within an input program."),
233 N_("%s is only allowed within an input program."),
234 N_("%s is only allowed within an input program."),
237 msg (SE, gettext (state_name[pgm_state]), cp->name);
241 /* The structured output manager numbers all its tables. Increment
242 the major table number for each separate procedure. */
248 /* Call the command dispatcher. Save and restore the name of
249 the current command around this call. */
251 const char *prev_proc;
253 prev_proc = cur_proc;
255 result = cp->func ();
256 cur_proc = prev_proc;
259 /* Perform the state transition if the command completed
260 successfully (at least in part). */
261 if (result != CMD_FAILURE)
263 pgm_state = cp->transition[pgm_state];
265 if (pgm_state == STATE_ERROR)
267 discard_variables ();
268 pgm_state = STATE_INIT;
272 /* Pass the command's success value up to the caller. */
278 match_strings (const char *a, size_t a_len,
279 const char *b, size_t b_len)
281 size_t match_len = 0;
283 while (a_len > 0 && b_len > 0)
285 /* Mismatch always returns zero. */
286 if (toupper ((unsigned char) *a++) != toupper ((unsigned char) *b++))
298 /* Returns the first character in the first word in STRING,
299 storing the word's length in *WORD_LEN. If no words remain,
300 returns a null pointer and stores 0 in *WORD_LEN. Words are
301 sequences of alphanumeric characters or single
302 non-alphanumeric characters. Words are delimited by
305 find_word (const char *string, size_t *word_len)
307 /* Skip whitespace and asterisks. */
308 while (isspace (*string))
318 /* Special one-character word? */
319 if (!isalnum ((unsigned char) *string))
325 /* Alphanumeric word. */
327 while (isalnum ((unsigned char) string[*word_len]))
333 /* Returns nonzero if strings A and B can be confused based on
334 their first three letters. */
336 conflicting_3char_prefixes (const char *a, const char *b)
338 size_t aw_len, bw_len;
341 aw = find_word (a, &aw_len);
342 bw = find_word (b, &bw_len);
343 assert (aw != NULL && bw != NULL);
345 /* Words that are the same don't conflict. */
346 if (aw_len == bw_len && !mm_case_compare (aw, bw, aw_len))
349 /* Words that are otherwise the same in the first three letters
351 return ((aw_len > 3 && bw_len > 3)
352 || (aw_len == 3 && bw_len > 3)
353 || (bw_len == 3 && aw_len > 3)) && !mm_case_compare (aw, bw, 3);
356 /* Returns nonzero if CMD can be confused with another command
357 based on the first three letters of its first word. */
359 conflicting_3char_prefix_command (const struct command *cmd)
361 assert (cmd >= commands && cmd < commands + COMMAND_CNT);
363 return ((cmd > commands
364 && conflicting_3char_prefixes (cmd[-1].name, cmd[0].name))
365 || (cmd < commands + COMMAND_CNT
366 && conflicting_3char_prefixes (cmd[0].name, cmd[1].name)));
369 /* Ways that a set of words can match a command name. */
372 MISMATCH, /* Not a match. */
373 PARTIAL_MATCH, /* The words begin the command name. */
374 COMPLETE_MATCH /* The words are the command name. */
377 /* Figures out how well the WORD_CNT words in WORDS match CMD,
378 and returns the appropriate enum value. If WORDS are a
379 partial match for CMD and the next word in CMD is a dash, then
380 *DASH_POSSIBLE is set to 1 if DASH_POSSIBLE is non-null;
381 otherwise, *DASH_POSSIBLE is unchanged. */
382 static enum command_match
383 cmd_match_words (const struct command *cmd,
384 char *const words[], size_t word_cnt,
391 for (word = find_word (cmd->name, &word_len), word_idx = 0;
392 word != NULL && word_idx < word_cnt;
393 word = find_word (word + word_len, &word_len), word_idx++)
394 if (word_len != strlen (words[word_idx])
395 || mm_case_compare (word, words[word_idx], word_len))
397 size_t match_chars = match_strings (word, word_len,
399 strlen (words[word_idx]));
400 if (match_chars == 0)
405 else if (match_chars == 1 || match_chars == 2)
407 /* One- and two-character abbreviations are not
411 else if (match_chars == 3)
413 /* Three-character abbreviations are acceptable
414 in the first word of a command if there are
415 no name conflicts. They are always
416 acceptable after the first word. */
417 if (word_idx == 0 && conflicting_3char_prefix_command (cmd))
420 else /* match_chars > 3 */
422 /* Four-character and longer abbreviations are
423 always acceptable. */
427 if (word == NULL && word_idx == word_cnt)
429 /* cmd->name = "FOO BAR", words[] = {"FOO", "BAR"}. */
430 return COMPLETE_MATCH;
432 else if (word == NULL)
434 /* cmd->name = "FOO BAR", words[] = {"FOO", "BAR", "BAZ"}. */
439 /* cmd->name = "FOO BAR BAZ", words[] = {"FOO", "BAR"}. */
440 if (word[0] == '-' && dash_possible != NULL)
442 return PARTIAL_MATCH;
446 /* Returns the number of commands for which the WORD_CNT words in
447 WORDS are a partial or complete match. If some partial match
448 has a dash as the next word, then *DASH_POSSIBLE is set to 1,
449 otherwise it is set to 0. */
451 count_matching_commands (char *const words[], size_t word_cnt,
454 const struct command *cmd;
459 for (cmd = commands; cmd < commands + COMMAND_CNT; cmd++)
460 if (cmd_match_words (cmd, words, word_cnt, dash_possible) != MISMATCH)
463 return cmd_match_count;
466 /* Returns the command for which the WORD_CNT words in WORDS are
467 a complete match. Returns a null pointer if no such command
469 static const struct command *
470 get_complete_match (char *const words[], size_t word_cnt)
472 const struct command *cmd;
474 for (cmd = commands; cmd < commands + COMMAND_CNT; cmd++)
475 if (cmd_match_words (cmd, words, word_cnt, NULL) == COMPLETE_MATCH)
481 /* Frees the WORD_CNT words in WORDS. */
483 free_words (char *words[], size_t word_cnt)
487 for (idx = 0; idx < word_cnt; idx++)
491 /* Flags an error that the command whose name is given by the
492 WORD_CNT words in WORDS is unknown. */
494 unknown_command_error (char *const words[], size_t word_cnt)
501 for (idx = 0; idx < word_cnt; idx++)
502 words_len += strlen (words[idx]);
504 cp = name = xmalloc (words_len + word_cnt + 16);
505 for (idx = 0; idx < word_cnt; idx++)
509 cp = stpcpy (cp, words[idx]);
513 msg (SE, _("Unknown command %s."), name);
519 /* Parse the command name and return a pointer to the corresponding
520 struct command if successful.
521 If not successful, return a null pointer. */
522 static const struct command *
523 parse_command_name (void)
527 int complete_word_cnt;
531 word_cnt = complete_word_cnt = 0;
532 while (token == T_ID || (dash_possible && token == '-'))
536 assert (word_cnt < sizeof words / sizeof *words);
538 words[word_cnt++] = xstrdup (ds_c_str (&tokstr));
540 words[word_cnt++] = xstrdup ("-");
542 cmd_match_cnt = count_matching_commands (words, word_cnt,
544 if (cmd_match_cnt == 0)
546 else if (cmd_match_cnt == 1)
548 const struct command *command = get_complete_match (words, word_cnt);
551 if (command->skip_entire_name)
553 if ( command->debug & !test_mode )
555 free_words (words, word_cnt);
559 else /* cmd_match_cnt > 1 */
561 /* Do we have a complete command name so far? */
562 if (get_complete_match (words, word_cnt) != NULL)
563 complete_word_cnt = word_cnt;
568 /* If we saw a complete command name earlier, drop back to
570 if (complete_word_cnt)
572 int pushback_word_cnt;
573 const struct command *command;
575 /* Get the command. */
576 command = get_complete_match (words, complete_word_cnt);
577 assert (command != NULL);
579 /* Figure out how many words we want to keep.
580 We normally want to swallow the entire command. */
581 pushback_word_cnt = complete_word_cnt + 1;
582 if (!command->skip_entire_name)
585 /* FIXME: We only support one-token pushback. */
586 assert (pushback_word_cnt + 1 >= word_cnt);
588 while (word_cnt > pushback_word_cnt)
591 if (strcmp (words[word_cnt], "-"))
592 lex_put_back_id (words[word_cnt]);
595 free (words[word_cnt]);
598 if ( command->debug && !test_mode )
601 free_words (words, word_cnt);
606 unknown_command_error (words, word_cnt);
607 free_words (words, word_cnt);
611 /* Simple commands. */
613 /* Parse and execute EXIT command. */
617 if (getl_reading_script)
619 msg (SE, _("This command is not accepted in a syntax file. "
620 "Instead, use FINISH to terminate a syntax file."));
629 /* Parse and execute FINISH command. */
633 /* Do not check for `.'
634 Do not fetch any extra tokens. */
635 if (getl_interactive)
637 msg (SM, _("This command is not executed "
638 "in interactive mode. Instead, PSPP drops "
639 "down to the command prompt. Use EXIT if you really want "
649 /* Parses the N command. */
651 cmd_n_of_cases (void)
656 if (!lex_force_int ())
660 if (!lex_match_id ("ESTIMATED"))
661 dict_set_case_limit (default_dict, x);
663 return lex_end_of_command ();
666 /* Parses, performs the EXECUTE procedure. */
670 procedure (NULL, NULL);
671 return lex_end_of_command ();
674 /* Parses, performs the ERASE command. */
680 msg (SE, _("This command not allowed when the SAFER option is set."));
684 if (!lex_force_match_id ("FILE"))
687 if (!lex_force_string ())
690 if (remove (ds_c_str (&tokstr)) == -1)
692 msg (SW, _("Error removing `%s': %s."),
693 ds_c_str (&tokstr), strerror (errno));
701 /* Spawn a shell process. */
712 const char *shell_fn;
718 for (i = 3; i < 20; i++)
722 shell_fn = getenv ("SHELL");
723 if (shell_fn == NULL)
724 shell_fn = "/bin/sh";
727 const char *cp = strrchr (shell_fn, '/');
728 cp = cp ? &cp[1] : shell_fn;
729 shell_process = local_alloc (strlen (cp) + 8);
730 strcpy (shell_process, "-");
731 strcat (shell_process, cp);
732 if (strcmp (cp, "sh"))
733 shell_process[0] = '+';
736 execl (shell_fn, shell_process, NULL);
742 msg (SE, _("Couldn't fork: %s."), strerror (errno));
747 while (wait (NULL) != pid)
754 /* Parses the HOST command argument and executes the specified
755 command. Returns a suitable command return code. */
762 /* Handle either a string argument or a full-line argument. */
764 int c = lex_look_ahead ();
766 if (c == '\'' || c == '"')
769 if (!lex_force_string ())
771 cmd = ds_c_str (&tokstr);
776 cmd = lex_rest_of_line (NULL);
782 /* Execute the command. */
783 if (system (cmd) == -1)
784 msg (SE, _("Error executing command: %s."), strerror (errno));
786 /* Finish parsing. */
793 lex_error (_("expecting end of command"));
794 return CMD_TRAILING_GARBAGE;
803 /* Parses, performs the HOST command. */
811 msg (SE, _("This command not allowed when the SAFER option is set."));
816 /* Figure out whether to invoke an interactive shell or to execute a
817 single shell command. */
818 if (lex_look_ahead () == '.')
821 code = shell () ? CMD_PART_SUCCESS_MAYBE : CMD_SUCCESS;
824 code = run_command ();
826 /* Make sure that the system has a command interpreter, then run a
828 if (system (NULL) != 0)
829 code = run_command ();
832 msg (SE, _("No operating system support for this command."));
837 return code ? CMD_FAILURE : CMD_SUCCESS;
840 /* Parses, performs the NEW FILE command. */
844 discard_variables ();
846 return lex_end_of_command ();
849 /* Parses, performs the CLEAR TRANSFORMATIONS command. */
851 cmd_clear_transformations (void)
853 if (getl_reading_script)
855 msg (SW, _("This command is not valid in a syntax file."));
859 cancel_transformations ();
860 /* FIXME: what about variables created by transformations?
861 They need to be properly initialized. */