/* GDB CLI commands.
- Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010,
- 2011 Free Software Foundation, Inc.
+ Copyright (C) 2000-2005, 2007-2012 Free Software Foundation, Inc.
This file is part of GDB.
#include "defs.h"
#include "exceptions.h"
#include "arch-utils.h"
+#include "dyn-string.h"
#include "readline/readline.h"
#include "readline/tilde.h"
#include "completer.h"
/* Prototypes for local utility functions */
static void ambiguous_line_spec (struct symtabs_and_lines *);
+
+static void filter_sals (struct symtabs_and_lines *);
+
\f
/* Limit the call depth of user-defined commands */
int max_user_call_depth;
struct cmd_list_element *showchecklist;
+struct cmd_list_element *skiplist;
+
/* Command tracing state. */
int source_verbose = 0;
static void
info_command (char *arg, int from_tty)
{
- printf_unfiltered (_("\"info\" must be followed by the name of an info command.\n"));
+ printf_unfiltered (_("\"info\" must be followed by "
+ "the name of an info command.\n"));
help_list (infolist, "info ", -1, gdb_stdout);
}
help_cmd (command, gdb_stdout);
}
\f
-/* String compare function for qsort. */
-static int
-compare_strings (const void *arg1, const void *arg2)
-{
- const char **s1 = (const char **) arg1;
- const char **s2 = (const char **) arg2;
-
- return strcmp (*s1, *s2);
-}
-
/* The "complete" command is used by Emacs to implement completion. */
static void
show_script_ext_mode (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- fprintf_filtered (file, _("\
-Script filename extension recognition is \"%s\".\n"),
+ fprintf_filtered (file,
+ _("Script filename extension recognition is \"%s\".\n"),
value);
}
TRY_CATCH (e, RETURN_MASK_ERROR)
{
- source_python_script (stream, file);
+ /* The python support reopens the file using python functions,
+ so there's no point in passing STREAM here. */
+ source_python_script (file);
}
if (e.reason < 0)
{
if (!find_and_open_script (file, search_path, &stream, &full_path))
{
- /* The script wasn't found, or was otherwise inaccessible.
+ /* The script wasn't found, or was otherwise inaccessible.
If the source command was invoked interactively, throw an
error. Otherwise (e.g. if it was invoked by a script),
silently ignore the error. */
}
old_cleanups = make_cleanup (xfree, full_path);
- source_script_from_stream (stream, file);
+ /* The python support reopens the file, so we need to pass full_path here
+ in case the file was found on the search path. It's useful to do this
+ anyway so that error messages show the actual file used. But only do
+ this if we (may have) used search_path, as printing the full path in
+ errors for the non-search case can be more noise than signal. */
+ source_script_from_stream (stream, search_path ? full_path : file);
do_cleanups (old_cleanups);
}
chdir (current_directory);
#endif
#else /* Can fork. */
- int rc, status, pid;
+ int status, pid;
if ((pid = vfork ()) == 0)
{
- char *p, *user_shell;
+ const char *p, *user_shell;
if ((user_shell = (char *) getenv ("SHELL")) == NULL)
user_shell = "/bin/sh";
/* Get the name of the shell for arg0. */
- if ((p = strrchr (user_shell, '/')) == NULL)
- p = user_shell;
- else
- p++; /* Get past '/' */
+ p = lbasename (user_shell);
if (!arg)
execl (user_shell, p, (char *) 0);
}
if (pid != -1)
- while ((rc = wait (&status)) != pid && rc != -1)
- ;
+ waitpid (pid, &status, 0);
else
error (_("Fork failed"));
#endif /* Can fork. */
/* Now should only be one argument -- decode it in SAL. */
arg1 = arg;
- sals = decode_line_1 (&arg1, 0, 0, 0, 0, 0);
+ sals = decode_line_1 (&arg1, DECODE_LINE_LIST_MODE, 0, 0);
+ filter_sals (&sals);
if (! sals.nelts)
{
/* C++ */
if (strcmp (arg, "-") == 0)
{
print_source_lines (cursal.symtab,
- max (get_first_line_listed () - get_lines_to_list (), 1),
+ max (get_first_line_listed ()
+ - get_lines_to_list (), 1),
get_first_line_listed (), 0);
return;
}
dummy_beg = 1;
else
{
- sals = decode_line_1 (&arg1, 0, 0, 0, 0, 0);
+ sals = decode_line_1 (&arg1, DECODE_LINE_LIST_MODE, 0, 0);
+ filter_sals (&sals);
if (!sals.nelts)
return; /* C++ */
if (sals.nelts > 1)
else
{
if (dummy_beg)
- sals_end = decode_line_1 (&arg1, 0, 0, 0, 0, 0);
+ sals_end = decode_line_1 (&arg1, DECODE_LINE_LIST_MODE, 0, 0);
else
- sals_end = decode_line_1 (&arg1, 0, sal.symtab, sal.line, 0, 0);
+ sals_end = decode_line_1 (&arg1, DECODE_LINE_LIST_MODE,
+ sal.symtab, sal.line);
+ filter_sals (&sals);
if (sals_end.nelts == 0)
return;
if (sals_end.nelts > 1)
paddress (gdbarch, low), paddress (gdbarch, high));
/* Dump the specified range. */
- gdb_disassembly (gdbarch, uiout, 0, flags, -1, low, high);
+ gdb_disassembly (gdbarch, current_uiout, 0, flags, -1, low, high);
printf_filtered ("End of assembler dump.\n");
gdb_flush (gdb_stdout);
void
apropos_command (char *searchstr, int from_tty)
{
- extern struct cmd_list_element *cmdlist; /* This is the main command
- list. */
regex_t pattern;
- char *pattern_fastmap;
- char errorbuffer[512];
+ int code;
- pattern_fastmap = xcalloc (256, sizeof (char));
if (searchstr == NULL)
- error (_("REGEXP string is empty"));
+ error (_("REGEXP string is empty"));
- if (regcomp(&pattern,searchstr,REG_ICASE) == 0)
+ code = regcomp (&pattern, searchstr, REG_ICASE);
+ if (code == 0)
{
- pattern.fastmap=pattern_fastmap;
- re_compile_fastmap(&pattern);
- apropos_cmd (gdb_stdout,cmdlist,&pattern,"");
+ struct cleanup *cleanups;
+
+ cleanups = make_regfree_cleanup (&pattern);
+ apropos_cmd (gdb_stdout, cmdlist, &pattern, "");
+ do_cleanups (cleanups);
}
else
{
- regerror(regcomp(&pattern,searchstr,REG_ICASE),NULL,errorbuffer,512);
- error (_("Error in regular expression:%s"),errorbuffer);
+ char *err = get_regcomp_error (code, &pattern);
+
+ make_cleanup (xfree, err);
+ error (_("Error in regular expression: %s"), err);
+ }
+}
+
+/* Subroutine of alias_command to simplify it.
+ Return the first N elements of ARGV flattened back to a string
+ with a space separating each element.
+ ARGV may not be NULL.
+ This does not take care of quoting elements in case they contain spaces
+ on purpose. */
+
+static dyn_string_t
+argv_to_dyn_string (char **argv, int n)
+{
+ int i;
+ dyn_string_t result = dyn_string_new (10);
+
+ gdb_assert (argv != NULL);
+ gdb_assert (n >= 0 && n <= countargv (argv));
+
+ for (i = 0; i < n; ++i)
+ {
+ if (i > 0)
+ dyn_string_append_char (result, ' ');
+ dyn_string_append_cstr (result, argv[i]);
+ }
+
+ return result;
+}
+
+/* Subroutine of alias_command to simplify it.
+ Return TRUE if COMMAND exists, unambiguously. Otherwise FALSE. */
+
+static int
+valid_command_p (char *command)
+{
+ struct cmd_list_element *c;
+
+ c = lookup_cmd_1 (& command, cmdlist, NULL, 1);
+
+ if (c == NULL || c == (struct cmd_list_element *) -1)
+ return FALSE;
+
+ /* This is the slightly tricky part.
+ lookup_cmd_1 will return a pointer to the last part of COMMAND
+ to match, leaving COMMAND pointing at the remainder. */
+ while (*command == ' ' || *command == '\t')
+ ++command;
+ return *command == '\0';
+}
+
+/* Make an alias of an existing command. */
+
+static void
+alias_command (char *args, int from_tty)
+{
+ int i, alias_argc, command_argc;
+ int abbrev_flag = 0;
+ char *args2, *equals, *alias, *command;
+ char **alias_argv, **command_argv;
+ dyn_string_t alias_dyn_string, command_dyn_string;
+ struct cmd_list_element *c;
+ static const char usage[] = N_("Usage: alias [-a] [--] ALIAS = COMMAND");
+
+ if (args == NULL || strchr (args, '=') == NULL)
+ error (_(usage));
+
+ args2 = xstrdup (args);
+ make_cleanup (xfree, args2);
+ equals = strchr (args2, '=');
+ *equals = '\0';
+ alias_argv = gdb_buildargv (args2);
+ make_cleanup_freeargv (alias_argv);
+ command_argv = gdb_buildargv (equals + 1);
+ make_cleanup_freeargv (command_argv);
+
+ for (i = 0; alias_argv[i] != NULL; )
+ {
+ if (strcmp (alias_argv[i], "-a") == 0)
+ {
+ ++alias_argv;
+ abbrev_flag = 1;
+ }
+ else if (strcmp (alias_argv[i], "--") == 0)
+ {
+ ++alias_argv;
+ break;
+ }
+ else
+ break;
+ }
+
+ if (alias_argv[0] == NULL || command_argv[0] == NULL
+ || *alias_argv[0] == '\0' || *command_argv[0] == '\0')
+ error (_(usage));
+
+ for (i = 0; alias_argv[i] != NULL; ++i)
+ {
+ if (! valid_user_defined_cmd_name_p (alias_argv[i]))
+ {
+ if (i == 0)
+ error (_("Invalid command name: %s"), alias_argv[i]);
+ else
+ error (_("Invalid command element name: %s"), alias_argv[i]);
+ }
+ }
+
+ alias_argc = countargv (alias_argv);
+ command_argc = countargv (command_argv);
+
+ /* COMMAND must exist.
+ Reconstruct the command to remove any extraneous spaces,
+ for better error messages. */
+ command_dyn_string = argv_to_dyn_string (command_argv, command_argc);
+ make_cleanup_dyn_string_delete (command_dyn_string);
+ command = dyn_string_buf (command_dyn_string);
+ if (! valid_command_p (command))
+ error (_("Invalid command to alias to: %s"), command);
+
+ /* ALIAS must not exist. */
+ alias_dyn_string = argv_to_dyn_string (alias_argv, alias_argc);
+ make_cleanup_dyn_string_delete (alias_dyn_string);
+ alias = dyn_string_buf (alias_dyn_string);
+ if (valid_command_p (alias))
+ error (_("Alias already exists: %s"), alias);
+
+ /* If ALIAS is one word, it is an alias for the entire COMMAND.
+ Example: alias spe = set print elements
+
+ Otherwise ALIAS and COMMAND must have the same number of words,
+ and every word except the last must match; and the last word of
+ ALIAS is made an alias of the last word of COMMAND.
+ Example: alias set print elms = set pr elem
+ Note that unambiguous abbreviations are allowed. */
+
+ if (alias_argc == 1)
+ {
+ /* add_cmd requires *we* allocate space for name, hence the xstrdup. */
+ add_com_alias (xstrdup (alias_argv[0]), command, class_alias,
+ abbrev_flag);
+ }
+ else
+ {
+ int i;
+ dyn_string_t alias_prefix_dyn_string, command_prefix_dyn_string;
+ char *alias_prefix, *command_prefix;
+ struct cmd_list_element *c_alias, *c_command;
+
+ if (alias_argc != command_argc)
+ error (_("Mismatched command length between ALIAS and COMMAND."));
+
+ /* Create copies of ALIAS and COMMAND without the last word,
+ and use that to verify the leading elements match. */
+ alias_prefix_dyn_string =
+ argv_to_dyn_string (alias_argv, alias_argc - 1);
+ make_cleanup_dyn_string_delete (alias_prefix_dyn_string);
+ command_prefix_dyn_string =
+ argv_to_dyn_string (alias_argv, command_argc - 1);
+ make_cleanup_dyn_string_delete (command_prefix_dyn_string);
+ alias_prefix = dyn_string_buf (alias_prefix_dyn_string);
+ command_prefix = dyn_string_buf (command_prefix_dyn_string);
+
+ c_command = lookup_cmd_1 (& command_prefix, cmdlist, NULL, 1);
+ /* We've already tried to look up COMMAND. */
+ gdb_assert (c_command != NULL
+ && c_command != (struct cmd_list_element *) -1);
+ gdb_assert (c_command->prefixlist != NULL);
+ c_alias = lookup_cmd_1 (& alias_prefix, cmdlist, NULL, 1);
+ if (c_alias != c_command)
+ error (_("ALIAS and COMMAND prefixes do not match."));
+
+ /* add_cmd requires *we* allocate space for name, hence the xstrdup. */
+ add_alias_cmd (xstrdup (alias_argv[alias_argc - 1]),
+ command_argv[command_argc - 1],
+ class_alias, abbrev_flag, c_command->prefixlist);
}
- xfree (pattern_fastmap);
}
\f
/* Print a list of files and line numbers which a user may choose from
sals->sals[i].symtab->filename, sals->sals[i].line);
}
+/* Sort function for filter_sals. */
+
+static int
+compare_symtabs (const void *a, const void *b)
+{
+ const struct symtab_and_line *sala = a;
+ const struct symtab_and_line *salb = b;
+ int r;
+
+ if (!sala->symtab->dirname)
+ {
+ if (salb->symtab->dirname)
+ return -1;
+ }
+ else if (!salb->symtab->dirname)
+ {
+ if (sala->symtab->dirname)
+ return 1;
+ }
+ else
+ {
+ r = filename_cmp (sala->symtab->dirname, salb->symtab->dirname);
+ if (r)
+ return r;
+ }
+
+ r = filename_cmp (sala->symtab->filename, salb->symtab->filename);
+ if (r)
+ return r;
+
+ if (sala->line < salb->line)
+ return -1;
+ return sala->line == salb->line ? 0 : 1;
+}
+
+/* Remove any SALs that do not match the current program space, or
+ which appear to be "file:line" duplicates. */
+
+static void
+filter_sals (struct symtabs_and_lines *sals)
+{
+ int i, out, prev;
+
+ out = 0;
+ for (i = 0; i < sals->nelts; ++i)
+ {
+ if (sals->sals[i].pspace == current_program_space
+ && sals->sals[i].symtab != NULL)
+ {
+ sals->sals[out] = sals->sals[i];
+ ++out;
+ }
+ }
+ sals->nelts = out;
+
+ qsort (sals->sals, sals->nelts, sizeof (struct symtab_and_line),
+ compare_symtabs);
+
+ out = 1;
+ prev = 0;
+ for (i = 1; i < sals->nelts; ++i)
+ {
+ if (compare_symtabs (&sals->sals[prev], &sals->sals[i]))
+ {
+ /* Symtabs differ. */
+ sals->sals[out] = sals->sals[i];
+ prev = out;
+ ++out;
+ }
+ }
+ sals->nelts = out;
+
+ if (sals->nelts == 0)
+ {
+ xfree (sals->sals);
+ sals->sals = NULL;
+ }
+}
+
static void
set_debug (char *arg, int from_tty)
{
- printf_unfiltered (_("\"set debug\" must be followed by the name of a debug subcommand.\n"));
+ printf_unfiltered (_("\"set debug\" must be followed by "
+ "the name of a debug subcommand.\n"));
help_list (setdebuglist, "set debug ", -1, gdb_stdout);
}
showprintlist = NULL;
setchecklist = NULL;
showchecklist = NULL;
+ skiplist = NULL;
}
static void
const char *value)
{
if (info_verbose)
- fprintf_filtered (file, _("\
-Verbose printing of informational messages is %s.\n"), value);
+ fprintf_filtered (file,
+ _("Verbose printing of informational messages is %s.\n"),
+ value);
else
fprintf_filtered (file, _("Verbosity is %s.\n"), value);
}
show_remote_timeout (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- fprintf_filtered (file, _("\
-Timeout limit to wait for target to respond is %s.\n"),
+ fprintf_filtered (file,
+ _("Timeout limit to wait for target to respond is %s.\n"),
value);
}
show_max_user_call_depth (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- fprintf_filtered (file, _("\
-The max call depth for user-defined commands is %s.\n"),
+ fprintf_filtered (file,
+ _("The max call depth for user-defined commands is %s.\n"),
value);
}
char *source_help_text;
/* Define the classes of commands.
- They will appear in the help list in the reverse of this order. */
+ They will appear in the help list in alphabetical order. */
add_cmd ("internals", class_maintenance, NULL, _("\
Maintenance commands.\n\
well documented as user commands."),
&cmdlist);
add_cmd ("obscure", class_obscure, NULL, _("Obscure features."), &cmdlist);
- add_cmd ("aliases", class_alias, NULL, _("Aliases of other commands."), &cmdlist);
+ add_cmd ("aliases", class_alias, NULL,
+ _("Aliases of other commands."), &cmdlist);
add_cmd ("user-defined", class_user, NULL, _("\
User-defined commands.\n\
The commands in this class are those defined by the user.\n\
/* Another way to get at the same thing. */
add_info ("set", show_command, _("Show all GDB settings."));
- add_cmd ("commands", no_class, show_commands, _("\
+ add_cmd ("commands", no_set_class, show_commands, _("\
Show the history of commands you typed.\n\
You can supply a command number to start with, or a `+' to start after\n\
the previous command number shown."),
&showlist);
- add_cmd ("version", no_class, show_version,
+ add_cmd ("version", no_set_class, show_version,
_("Show what version of GDB this is."), &showlist);
add_com ("while", class_support, while_command, _("\
FUNCTION, to list around beginning of that function,\n\
FILE:FUNCTION, to distinguish among like-named static functions.\n\
*ADDRESS, to list around the line containing that address.\n\
-With two args if one is empty it stands for ten lines away from the other arg."));
+With two args if one is empty it stands for ten lines away from \
+the other arg."));
if (!xdb_commands)
add_com_alias ("l", "list", class_files, 1);
if (xdb_commands)
add_com_alias ("va", "disassemble", class_xdb, 0);
- /* NOTE: cagney/2000-03-20: Being able to enter ``(gdb) !ls'' would
- be a really useful feature. Unfortunately, the below wont do
- this. Instead it adds support for the form ``(gdb) ! ls''
- (i.e. the space is required). If the ``!'' command below is
- added the complains about no ``!'' command would be replaced by
- complains about how the ``!'' command is broken :-) */
- if (xdb_commands)
- add_com_alias ("!", "shell", class_support, 0);
+ add_com_alias ("!", "shell", class_support, 0);
c = add_com ("make", class_support, make_command, _("\
Run the ``make'' program using the rest of the line as arguments."));
NULL,
NULL,
&setlist, &showlist);
+
+ c = add_com ("alias", class_support, alias_command, _("\
+Define a new command that is an alias of an existing command.\n\
+Usage: alias [-a] [--] ALIAS = COMMAND\n\
+ALIAS is the name of the alias command to create.\n\
+COMMAND is the command being aliased to.\n\
+If \"-a\" is specified, the command is an abbreviation,\n\
+and will not appear in help command list output.\n\
+\n\
+Examples:\n\
+Make \"spe\" an alias of \"set print elements\":\n\
+ alias spe = set print elements\n\
+Make \"elms\" an alias of \"elements\" in the \"set print\" command:\n\
+ alias -a set print elms = set print elements"));
}