X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fcommand.c;h=b112d730b5e5a93cfbf4e36c4d2acc3f444ce3ed;hb=73dab896d406ce96df17d78204c84c5a5c477075;hp=696547ff73297a326dd508ce64f4d46ef0fac792;hpb=1ab3bf1b148d31aad66735f52f9ff72af8769cd0;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/command.c b/gdb/command.c index 696547ff73..b112d730b5 100644 --- a/gdb/command.c +++ b/gdb/command.c @@ -15,7 +15,6 @@ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include "defs.h" #include "gdbcmd.h" #include "symtab.h" @@ -32,7 +31,7 @@ static void show_user PARAMS ((char *, int)); static void -show_user_1 PARAMS ((struct cmd_list_element *, FILE *)); +show_user_1 PARAMS ((struct cmd_list_element *, GDB_FILE *)); static void make_command PARAMS ((char *, int)); @@ -44,9 +43,11 @@ static int parse_binary_operation PARAMS ((char *)); static void -print_doc_line PARAMS ((FILE *, char *)); +print_doc_line PARAMS ((GDB_FILE *, char *)); -/* Add element named NAME to command list *LIST. +/* Add element named NAME. + CLASS is the top level category into which commands are broken down + for "help" purposes. FUN should be the function to execute the command; it will get a character string as argument, with leading and trailing blanks already eliminated. @@ -54,7 +55,9 @@ print_doc_line PARAMS ((FILE *, char *)); DOC is a documentation string for the command. Its first line should be a complete sentence. It should start with ? for a command that is an abbreviation - or with * for a command that most users don't need to know about. */ + or with * for a command that most users don't need to know about. + + Add this command to command list *LIST. */ struct cmd_list_element * add_cmd (name, class, fun, doc, list) @@ -76,8 +79,10 @@ add_cmd (name, class, fun, doc, list) c->prefixlist = 0; c->prefixname = (char *)NULL; c->allow_unknown = 0; + c->hook = 0; + c->hookee = 0; + c->cmd_pointer = 0; c->abbrev_flag = 0; - c->aux = 0; c->type = not_set_cmd; c->completer = make_symbol_completion_list; c->var = 0; @@ -135,7 +140,7 @@ add_alias_cmd (name, oldname, class, abbrev_flag, list) c->prefixname = old->prefixname; c->allow_unknown = old->allow_unknown; c->abbrev_flag = abbrev_flag; - c->aux = old->aux; + c->cmd_pointer = old; return c; } @@ -163,7 +168,7 @@ add_prefix_cmd (name, class, fun, doc, prefixlist, prefixname, return c; } -/* Like add_prefix_cmd butsets the abbrev_flag on the new command. */ +/* Like add_prefix_cmd but sets the abbrev_flag on the new command. */ struct cmd_list_element * add_abbrev_prefix_cmd (name, class, fun, doc, prefixlist, prefixname, @@ -185,9 +190,19 @@ add_abbrev_prefix_cmd (name, class, fun, doc, prefixlist, prefixname, return c; } -/* ARGSUSED */ +/* This is an empty "cfunc". */ void -not_just_help_class_command (args, from_tty, c) +not_just_help_class_command (args, from_tty) + char *args; + int from_tty; +{ +} + +/* This is an empty "sfunc". */ +static void empty_sfunc PARAMS ((char *, int, struct cmd_list_element *)); + +static void +empty_sfunc (args, from_tty, c) char *args; int from_tty; struct cmd_list_element *c; @@ -210,17 +225,40 @@ add_set_cmd (name, class, var_type, var, doc, list) char *doc; struct cmd_list_element **list; { - /* For set/show, we have to call do_setshow_command - differently than an ordinary function (take commandlist as - well as arg), so the function field isn't helpful. However, - function == NULL means that it's a help class, so set the function - to not_just_help_class_command. */ struct cmd_list_element *c - = add_cmd (name, class, not_just_help_class_command, doc, list); + = add_cmd (name, class, NO_FUNCTION, doc, list); c->type = set_cmd; c->var_type = var_type; c->var = var; + /* This needs to be something besides NO_FUNCTION so that this isn't + treated as a help class. */ + c->function.sfunc = empty_sfunc; + return c; +} + +/* Add element named NAME to command list LIST (the list for set + or some sublist thereof). + CLASS is as in add_cmd. + ENUMLIST is a list of strings which may follow NAME. + VAR is address of the variable which will contain the matching string + (from ENUMLIST). + DOC is the documentation string. */ + +struct cmd_list_element * +add_set_enum_cmd (name, class, enumlist, var, doc, list) + char *name; + enum command_class class; + char *enumlist[]; + char *var; + char *doc; + struct cmd_list_element **list; +{ + struct cmd_list_element *c + = add_set_cmd (name, class, var_enum, var, doc, list); + + c->enums = enumlist; + return c; } @@ -234,7 +272,7 @@ add_show_from_set (setcmd, list) struct cmd_list_element *showcmd = (struct cmd_list_element *) xmalloc (sizeof (struct cmd_list_element)); - bcopy (setcmd, showcmd, sizeof (struct cmd_list_element)); + memcpy (showcmd, setcmd, sizeof (struct cmd_list_element)); delete_cmd (showcmd->name, list); showcmd->type = show_cmd; @@ -243,7 +281,7 @@ add_show_from_set (setcmd, list) && setcmd->doc[2] == 't' && setcmd->doc[3] == ' ') showcmd->doc = concat ("Show ", setcmd->doc + 4, NULL); else - fprintf (stderr, "GDB internal error: Bad docstring for set command\n"); + fprintf_unfiltered (gdb_stderr, "GDB internal error: Bad docstring for set command\n"); showcmd->next = *list; *list = showcmd; @@ -260,20 +298,24 @@ delete_cmd (name, list) register struct cmd_list_element *c; struct cmd_list_element *p; - while (*list && !strcmp ((*list)->name, name)) + while (*list && STREQ ((*list)->name, name)) { + if ((*list)->hookee) + (*list)->hookee->hook = 0; /* Hook slips out of its mouth */ p = (*list)->next; - free (*list); + free ((PTR)*list); *list = p; } if (*list) for (c = *list; c->next;) { - if (!strcmp (c->next->name, name)) + if (STREQ (c->next->name, name)) { + if (c->next->hookee) + c->next->hookee->hook = 0; /* hooked cmd gets away. */ p = c->next->next; - free (c->next); + free ((PTR)c->next); c->next = p; } else @@ -295,7 +337,7 @@ delete_cmd (name, list) void help_cmd (command, stream) char *command; - FILE *stream; + GDB_FILE *stream; { struct cmd_list_element *c; extern struct cmd_list_element *cmdlist; @@ -337,6 +379,10 @@ help_cmd (command, stream) /* If this is a class name, print all of the commands in the class */ if (c->function.cfunc == NULL) help_list (cmdlist, "", c->class, stream); + + if (c->hook) + fprintf_filtered (stream, "\nThis command has a hook defined: %s\n", + c->hook->name); } /* @@ -356,7 +402,7 @@ help_list (list, cmdtype, class, stream) struct cmd_list_element *list; char *cmdtype; enum command_class class; - FILE *stream; + GDB_FILE *stream; { int len; char *cmdtype1, *cmdtype2; @@ -397,7 +443,7 @@ Command name abbreviations are allowed if unambiguous.\n", /* Print only the first line of STR on STREAM. */ static void print_doc_line (stream, str) - FILE *stream; + GDB_FILE *stream; char *str; { static char *line_buffer = 0; @@ -416,7 +462,7 @@ print_doc_line (stream, str) if (p - str > line_size - 1) { line_size = p - str + 1; - free (line_buffer); + free ((PTR)line_buffer); line_buffer = (char *) xmalloc (line_size); } strncpy (line_buffer, str, p - str); @@ -448,7 +494,7 @@ help_cmd_list (list, class, prefix, recurse, stream) enum command_class class; char *prefix; int recurse; - FILE *stream; + GDB_FILE *stream; { register struct cmd_list_element *c; @@ -470,36 +516,41 @@ help_cmd_list (list, class, prefix, recurse, stream) } } -/* This routine takes a line of TEXT and a CLIST in which to - start the lookup. When it returns it will have incremented the text - pointer past the section of text it matched, set *RESULT_LIST to - the list in which the last word was matched, and will return the - cmd list element which the text matches. It will return 0 if no - match at all was possible. It will return -1 if ambigous matches are - possible; in this case *RESULT_LIST will be set to the list in which - there are ambiguous choices (and text will be set to the ambiguous - text string). +/* This routine takes a line of TEXT and a CLIST in which to start the + lookup. When it returns it will have incremented the text pointer past + the section of text it matched, set *RESULT_LIST to point to the list in + which the last word was matched, and will return a pointer to the cmd + list element which the text matches. It will return NULL if no match at + all was possible. It will return -1 (cast appropriately, ick) if ambigous + matches are possible; in this case *RESULT_LIST will be set to point to + the list in which there are ambiguous choices (and *TEXT will be set to + the ambiguous text string). + + If the located command was an abbreviation, this routine returns the base + command of the abbreviation. It does no error reporting whatsoever; control will always return to the superior routine. - In the case of an ambiguous return (-1), *RESULT_LIST will be set to - point at the prefix_command (ie. the best match) *or* (special - case) will be 0 if no prefix command was ever found. For example, - in the case of "info a", "info" matches without ambiguity, but "a" - could be "args" or "address", so *RESULT_LIST is set to - the cmd_list_element for "info". So in this case - result list should not be interpeted as a pointer to the beginning - of a list; it simply points to a specific command. + In the case of an ambiguous return (-1), *RESULT_LIST will be set to point + at the prefix_command (ie. the best match) *or* (special case) will be NULL + if no prefix command was ever found. For example, in the case of "info a", + "info" matches without ambiguity, but "a" could be "args" or "address", so + *RESULT_LIST is set to the cmd_list_element for "info". So in this case + RESULT_LIST should not be interpeted as a pointer to the beginning of a + list; it simply points to a specific command. In the case of an ambiguous + return *TEXT is advanced past the last non-ambiguous prefix (e.g. + "info t" can be "info types" or "info target"; upon return *TEXT has been + advanced past "info "). If RESULT_LIST is NULL, don't set *RESULT_LIST (but don't otherwise affect the operation). This routine does *not* modify the text pointed to by TEXT. - If IGNORE_HELP_CLASSES is nonzero, ignore any command list - elements which are actually help classes rather than commands (i.e. - the function field of the struct cmd_list_element is 0). */ + If IGNORE_HELP_CLASSES is nonzero, ignore any command list elements which + are actually help classes rather than commands (i.e. the function field of + the struct cmd_list_element is NULL). */ struct cmd_list_element * lookup_cmd_1 (text, clist, result_list, ignore_help_classes) @@ -536,7 +587,7 @@ lookup_cmd_1 (text, clist, result_list, ignore_help_classes) for (tmp = 0; tmp < len; tmp++) { char x = (*text)[tmp]; - command[tmp] = (x >= 'A' && x <= 'Z') ? x - 'A' + 'a' : x; + command[tmp] = isupper(x) ? tolower(x) : x; } command[len] = '\0'; @@ -572,6 +623,14 @@ lookup_cmd_1 (text, clist, result_list, ignore_help_classes) /* We've matched something on this list. Move text pointer forward. */ *text = p; + + /* If this was an abbreviation, use the base command instead. */ + + if (found->cmd_pointer) + found = found->cmd_pointer; + + /* If we found a prefix command, keep looking. */ + if (found->prefixlist) { c = lookup_cmd_1 (text, *found->prefixlist, result_list, @@ -650,12 +709,15 @@ lookup_cmd (line, list, cmdtype, allow_unknown, ignore_help_classes) struct cmd_list_element *last_list = 0; struct cmd_list_element *c = lookup_cmd_1 (line, list, &last_list, ignore_help_classes); +#if 0 + /* This is wrong for complete_command. */ char *ptr = (*line) + strlen (*line) - 1; /* Clear off trailing whitespace. */ while (ptr >= *line && (*ptr == ' ' || *ptr == '\t')) ptr--; *(ptr + 1) = '\0'; +#endif if (!c) { @@ -785,10 +847,7 @@ lookup_cmd (line, list, cmdtype, allow_unknown) /* Find end of command name. */ p = *line; - while (*p == '-' - || (*p >= 'a' && *p <= 'z') - || (*p >= 'A' && *p <= 'Z') - || (*p >= '0' && *p <= '9')) + while (*p == '-' || isalnum(*p)) p++; /* Look up the command name. @@ -813,8 +872,8 @@ lookup_cmd (line, list, cmdtype, allow_unknown) for (cmd_len = 0; cmd_len < p - *line; cmd_len++) { char x = (*line)[cmd_len]; - if (x >= 'A' && x <= 'Z') - processed_cmd[cmd_len] = x - 'A' + 'a'; + if (isupper(x)) + processed_cmd[cmd_len] = tolower(x); else processed_cmd[cmd_len] = x; } @@ -887,12 +946,18 @@ lookup_cmd (line, list, cmdtype, allow_unknown) /* Helper function for SYMBOL_COMPLETION_FUNCTION. */ /* Return a vector of char pointers which point to the different - possible completions in LIST of TEXT. */ + possible completions in LIST of TEXT. + + WORD points in the same buffer as TEXT, and completions should be + returned relative to this position. For example, suppose TEXT is "foo" + and we want to complete to "foobar". If WORD is "oo", return + "oobar"; if WORD is "baz/foo", return "baz/foobar". */ char ** -complete_on_cmdlist (list, text) +complete_on_cmdlist (list, text, word) struct cmd_list_element *list; char *text; + char *word; { struct cmd_list_element *ptr; char **matchlist; @@ -919,13 +984,99 @@ complete_on_cmdlist (list, text) } matchlist[matches] = (char *) - xmalloc (strlen (ptr->name) + 1); - strcpy (matchlist[matches++], ptr->name); + xmalloc (strlen (word) + strlen (ptr->name) + 1); + if (word == text) + strcpy (matchlist[matches], ptr->name); + else if (word > text) + { + /* Return some portion of ptr->name. */ + strcpy (matchlist[matches], ptr->name + (word - text)); + } + else + { + /* Return some of text plus ptr->name. */ + strncpy (matchlist[matches], word, text - word); + matchlist[matches][text - word] = '\0'; + strcat (matchlist[matches], ptr->name); + } + ++matches; } if (matches == 0) { - free (matchlist); + free ((PTR)matchlist); + matchlist = 0; + } + else + { + matchlist = (char **) xrealloc ((char *)matchlist, ((matches + 1) + * sizeof (char *))); + matchlist[matches] = (char *) 0; + } + + return matchlist; +} + +/* Helper function for SYMBOL_COMPLETION_FUNCTION. */ + +/* Return a vector of char pointers which point to the different + possible completions in CMD of TEXT. + + WORD points in the same buffer as TEXT, and completions should be + returned relative to this position. For example, suppose TEXT is "foo" + and we want to complete to "foobar". If WORD is "oo", return + "oobar"; if WORD is "baz/foo", return "baz/foobar". */ + +char ** +complete_on_enum (enumlist, text, word) + char **enumlist; + char *text; + char *word; +{ + char **matchlist; + int sizeof_matchlist; + int matches; + int textlen = strlen (text); + int i; + char *name; + + sizeof_matchlist = 10; + matchlist = (char **) xmalloc (sizeof_matchlist * sizeof (char *)); + matches = 0; + + for (i = 0; name = enumlist[i]; i++) + if (strncmp (name, text, textlen) == 0) + { + if (matches == sizeof_matchlist) + { + sizeof_matchlist *= 2; + matchlist = (char **) xrealloc ((char *)matchlist, + (sizeof_matchlist + * sizeof (char *))); + } + + matchlist[matches] = (char *) + xmalloc (strlen (word) + strlen (name) + 1); + if (word == text) + strcpy (matchlist[matches], name); + else if (word > text) + { + /* Return some portion of name. */ + strcpy (matchlist[matches], name + (word - text)); + } + else + { + /* Return some of text plus name. */ + strncpy (matchlist[matches], word, text - word); + matchlist[matches][text - word] = '\0'; + strcat (matchlist[matches], name); + } + ++matches; + } + + if (matches == 0) + { + free ((PTR)matchlist); matchlist = 0; } else @@ -999,6 +1150,11 @@ do_setshow_command (arg, from_tty, c) { /* \ at end of argument is used after spaces so they won't be lost. */ + /* This is obsolete now that we no longer strip + trailing whitespace and actually, the backslash + didn't get here in my test, readline or + something did something funky with a backslash + right before a newline. */ if (*p == 0) break; ch = parse_escape (&p); @@ -1010,8 +1166,10 @@ do_setshow_command (arg, from_tty, c) else *q++ = ch; } +#if 0 if (*(p - 1) != '\\') *q++ = ' '; +#endif *q++ = '\0'; new = (char *) xrealloc (new, q - new); if (*(char **)c->var != NULL) @@ -1039,15 +1197,61 @@ do_setshow_command (arg, from_tty, c) case var_uinteger: if (arg == NULL) error_no_arg ("integer to set it to."); - *(int *) c->var = parse_and_eval_address (arg); - if (*(int *) c->var == 0) - *(int *) c->var = UINT_MAX; + *(unsigned int *) c->var = parse_and_eval_address (arg); + if (*(unsigned int *) c->var == 0) + *(unsigned int *) c->var = UINT_MAX; break; + case var_integer: + { + unsigned int val; + if (arg == NULL) + error_no_arg ("integer to set it to."); + val = parse_and_eval_address (arg); + if (val == 0) + *(int *) c->var = INT_MAX; + else if (val >= INT_MAX) + error ("integer %u out of range", val); + else + *(int *) c->var = val; + break; + } case var_zinteger: if (arg == NULL) error_no_arg ("integer to set it to."); *(int *) c->var = parse_and_eval_address (arg); break; + case var_enum: + { + int i; + int len; + int nmatches; + char *match; + char *p; + + p = strchr (arg, ' '); + + if (p) + len = p - arg; + else + len = strlen (arg); + + nmatches = 0; + for (i = 0; c->enums[i]; i++) + if (strncmp (arg, c->enums[i], len) == 0) + { + match = c->enums[i]; + nmatches++; + } + + if (nmatches <= 0) + error ("Undefined item: \"%s\".", arg); + + if (nmatches > 1) + error ("Ambiguous item \"%s\".", arg); + + *(char **)c->var = match; + } + break; default: error ("gdb internal error: bad var_type in do_setshow_command"); } @@ -1055,43 +1259,53 @@ do_setshow_command (arg, from_tty, c) else if (c->type == show_cmd) { /* Print doc minus "show" at start. */ - print_doc_line (stdout, c->doc + 5); + print_doc_line (gdb_stdout, c->doc + 5); - fputs_filtered (" is ", stdout); + fputs_filtered (" is ", gdb_stdout); wrap_here (" "); switch (c->var_type) { case var_string: { unsigned char *p; - fputs_filtered ("\"", stdout); + fputs_filtered ("\"", gdb_stdout); for (p = *(unsigned char **) c->var; *p != '\0'; p++) - printchar (*p, stdout, '"'); - fputs_filtered ("\"", stdout); + gdb_printchar (*p, gdb_stdout, '"'); + fputs_filtered ("\"", gdb_stdout); } break; case var_string_noescape: case var_filename: - fputs_filtered ("\"", stdout); - fputs_filtered (*(char **) c->var, stdout); - fputs_filtered ("\"", stdout); + case var_enum: + fputs_filtered ("\"", gdb_stdout); + fputs_filtered (*(char **) c->var, gdb_stdout); + fputs_filtered ("\"", gdb_stdout); break; case var_boolean: - fputs_filtered (*(int *) c->var ? "on" : "off", stdout); + fputs_filtered (*(int *) c->var ? "on" : "off", gdb_stdout); break; case var_uinteger: if (*(unsigned int *) c->var == UINT_MAX) { - fputs_filtered ("unlimited", stdout); + fputs_filtered ("unlimited", gdb_stdout); break; } /* else fall through */ case var_zinteger: - fprintf_filtered (stdout, "%d", *(unsigned int *) c->var); + fprintf_filtered (gdb_stdout, "%u", *(unsigned int *) c->var); + break; + case var_integer: + if (*(int *) c->var == INT_MAX) + { + fputs_filtered ("unlimited", gdb_stdout); + } + else + fprintf_filtered (gdb_stdout, "%d", *(int *) c->var); break; + default: error ("gdb internal error: bad var_type in do_setshow_command"); } - fputs_filtered (".\n", stdout); + fputs_filtered (".\n", gdb_stdout); } else error ("gdb internal error: bad cmd_type in do_setshow_command"); @@ -1113,9 +1327,9 @@ cmd_show_list (list, from_tty, prefix) cmd_show_list (*list->prefixlist, from_tty, list->prefixname + 5); if (list->type == show_cmd) { - fputs_filtered (prefix, stdout); - fputs_filtered (list->name, stdout); - fputs_filtered (": ", stdout); + fputs_filtered (prefix, gdb_stdout); + fputs_filtered (list->name, gdb_stdout); + fputs_filtered (": ", gdb_stdout); do_setshow_command ((char *)NULL, from_tty, list); } } @@ -1127,6 +1341,11 @@ shell_escape (arg, from_tty) char *arg; int from_tty; { +#ifdef CANT_FORK + /* FIXME: what about errors (I don't know how GO32 system() handles + them)? */ + system (arg); +#else /* Can fork. */ int rc, status, pid; char *p, *user_shell; @@ -1146,8 +1365,10 @@ shell_escape (arg, from_tty) else execl (user_shell, p, "-c", arg, 0); - fprintf (stderr, "Exec of shell failed\n"); - exit (0); + fprintf_unfiltered (gdb_stderr, "Cannot execute %s: %s\n", user_shell, + safe_strerror (errno)); + gdb_flush (gdb_stderr); + _exit (0177); } if (pid != -1) @@ -1155,6 +1376,7 @@ shell_escape (arg, from_tty) ; else error ("Fork failed"); +#endif /* Can fork. */ } static void @@ -1179,17 +1401,20 @@ make_command (arg, from_tty) static void show_user_1 (c, stream) struct cmd_list_element *c; - FILE *stream; + GDB_FILE *stream; { register struct command_line *cmdlines; cmdlines = c->user_commands; if (!cmdlines) return; - fprintf_filtered (stream, "User command %s:\n", c->name); + fputs_filtered ("User command ", stream); + fputs_filtered (c->name, stream); + fputs_filtered (":\n", stream); + while (cmdlines) { - fprintf_filtered (stream, "%s\n", cmdlines->line); + print_command_line (cmdlines, 4); cmdlines = cmdlines->next; } fputs_filtered ("\n", stream); @@ -1209,14 +1434,14 @@ show_user (args, from_tty) c = lookup_cmd (&args, cmdlist, "", 0, 1); if (c->class != class_user) error ("Not a user command."); - show_user_1 (c, stdout); + show_user_1 (c, gdb_stdout); } else { for (c = cmdlist; c; c = c->next) { if (c->class == class_user) - show_user_1 (c, stdout); + show_user_1 (c, gdb_stdout); } } } @@ -1227,10 +1452,8 @@ _initialize_command () add_com ("shell", class_support, shell_escape, "Execute the rest of the line as a shell command. \n\ With no arguments, run an inferior shell."); - add_com ("make", class_support, make_command, "Run the ``make'' program using the rest of the line as arguments."); - add_cmd ("user", no_class, show_user, "Show definitions of user defined commands.\n\ Argument is the name of the user defined command.\n\