-/* Top level for GDB, the GNU debugger.
- Copyright (C) 1986, 1987, 1988, 1989, 1990 Free Software Foundation, Inc.
+/* Top level `main' program for GDB, the GNU debugger.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992
+ Free Software Foundation, Inc.
This file is part of GDB.
-GDB is free software; you can redistribute it and/or modify
+This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 1, or (at your option)
-any later version.
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
-GDB is distributed in the hope that it will be useful,
+This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with GDB; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-#include <stdio.h>
-int fclose ();
#include "defs.h"
#include "gdbcmd.h"
-#include "param.h"
+#include "call-cmds.h"
#include "symtab.h"
#include "inferior.h"
#include "signals.h"
#include "target.h"
#include "breakpoint.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "language.h"
-#include <getopt.h>
-#include <readline/readline.h>
-#include <readline/history.h>
+#include "getopt.h"
+
+/* readline include files */
+#include "readline.h"
+#include "history.h"
/* readline defines this. */
#undef savestring
#endif
#include <string.h>
+#ifndef NO_SYS_FILE
#include <sys/file.h>
+#endif
#include <setjmp.h>
#include <sys/param.h>
#include <sys/stat.h>
+#include <ctype.h>
#ifdef SET_STACK_LIMIT_HUGE
#include <sys/time.h>
#include <sys/resource.h>
-#include <ctype.h>
int original_stack_limit;
#endif
+/* Prototypes for local functions */
+
+static char *
+symbol_completion_function PARAMS ((char *, int));
+
+static void
+command_loop PARAMS ((void));
+
+static void
+command_loop_marker PARAMS ((int));
+
+static void
+print_gdb_version PARAMS ((FILE *));
+
+static void
+quit_command PARAMS ((char *, int));
+
+static void
+initialize_main PARAMS ((void));
+
+static void
+initialize_history PARAMS ((void));
+
+static void
+initialize_cmd_lists PARAMS ((void));
+
+static void
+float_handler PARAMS ((int));
+
+static void
+source_command PARAMS ((char *, int));
+
+static void
+cd_command PARAMS ((char *, int));
+
+static void
+print_gnu_advertisement PARAMS ((void));
+
+static void
+init_signals PARAMS ((void));
+
+static void
+read_command_file PARAMS ((FILE *));
+
+static void
+set_verbose PARAMS ((char *, int, struct cmd_list_element *));
+
+static void
+show_history PARAMS ((char *, int));
+
+static void
+set_history PARAMS ((char *, int));
+
+static void
+set_history_size_command PARAMS ((char *, int, struct cmd_list_element *));
+
+static void
+show_commands PARAMS ((char *, int));
+
+static void
+echo_command PARAMS ((char *, int));
+
+static void
+pwd_command PARAMS ((char *, int));
+
+static void
+show_version PARAMS ((char *, int));
+
+static void
+document_command PARAMS ((char *, int));
+
+static void
+define_command PARAMS ((char *, int));
+
+static void
+validate_comname PARAMS ((char *));
+
+static void
+help_command PARAMS ((char *, int));
+
+static void
+show_command PARAMS ((char *, int));
+
+static void
+info_command PARAMS ((char *, int));
+
+static void
+do_nothing PARAMS ((int));
+
+static int
+quit_cover PARAMS ((char *));
+
+static void
+disconnect PARAMS ((int));
+
+static void
+source_cleanup PARAMS ((FILE *));
/* If this definition isn't overridden by the header files, assume
that isatty and fileno exist on this system. */
#ifndef GDBINIT_FILENAME
#define GDBINIT_FILENAME ".gdbinit"
#endif
-char gdbinit[] = GDBINIT_FILENAME;
+static char gdbinit[] = GDBINIT_FILENAME;
+static int inhibit_gdbinit = 0;
#define ALL_CLEANUPS ((struct cleanup *)0)
extern char *version;
+/* Canonical host name as a string. */
+
+extern char *host_canonical;
+
+/* Canonical target name as a string. */
+
+extern char *target_canonical;
+
+/* Message to be printed before the error message, when an error occurs. */
+
+extern char *error_pre_print;
+
+/* Message to be printed before the warning message, when a warning occurs. */
+
+extern char *warning_pre_print;
+
+extern char lang_frame_mismatch_warn[]; /* language.c */
+
+/* Whether GDB's stdin is on a terminal. */
+
+extern int gdb_has_a_terminal; /* inflow.c */
+
/* Flag for whether we want all the "from_tty" gubbish printed. */
int caution = 1; /* Default is yes, sigh. */
struct cmd_list_element *setlist;
+/* Chain containing all defined unset subcommands */
+
+struct cmd_list_element *unsetlist;
+
/* Chain containing all defined show subcommands. */
+
struct cmd_list_element *showlist;
/* Chain containing all defined \"set history\". */
struct cmd_list_element *sethistlist;
/* Chain containing all defined \"show history\". */
+
struct cmd_list_element *showhistlist;
/* Chain containing all defined \"unset history\". */
struct cmd_list_element *unsethistlist;
+/* Chain containing all defined maintenance subcommands. */
+
+#if MAINTENANCE_CMDS
+struct cmd_list_element *maintenancelist;
+#endif
+
+/* Chain containing all defined "maintenance info" subcommands. */
+
+#if MAINTENANCE_CMDS
+struct cmd_list_element *maintenanceinfolist;
+#endif
+
+/* Chain containing all defined "maintenance print" subcommands. */
+
+#if MAINTENANCE_CMDS
+struct cmd_list_element *maintenanceprintlist;
+#endif
+
+struct cmd_list_element *setprintlist;
+
+struct cmd_list_element *showprintlist;
+
+struct cmd_list_element *setchecklist;
+
+struct cmd_list_element *showchecklist;
+
/* stdio stream that command input is being read from. */
FILE *instream;
char *current_directory;
/* The directory name is actually stored here (usually). */
-static char dirbuf[MAXPATHLEN];
+static char dirbuf[1024];
/* Function to call before reading a command, if nonzero.
The function receives two args: an input stream,
and a prompt string. */
-
-void (*window_hook) ();
-extern int frame_file_full_name;
+void (*window_hook) PARAMS ((FILE *, char *));
+
+extern int mapped_symbol_files;
+extern int readnow_symbol_files;
+
int epoch_interface;
int xgdb_verbose;
-/* The external commands we call... */
-extern void init_source_path ();
-extern void directory_command ();
-extern void exec_file_command ();
-extern void symbol_file_command ();
-extern void core_file_command ();
-extern void tty_command ();
-
-extern void help_list ();
-extern void initialize_all_files ();
-extern void init_malloc ();
-
-/* Forward declarations for this file */
-void free_command_lines ();
-char *gdb_readline ();
-char *command_line_input ();
-static void initialize_main ();
-static void initialize_cmd_lists ();
-static void init_signals ();
-static void quit_command ();
-void command_loop ();
-static void source_command ();
-static void print_gdb_version ();
-static void float_handler ();
-static void cd_command ();
-static void read_command_file ();
-
-char *getenv ();
-
/* gdb prints this when reading a command interactively */
static char *prompt;
#ifndef STOP_SIGNAL
#ifdef SIGTSTP
#define STOP_SIGNAL SIGTSTP
+static void stop_sig PARAMS ((int));
#endif
#endif
#define HAVE_SIGSETMASK !defined (USG)
#endif
-#if !HAVE_SIGSETMASK
+#if 0 == (HAVE_SIGSETMASK)
#define sigsetmask(n)
#endif
\f
-/* This is how `error' returns to command level. */
+/* Where to go for return_to_top_level (RETURN_ERROR). */
+static jmp_buf error_return;
+/* Where to go for return_to_top_level (RETURN_QUIT). */
+static jmp_buf quit_return;
-jmp_buf to_top_level;
+/* Temporary variable for SET_TOP_LEVEL. */
+static int top_level_val;
-void
-return_to_top_level ()
+/* Do a setjmp on error_return and quit_return. catch_errors is
+ generally a cleaner way to do this, but main() would look pretty
+ ugly if it had to use catch_errors each time. */
+
+#define SET_TOP_LEVEL() \
+ (((top_level_val = setjmp (error_return)) \
+ ? (PTR) 0 : (PTR) memcpy (quit_return, error_return, sizeof (jmp_buf))) \
+ , top_level_val)
+
+/* Return for reason REASON. This generally gets back to the command
+ loop, but can be caught via catch_errors. */
+
+NORETURN void
+return_to_top_level (reason)
+ enum return_reason reason;
{
quit_flag = 0;
immediate_quit = 0;
bpstat_clear_actions(stop_bpstat); /* Clear queued breakpoint commands */
- clear_momentary_breakpoints ();
disable_current_display ();
do_cleanups (ALL_CLEANUPS);
- longjmp (to_top_level, 1);
+ (NORETURN void) longjmp
+ (reason == RETURN_ERROR ? error_return : quit_return, 1);
}
-/* Call FUNC with arg ARGS, catching any errors.
- If there is no error, return the value returned by FUNC.
- If there is an error, return zero after printing ERRSTRING
- (which is in addition to the specific error message already printed). */
+/* Call FUNC with arg ARGS, catching any errors. If there is no
+ error, return the value returned by FUNC. If there is an error,
+ print ERRSTRING, print the specific error message, then return
+ zero.
+
+ MASK specifies what to catch; it is normally set to
+ RETURN_MASK_ALL, if for no other reason than that the code which
+ calls catch_errors might not be set up to deal with a quit which
+ isn't caught. But if the code can deal with it, it generally
+ should be RETURN_MASK_ERROR, unless for some reason it is more
+ useful to abort only the portion of the operation inside the
+ catch_errors. Note that quit should return to the command line
+ fairly quickly, even if some further processing is being done. */
int
-catch_errors (func, args, errstring)
- int (*func) ();
- int args;
+catch_errors (func, args, errstring, mask)
+ int (*func) PARAMS ((char *));
+ PTR args;
char *errstring;
+ return_mask mask;
{
- jmp_buf saved;
+ jmp_buf saved_error;
+ jmp_buf saved_quit;
+ jmp_buf tmp_jmp;
int val;
struct cleanup *saved_cleanup_chain;
+ char *saved_error_pre_print;
saved_cleanup_chain = save_cleanups ();
+ saved_error_pre_print = error_pre_print;
- bcopy (to_top_level, saved, sizeof (jmp_buf));
+ if (mask & RETURN_MASK_ERROR)
+ memcpy ((char *)saved_error, (char *)error_return, sizeof (jmp_buf));
+ if (mask & RETURN_MASK_QUIT)
+ memcpy (saved_quit, quit_return, sizeof (jmp_buf));
+ error_pre_print = errstring;
- if (setjmp (to_top_level) == 0)
- val = (*func) (args);
- else
+ if (setjmp (tmp_jmp) == 0)
{
- if (errstring)
- fprintf (stderr, "%s\n", errstring);
- val = 0;
+ if (mask & RETURN_MASK_ERROR)
+ memcpy (error_return, tmp_jmp, sizeof (jmp_buf));
+ if (mask & RETURN_MASK_QUIT)
+ memcpy (quit_return, tmp_jmp, sizeof (jmp_buf));
+ val = (*func) (args);
}
+ else
+ val = 0;
restore_cleanups (saved_cleanup_chain);
- bcopy (saved, to_top_level, sizeof (jmp_buf));
+ error_pre_print = saved_error_pre_print;
+ if (mask & RETURN_MASK_ERROR)
+ memcpy (error_return, saved_error, sizeof (jmp_buf));
+ if (mask & RETURN_MASK_QUIT)
+ memcpy (quit_return, saved_quit, sizeof (jmp_buf));
return val;
}
/* Handler for SIGHUP. */
static void
-disconnect ()
+disconnect (signo)
+int signo;
{
- kill_inferior_fast ();
+ catch_errors (quit_cover, NULL,
+ "Could not kill the program being debugged", RETURN_MASK_ALL);
signal (SIGHUP, SIG_DFL);
kill (getpid (), SIGHUP);
}
+
+/* Just a little helper function for disconnect(). */
+
+static int
+quit_cover (s)
+char *s;
+{
+ caution = 0; /* Throw caution to the wind -- we're exiting.
+ This prevents asking the user dumb questions. */
+ quit_command((char *)0, 0);
+ return 0;
+}
\f
/* Clean up on error during a "source" command (or execution of a
user-defined command). */
char **argv;
{
int count;
- static int inhibit_gdbinit = 0;
static int quiet = 0;
static int batch = 0;
/* Number of elements used. */
int ndir;
+ struct stat homebuf, cwdbuf;
+ char *homedir, *homeinit;
+
register int i;
/* This needs to happen before the first use of malloc. */
- init_malloc ();
+ init_malloc ((PTR) NULL);
#if defined (ALIGN_STACK_ON_STARTUP)
i = (int) &count & 0x3;
alloca (4 - i);
#endif
+ /* If error() is called from initialization code, just exit */
+ if (SET_TOP_LEVEL ()) {
+ exit(1);
+ }
+
cmdsize = 1;
cmdarg = (char **) xmalloc (cmdsize * sizeof (*cmdarg));
ncmd = 0;
line[0] = '\0'; /* Terminate saved (now empty) cmd line */
instream = stdin;
- getwd (dirbuf);
+ getcwd (dirbuf, sizeof (dirbuf));
current_directory = dirbuf;
#ifdef SET_STACK_LIMIT_HUGE
with no equivalent). */
static struct option long_options[] =
{
- {"quiet", 0, &quiet, 1},
- {"nx", 0, &inhibit_gdbinit, 1},
- {"batch", 0, &batch, 1},
- {"epoch", 0, &epoch_interface, 1},
- {"fullname", 0, &frame_file_full_name, 1},
- {"help", 0, &print_help, 1},
- {"se", 1, 0, 10},
- {"symbols", 1, 0, 's'},
- {"s", 1, 0, 's'},
- {"exec", 1, 0, 'e'},
- {"core", 1, 0, 'c'},
- {"c", 1, 0, 'c'},
- {"command", 1, 0, 'x'},
- {"x", 1, 0, 'x'},
- {"directory", 1, 0, 'd'},
- {"cd", 1, 0, 11},
- {"tty", 1, 0, 't'},
- {"b", 1, 0, 'b'},
+ {"readnow", no_argument, &readnow_symbol_files, 1},
+ {"r", no_argument, &readnow_symbol_files, 1},
+ {"mapped", no_argument, &mapped_symbol_files, 1},
+ {"m", no_argument, &mapped_symbol_files, 1},
+ {"quiet", no_argument, &quiet, 1},
+ {"q", no_argument, &quiet, 1},
+ {"silent", no_argument, &quiet, 1},
+ {"nx", no_argument, &inhibit_gdbinit, 1},
+ {"n", no_argument, &inhibit_gdbinit, 1},
+ {"batch", no_argument, &batch, 1},
+ {"epoch", no_argument, &epoch_interface, 1},
+ {"fullname", no_argument, &frame_file_full_name, 1},
+ {"f", no_argument, &frame_file_full_name, 1},
+ {"help", no_argument, &print_help, 1},
+ {"se", required_argument, 0, 10},
+ {"symbols", required_argument, 0, 's'},
+ {"s", required_argument, 0, 's'},
+ {"exec", required_argument, 0, 'e'},
+ {"e", required_argument, 0, 'e'},
+ {"core", required_argument, 0, 'c'},
+ {"c", required_argument, 0, 'c'},
+ {"command", required_argument, 0, 'x'},
+ {"x", required_argument, 0, 'x'},
+ {"directory", required_argument, 0, 'd'},
+ {"cd", required_argument, 0, 11},
+ {"tty", required_argument, 0, 't'},
+ {"baud", required_argument, 0, 'b'},
+ {"b", required_argument, 0, 'b'},
/* Allow machine descriptions to add more options... */
#ifdef ADDITIONAL_OPTIONS
ADDITIONAL_OPTIONS
#endif
+ {0, no_argument, 0, 0},
};
while (1)
{
+ int option_index;
+
c = getopt_long_only (argc, argv, "",
long_options, &option_index);
if (c == EOF)
#endif
case '?':
fprintf (stderr,
- "Use `%s +help' for a complete list of options.\n",
+ "Use `%s --help' for a complete list of options.\n",
argv[0]);
exit (1);
}
-
}
+
if (print_help)
{
- fputs ("\
-This is GDB, the GNU debugger. Use the command\n\
- gdb [options] [executable [core-file]]\n\
-to enter the debugger.\n\
-\n\
-Options available are:\n\
+ print_gdb_version(stderr);
+ fputs ("\n\
+This is the GNU debugger. Usage:\n\
+ gdb [options] [executable-file [core-file or process-id]]\n\
+Options:\n\
-help Print this message.\n\
-quiet Do not print version number on startup.\n\
-fullname Output information used by emacs-GDB interface.\n\
-exec=EXECFILE Use EXECFILE as the executable.\n\
-se=FILE Use FILE as symbol file and executable file.\n\
-core=COREFILE Analyze the core dump COREFILE.\n\
- -b BAUDRATE Set serial port baud rate used for remote debugging\n\
+ -b BAUDRATE Set serial port baud rate used for remote debugging.\n\
+ -mapped Use mapped symbol files if supported on this system.\n\
+ -readnow Fully read symbol files on first access.\n\
", stderr);
#ifdef ADDITIONAL_OPTION_HELP
fputs (ADDITIONAL_OPTION_HELP, stderr);
if (!quiet)
{
- /* Print all the junk in one place, with a blank line after it
- to separate it from important stuff like "no such file".
- Also, we skip most of the noise, like Emacs, if started with
- a file name rather than with no arguments. */
- if (execarg == 0) {
- print_gdb_version (1);
- printf ("Type \"help\" for a list of commands.\n\n");
- }
+ /* Print all the junk at the top, with trailing "..." if we are about
+ to read a symbol file (possibly slowly). */
+ print_gnu_advertisement ();
+ print_gdb_version (stdout);
+ if (symarg)
+ printf_filtered ("..");
+ wrap_here("");
+ fflush (stdout); /* Force to screen during slow operations */
}
+ error_pre_print = "\n\n";
+ /* We may get more than one warning, don't double space all of them... */
+ warning_pre_print = "\nwarning: ";
+
+ /* We need a default language for parsing expressions, so simple things like
+ "set width 0" won't fail if no language is explicitly set in a config file
+ or implicitly set by reading an executable during startup. */
+ set_language (language_c);
+ expected_language = current_language; /* don't warn about the change. */
+
+ /* Read and execute $HOME/.gdbinit file, if it exists. This is done
+ *before* all the command line arguments are processed; it sets
+ global parameters, which are independent of what file you are
+ debugging or what directory you are in. */
+ homedir = getenv ("HOME");
+ if (homedir)
+ {
+ homeinit = (char *) alloca (strlen (getenv ("HOME")) +
+ strlen (gdbinit) + 10);
+ strcpy (homeinit, getenv ("HOME"));
+ strcat (homeinit, "/");
+ strcat (homeinit, gdbinit);
+ if (!inhibit_gdbinit && access (homeinit, R_OK) == 0)
+ {
+ if (!SET_TOP_LEVEL ())
+ source_command (homeinit, 0);
+ }
+ do_cleanups (ALL_CLEANUPS);
+
+ /* Do stats; no need to do them elsewhere since we'll only
+ need them if homedir is set. Make sure that they are
+ zero in case one of them fails (this guarantees that they
+ won't match if either exists). */
+
+ memset (&homebuf, 0, sizeof (struct stat));
+ memset (&cwdbuf, 0, sizeof (struct stat));
+
+ stat (homeinit, &homebuf);
+ stat (gdbinit, &cwdbuf); /* We'll only need this if
+ homedir was set. */
+ }
+
/* Now perform all the actions indicated by the arguments. */
if (cdarg != NULL)
{
- if (!setjmp (to_top_level))
+ if (!SET_TOP_LEVEL ())
{
cd_command (cdarg, 0);
init_source_path ();
do_cleanups (ALL_CLEANUPS);
for (i = 0; i < ndir; i++)
- if (!setjmp (to_top_level))
+ if (!SET_TOP_LEVEL ())
directory_command (dirarg[i], 0);
- free (dirarg);
+ free ((PTR)dirarg);
do_cleanups (ALL_CLEANUPS);
if (execarg != NULL
&& symarg != NULL
- && strcmp (execarg, symarg) == 0)
+ && STREQ (execarg, symarg))
{
/* The exec file and the symbol-file are the same. If we can't open
it, better only print one error message. */
- if (!setjmp (to_top_level))
+ if (!SET_TOP_LEVEL ())
{
exec_file_command (execarg, !batch);
- symbol_file_command (symarg, !batch);
+ symbol_file_command (symarg, 0);
}
}
else
{
if (execarg != NULL)
- if (!setjmp (to_top_level))
+ if (!SET_TOP_LEVEL ())
exec_file_command (execarg, !batch);
if (symarg != NULL)
- if (!setjmp (to_top_level))
- symbol_file_command (symarg, !batch);
+ if (!SET_TOP_LEVEL ())
+ symbol_file_command (symarg, 0);
}
do_cleanups (ALL_CLEANUPS);
+ /* After the symbol file has been read, print a newline to get us
+ beyond the copyright line... But errors should still set off
+ the error message with a (single) blank line. */
+ if (!quiet)
+ printf_filtered ("\n");
+ error_pre_print = "\n";
+ warning_pre_print = "\nwarning: ";
+
if (corearg != NULL)
- if (!setjmp (to_top_level))
+ if (!SET_TOP_LEVEL ())
core_file_command (corearg, !batch);
- else if (!setjmp (to_top_level))
+ else if (isdigit (corearg[0]) && !SET_TOP_LEVEL ())
attach_command (corearg, !batch);
do_cleanups (ALL_CLEANUPS);
if (ttyarg != NULL)
- if (!setjmp (to_top_level))
+ if (!SET_TOP_LEVEL ())
tty_command (ttyarg, !batch);
do_cleanups (ALL_CLEANUPS);
ADDITIONAL_OPTION_HANDLER;
#endif
- {
- struct stat homebuf, cwdbuf;
- char *homedir, *homeinit;
+ /* Error messages should no longer be distinguished with extra output. */
+ error_pre_print = 0;
+ warning_pre_print = "warning: ";
- /* Read init file, if it exists in home directory */
- homedir = getenv ("HOME");
- if (homedir)
+ /* Read the .gdbinit file in the current directory, *if* it isn't
+ the same as the $HOME/.gdbinit file (it should exist, also). */
+
+ if (!homedir
+ || memcmp ((char *) &homebuf, (char *) &cwdbuf, sizeof (struct stat)))
+ if (!inhibit_gdbinit && access (gdbinit, R_OK) == 0)
{
- homeinit = (char *) alloca (strlen (getenv ("HOME")) +
- strlen (gdbinit) + 10);
- strcpy (homeinit, getenv ("HOME"));
- strcat (homeinit, "/");
- strcat (homeinit, gdbinit);
- if (!inhibit_gdbinit && access (homeinit, R_OK) == 0)
- if (!setjmp (to_top_level))
- source_command (homeinit, 0);
- do_cleanups (ALL_CLEANUPS);
-
- /* Do stats; no need to do them elsewhere since we'll only
- need them if homedir is set. Make sure that they are
- zero in case one of them fails (this guarantees that they
- won't match if either exists). */
-
- bzero (&homebuf, sizeof (struct stat));
- bzero (&cwdbuf, sizeof (struct stat));
-
- stat (homeinit, &homebuf);
- stat (gdbinit, &cwdbuf); /* We'll only need this if
- homedir was set. */
- }
-
- /* Read the input file in the current directory, *if* it isn't
- the same file (it should exist, also). */
-
- if (!homedir
- || bcmp ((char *) &homebuf,
- (char *) &cwdbuf,
- sizeof (struct stat)))
- if (!inhibit_gdbinit && access (gdbinit, R_OK) == 0)
- if (!setjmp (to_top_level))
+ if (!SET_TOP_LEVEL ())
source_command (gdbinit, 0);
- do_cleanups (ALL_CLEANUPS);
- }
+ }
+ do_cleanups (ALL_CLEANUPS);
for (i = 0; i < ncmd; i++)
- if (!setjmp (to_top_level))
- {
- if (cmdarg[i][0] == '-' && cmdarg[i][1] == '\0')
- read_command_file (stdin);
- else
- source_command (cmdarg[i], !batch);
- do_cleanups (ALL_CLEANUPS);
- }
- free (cmdarg);
+ {
+ if (!SET_TOP_LEVEL ())
+ {
+ if (cmdarg[i][0] == '-' && cmdarg[i][1] == '\0')
+ read_command_file (stdin);
+ else
+ source_command (cmdarg[i], !batch);
+ do_cleanups (ALL_CLEANUPS);
+ }
+ }
+ free ((PTR)cmdarg);
+
+ /* Read in the old history after all the command files have been read. */
+ initialize_history();
if (batch)
{
while (1)
{
- if (!setjmp (to_top_level))
+ if (!SET_TOP_LEVEL ())
{
do_cleanups (ALL_CLEANUPS); /* Do complete cleanup */
command_loop ();
/* No exit -- exit is through quit_command. */
}
+void
+execute_user_command (c, args)
+ struct cmd_list_element *c;
+ char *args;
+{
+ register struct command_line *cmdlines;
+ struct cleanup *old_chain;
+
+ if (args)
+ error ("User-defined commands cannot take arguments.");
+
+ cmdlines = c->user_commands;
+ if (cmdlines == 0)
+ /* Null command */
+ return;
+
+ /* Set the instream to 0, indicating execution of a
+ user-defined function. */
+ old_chain = make_cleanup (source_cleanup, instream);
+ instream = (FILE *) 0;
+ while (cmdlines)
+ {
+ execute_command (cmdlines->line, 0);
+ cmdlines = cmdlines->next;
+ }
+ do_cleanups (old_chain);
+}
+
/* Execute the line P as a command.
Pass FROM_TTY as second argument to the defining function. */
int from_tty;
{
register struct cmd_list_element *c;
- register struct command_line *cmdlines;
+ register enum language flang;
+ static int warned = 0;
free_all_values ();
c = lookup_cmd (&p, cmdlist, "", 0, 1);
/* Pass null arg rather than an empty one. */
arg = *p ? p : 0;
+
+ /* If this command has been hooked, run the hook first. */
+ if (c->hook)
+ execute_user_command (c->hook, (char *)0);
+
if (c->class == class_user)
- {
- struct cleanup *old_chain;
-
- if (*p)
- error ("User-defined commands cannot take arguments.");
- cmdlines = c->user_commands;
- if (cmdlines == 0)
- /* Null command */
- return;
-
- /* Set the instream to 0, indicating execution of a
- user-defined function. */
- old_chain = make_cleanup (source_cleanup, instream);
- instream = (FILE *) 0;
- while (cmdlines)
- {
- execute_command (cmdlines->line, 0);
- cmdlines = cmdlines->next;
- }
- do_cleanups (old_chain);
- }
+ execute_user_command (c, arg);
else if (c->type == set_cmd || c->type == show_cmd)
do_setshow_command (arg, from_tty & caution, c);
- else if (c->function == NO_FUNCTION)
+ else if (c->function.cfunc == NO_FUNCTION)
error ("That is not a command, just a help topic.");
else
- (*c->function) (arg, from_tty & caution);
+ (*c->function.cfunc) (arg, from_tty & caution);
+ }
+
+ /* Tell the user if the language has changed (except first time). */
+ if (current_language != expected_language)
+ {
+ if (language_mode == language_mode_auto) {
+ language_info (1); /* Print what changed. */
+ }
+ warned = 0;
+ }
+
+ /* Warn the user if the working language does not match the
+ language of the current frame. Only warn the user if we are
+ actually running the program, i.e. there is a stack. */
+ /* FIXME: This should be cacheing the frame and only running when
+ the frame changes. */
+ if (target_has_stack)
+ {
+ flang = get_frame_language ();
+ if (!warned
+ && flang != language_unknown
+ && flang != current_language->la_language)
+ {
+ printf_filtered ("%s\n", lang_frame_mismatch_warn);
+ warned = 1;
}
+ }
}
/* ARGSUSED */
-void
+static void
command_loop_marker (foo)
int foo;
{
/* Read commands from `instream' and execute them
until end of file or error reading instream. */
-void
+static void
command_loop ()
{
struct cleanup *old_chain;
if (instream == stdin && stdin_is_tty)
reinitialize_more_filter ();
old_chain = make_cleanup (command_loop_marker, 0);
- command = command_line_input (instream == stdin ? prompt : 0,
+ command = command_line_input (instream == stdin ? prompt : (char *) NULL,
instream == stdin);
if (command == 0)
return;
/* Read a line from the stream "instream" without command line editing.
It prints PRROMPT once at the start.
+ Action is compatible with "readline", e.g. space for the result is
+ malloc'd and should be freed by the caller.
- If RETURN_RESULT is set it allocates
- space for whatever the user types and returns the result.
- If not, it just discards what the user types and returns a garbage
- non-NULL value.
-
- No matter what return_result is, a NULL return means end of file. */
+ A NULL return means end of file. */
char *
-gdb_readline (prrompt, return_result)
+gdb_readline (prrompt)
char *prrompt;
- int return_result;
{
int c;
char *result;
if (prrompt)
{
- printf (prrompt);
+ /* Don't use a _filtered function here. It causes the assumed
+ character position to be off, since the newline we read from
+ the user is not accounted for. */
+ fputs (prrompt, stdout);
fflush (stdout);
}
- if (return_result)
- result = (char *) xmalloc (result_size);
+ result = (char *) xmalloc (result_size);
while (1)
{
/* Read from stdin if we are executing a user defined command.
This is the right thing for prompt_for_continue, at least. */
c = fgetc (instream ? instream : stdin);
- if (c == EOF || c == '\n')
- break;
- if (return_result)
+
+ if (c == EOF)
{
- result[input_index++] = c;
- while (input_index >= result_size)
- {
- result_size *= 2;
- result = (char *) xrealloc (result, result_size);
- }
+ free (result);
+ return NULL;
}
- }
- if (c == EOF)
- {
- if (return_result)
- free (result);
- return NULL;
- }
+ if (c == '\n')
+ break;
- if (return_result)
- {
- result[input_index++] = '\0';
- return result;
+ result[input_index++] = c;
+ while (input_index >= result_size)
+ {
+ result_size *= 2;
+ result = (char *) xrealloc (result, result_size);
+ }
}
- else
- /* Return any old non-NULL pointer. */
- return (char *) "non-NULL";
-}
-/* Declaration for fancy readline with command line editing. */
-char *readline ();
+ result[input_index++] = '\0';
+ return result;
+}
/* Variables which control command line editing and history
substitution. These variables are given default values at the end
/* Variables which are necessary for fancy command line editing. */
char *gdb_completer_word_break_characters =
- " \t\n!@#$%^&*()-+=|~`}{[]\"';:?/>.<,";
+ " \t\n!@#$%^&*()+=|~`}{[]\"';:?/>.<,-";
+
+/* When completing on command names, we remove '-' from the list of
+ word break characters, since we use it in command names. If the
+ readline library sees one in any of the current completion strings,
+ it thinks that the string needs to be quoted and automatically supplies
+ a leading quote. */
+char *gdb_completer_command_word_break_characters =
+ " \t\n!@#$%^&*()+=|~`}{[]\"';:?/>.<,";
+
+/* Characters that can be used to quote completion strings. Note that we
+ can't include '"' because the gdb C parser treats such quoted sequences
+ as strings. */
+char *gdb_completer_quote_characters =
+ "'";
/* Functions that are used as part of the fancy command line editing. */
return NULL;
}
-/* Generate symbol names one by one for the completer. If STATE is
- zero, then we need to initialize, otherwise the initialization has
- already taken place. TEXT is what we expect the symbol to start
- with. RL_LINE_BUFFER is available to be looked at; it contains the
- entire text of the line. RL_POINT is the offset in that line of
- the cursor. You should pretend that the line ends at RL_POINT.
- The result is NULL if there are no more completions, else a char
- string which is a possible completion. */
-char *
-symbol_completion_function (text, state)
+/* Complete on filenames. */
+/* FIXME: This would be a lot more useful if the word breaks got set
+ to not include '/'. Probably best to make it up to each completer
+ to do its own word breaking. */
+char **
+filename_completer (text)
char *text;
- int state;
{
- static char **list = (char **)NULL;
- static int index;
- char *output;
- extern char *rl_line_buffer;
- extern int rl_point;
+ /* From readline. */
+ extern char *filename_completion_function ();
+ int subsequent_name;
+ char **return_val;
+ int return_val_used;
+ int return_val_alloced;
+
+ return_val_used = 0;
+ /* Small for testing. */
+ return_val_alloced = 1;
+ return_val = (char **) xmalloc (return_val_alloced * sizeof (char *));
+
+ subsequent_name = 0;
+ while (1)
+ {
+ char *p;
+ p = filename_completion_function (text, subsequent_name);
+ if (return_val_used >= return_val_alloced)
+ {
+ return_val_alloced *= 2;
+ return_val =
+ (char **) xrealloc (return_val,
+ return_val_alloced * sizeof (char *));
+ }
+ /* The string itself has already been stored in newly malloc'd space
+ for us by filename_completion_function. */
+ return_val[return_val_used++] = p;
+ if (p == NULL)
+ break;
+ subsequent_name = 1;
+ }
+ return return_val;
+}
+
+/* Generate symbol names one by one for the completer. Each time we are
+ called return another potential completion to the caller.
+
+ TEXT is what we expect the symbol to start with.
+
+ MATCHES is the number of matches that have currently been collected from
+ calling this completion function. When zero, then we need to initialize,
+ otherwise the initialization has already taken place and we can just
+ return the next potential completion string.
+
+ Returns NULL if there are no more completions, else a pointer to a string
+ which is a possible completion.
+
+ RL_LINE_BUFFER is available to be looked at; it contains the entire text
+ of the line. RL_POINT is the offset in that line of the cursor. You
+ should pretend that the line ends at RL_POINT. */
+
+static char *
+symbol_completion_function (text, matches)
+ char *text;
+ int matches;
+{
+ static char **list = (char **)NULL; /* Cache of completions */
+ static int index; /* Next cached completion */
+ char *output = NULL;
char *tmp_command, *p;
struct cmd_list_element *c, *result_list;
+ extern char *rl_line_buffer;
+ extern int rl_point;
- if (!state)
+ if (matches == 0)
{
- /* Free the storage used by LIST, but not by the strings inside. This is
- because rl_complete_internal () frees the strings. */
+ /* The caller is beginning to accumulate a new set of completions, so
+ we need to find all of them now, and cache them for returning one at
+ a time on future calls. */
+
if (list)
- free (list);
+ {
+ /* Free the storage used by LIST, but not by the strings inside.
+ This is because rl_complete_internal () frees the strings. */
+ free ((PTR)list);
+ }
list = 0;
index = 0;
- /* Decide whether to complete on a list of gdb commands or on
- symbols. */
+ /* Choose the default set of word break characters to break completions.
+ If we later find out that we are doing completions on command strings
+ (as opposed to strings supplied by the individual command completer
+ functions, which can be any string) then we will switch to the
+ special word break set for command strings, which leaves out the
+ '-' character used in some commands. */
+
+ /* FIXME: Using rl_completer_word_break_characters is the wrong
+ approach, because "show foo-bar<TAB>" won't know to use the
+ new set until too late. Better approach is to do the word breaking
+ ourself. */
+
+ rl_completer_word_break_characters =
+ gdb_completer_word_break_characters;
+
+ /* Decide whether to complete on a list of gdb commands or on symbols. */
tmp_command = (char *) alloca (rl_point + 1);
p = tmp_command;
if (rl_point == 0)
{
- /* An empty line we want to consider ambiguous; that is,
- it could be any command. */
+ /* An empty line we want to consider ambiguous; that is, it
+ could be any command. */
c = (struct cmd_list_element *) -1;
result_list = 0;
}
else
- c = lookup_cmd_1 (&p, cmdlist, &result_list, 1);
+ {
+ c = lookup_cmd_1 (&p, cmdlist, &result_list, 1);
+ }
/* Move p up to the next interesting thing. */
while (*p == ' ' || *p == '\t')
- p++;
+ {
+ p++;
+ }
if (!c)
- /* He's typed something unrecognizable. Sigh. */
- list = (char **) 0;
+ {
+ /* He's typed something unrecognizable. Sigh. */
+ list = NULL;
+ }
else if (c == (struct cmd_list_element *) -1)
{
/* If we didn't recognize everything up to the thing that
needs completing, and we don't know what command it is
- yet, we are in trouble. Part of the trouble might be
- that the list of delimiters used by readline includes
- '-', which we use in commands. Check for this. */
- if (p + strlen(text) != tmp_command + rl_point) {
- if (tmp_command[rl_point - strlen(text) - 1] == '-')
- text = p;
- else {
+ yet, we are in trouble. */
+
+ if (p + strlen(text) != tmp_command + rl_point)
+ {
/* This really should not produce an error. Better would
be to pretend to hit RETURN here; this would produce a
response like "Ambiguous command: foo, foobar, etc",
- and leave the line available for re-entry with ^P. Instead,
- this error blows away the user's typed input without
- any way to get it back. */
+ and leave the line available for re-entry with ^P.
+ Instead, this error blows away the user's typed input
+ without any way to get it back. */
error (" Unrecognized command.");
}
- }
/* He's typed something ambiguous. This is easier. */
if (result_list)
- list = complete_on_cmdlist (*result_list->prefixlist, text);
+ {
+ list = complete_on_cmdlist (*result_list->prefixlist, text);
+ }
else
- list = complete_on_cmdlist (cmdlist, text);
+ {
+ list = complete_on_cmdlist (cmdlist, text);
+ }
+ rl_completer_word_break_characters =
+ gdb_completer_command_word_break_characters;
}
else
{
command. */
if (!*p && *text)
- /* Always (might be longer versions of thie command). */
- list = complete_on_cmdlist (result_list, text);
+ {
+ /* Always (might be longer versions of thie command). */
+ list = complete_on_cmdlist (result_list, text);
+ rl_completer_word_break_characters =
+ gdb_completer_command_word_break_characters;
+ }
else if (!*p && !*text)
{
if (c->prefixlist)
- list = complete_on_cmdlist (*c->prefixlist, "");
+ {
+ list = complete_on_cmdlist (*c->prefixlist, "");
+ rl_completer_word_break_characters =
+ gdb_completer_command_word_break_characters;
+ }
else
- list = (*c->completer) ("");
+ {
+ list = (*c->completer) ("");
+ }
}
else
{
if (c->prefixlist && !c->allow_unknown)
{
-#if 0
- /* Something like "info adsfkdj". But error() is not
- the proper response; just return no completions
- instead. */
- *p = '\0';
- error ("\"%s\" command requires a subcommand.",
- tmp_command);
-#else
+ /* Something like "info adsfkdj". But error() is not the
+ proper response; just return no completions instead. */
list = NULL;
-#endif
}
else
- list = (*c->completer) (text);
+ {
+ list = (*c->completer) (text);
+ }
}
}
}
- /* If the debugged program wasn't compiled with symbols, or if we're
- clearly completing on a command and no command matches, return
- NULL. */
- if (!list)
- return ((char *)NULL);
+ /* If we found a list of potential completions during initialization then
+ dole them out one at a time. The vector of completions is NULL
+ terminated, so after returning the last one, return NULL (and continue
+ to do so) each time we are called after that, until a new list is
+ available. */
- output = list[index];
- if (output)
- index++;
+ if (list)
+ {
+ output = list[index];
+ if (output)
+ {
+ index++;
+ }
+ }
return (output);
}
+
+/* Skip over a possibly quoted word (as defined by the quote characters
+ and word break characters the completer uses). Returns pointer to the
+ location after the "word". */
+
+char *
+skip_quoted (str)
+ char *str;
+{
+ char quote_char = '\0';
+ char *scan;
+
+ for (scan = str; *scan != '\0'; scan++)
+ {
+ if (quote_char != '\0')
+ {
+ /* Ignore everything until the matching close quote char */
+ if (*scan == quote_char)
+ {
+ /* Found matching close quote. */
+ scan++;
+ break;
+ }
+ }
+ else if (strchr (gdb_completer_quote_characters, *scan))
+ {
+ /* Found start of a quoted string. */
+ quote_char = *scan;
+ }
+ else if (strchr (gdb_completer_word_break_characters, *scan))
+ {
+ break;
+ }
+ }
+ return (scan);
+}
+
\f
#ifdef STOP_SIGNAL
static void
-stop_sig ()
+stop_sig (signo)
+int signo;
{
#if STOP_SIGNAL == SIGTSTP
signal (SIGTSTP, SIG_DFL);
}
#endif /* STOP_SIGNAL */
-#if 0
-Writing the history file upon a terminating signal is not useful,
- because the info is rarely relevant and is in the core dump anyway.
- It is an annoyance to have the file cluttering up the place.
-/* The list of signals that would terminate us if not caught.
- We catch them, but just so that we can write the history file,
- and so forth. */
-int terminating_signals[] = {
- SIGHUP, SIGINT, SIGILL, SIGTRAP, SIGIOT,
- SIGEMT, SIGFPE, SIGKILL, SIGBUS, SIGSEGV, SIGSYS,
- SIGPIPE, SIGALRM, SIGTERM,
-#ifdef SIGXCPU
- SIGXCPU,
-#endif
-#ifdef SIGXFSZ
- SIGXFSZ,
-#endif
-#ifdef SIGVTALRM
- SIGVTALRM,
-#endif
-#ifdef SIGPROF
- SIGPROF,
-#endif
-#ifdef SIGLOST
- SIGLOST,
-#endif
-#ifdef SIGUSR1
- SIGUSR1, SIGUSR2
-#endif
- };
-
-#define TERMSIGS_LENGTH (sizeof (terminating_signals) / sizeof (int))
-
-static void
-catch_termination (sig)
- int sig;
-{
- /* We are probably here because GDB has a bug. Write out the history
- so that we might have a better chance of reproducing it. */
- /* Tell the user what we are doing so he can delete the file if
- it is unwanted. */
- write_history (history_filename);
- printf ("\n%s written.\n", history_filename);
- signal (sig, SIG_DFL);
- kill (getpid (), sig);
-}
-#endif
-
/* Initialize signal handlers. */
static void
-do_nothing ()
+do_nothing (signo)
+int signo;
{
}
static void
init_signals ()
{
- extern void request_quit ();
-#if 0
- register int i;
-
- for (i = 0; i < TERMSIGS_LENGTH; i++)
- signal (terminating_signals[i], catch_termination);
-#endif
-
signal (SIGINT, request_quit);
/* If we initialize SIGQUIT to SIG_IGN, then the SIG_IGN will get
passed to the inferior, which we don't want. It would be
possible to do a "signal (SIGQUIT, SIG_DFL)" after we fork, but
- on BSD4.3 systems using vfork, that will (apparently) affect the
+ on BSD4.3 systems using vfork, that can affect the
GDB process as well as the inferior (the signal handling tables
- being shared between the two, apparently). Since we establish
+ might be in memory, shared between the two). Since we establish
a handler for SIGQUIT, when we call exec it will set the signal
to SIG_DFL for us. */
signal (SIGQUIT, do_nothing);
if (signal (SIGHUP, do_nothing) != SIG_IGN)
signal (SIGHUP, disconnect);
signal (SIGFPE, float_handler);
+
+#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER)
+ signal (SIGWINCH, SIGWINCH_HANDLER);
+#endif
}
\f
/* Read one line from the command input stream `instream'
int repeat;
{
static char *linebuffer = 0;
- static int linelength = 0;
+ static unsigned linelength = 0;
register char *p;
char *p1;
char *rl;
while (1)
{
+ /* Reports are that some Sys V's don't flush stdout/err on reads
+ from stdin, when stdin/out are sockets rather than ttys. So we
+ have to do it ourselves, to make emacs-gdb and xxgdb work.
+ On other machines, doing this once per input should be a cheap nop. */
+ fflush (stdout);
+ fflush (stderr);
+
/* Don't use fancy stuff if not talking to stdin. */
if (command_editing_p && instream == stdin
&& ISATTY (instream))
rl = readline (local_prompt);
else
- rl = gdb_readline (local_prompt, 1);
+ rl = gdb_readline (local_prompt);
if (!rl || rl == (char *) EOF)
{
}
#ifdef STOP_SIGNAL
- signal (SIGTSTP, SIG_DFL);
+ signal (STOP_SIGNAL, SIG_DFL);
#endif
immediate_quit--;
while (1)
{
dont_repeat ();
- p = command_line_input (0, instream == stdin);
+ p = command_line_input ((char *) NULL, instream == stdin);
if (p == NULL)
/* Treat end of file like "end". */
break;
{
next = l->next;
free (l->line);
- free (l);
+ free ((PTR)l);
l = next;
}
}
void
add_info (name, fun, doc)
char *name;
- void (*fun) ();
+ void (*fun) PARAMS ((char *, int));
char *doc;
{
add_cmd (name, no_class, fun, doc, &infolist);
add_com (name, class, fun, doc)
char *name;
enum command_class class;
- void (*fun) ();
+ void (*fun) PARAMS ((char *, int));
char *doc;
{
add_cmd (name, class, fun, doc, &cmdlist);
error ("Argument required (%s).", why);
}
+/* ARGSUSED */
static void
help_command (command, from_tty)
char *command;
p = comname;
while (*p)
{
- if (!(*p >= 'A' && *p <= 'Z')
- && !(*p >= 'a' && *p <= 'z')
- && !(*p >= '0' && *p <= '9')
- && *p != '-')
+ if (!isalnum(*p) && *p != '-')
error ("Junk in argument list: \"%s\"", p);
p++;
}
}
+/* This is just a placeholder in the command data structures. */
+static void
+user_defined_command (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+}
+
static void
define_command (comname, from_tty)
char *comname;
int from_tty;
{
register struct command_line *cmds;
- register struct cmd_list_element *c, *newc;
+ register struct cmd_list_element *c, *newc, *hookc = 0;
char *tem = comname;
- extern void not_just_help_class_command ();
+#define HOOK_STRING "hook-"
+#define HOOK_LEN 5
validate_comname (comname);
+ /* Look it up, and verify that we got an exact match. */
c = lookup_cmd (&tem, cmdlist, "", -1, 1);
+ if (c && !STREQ (comname, c->name))
+ c = 0;
+
if (c)
{
if (c->class == class_user || c->class == class_alias)
tem = "Redefine command \"%s\"? ";
else
tem = "Really redefine built-in command \"%s\"? ";
- if (!query (tem, comname))
- error ("Command \"%s\" not redefined.", comname);
+ if (!query (tem, c->name))
+ error ("Command \"%s\" not redefined.", c->name);
}
+ /* If this new command is a hook, then mark the command which it
+ is hooking. Note that we allow hooking `help' commands, so that
+ we can hook the `stop' pseudo-command. */
+
+ if (!strncmp (comname, HOOK_STRING, HOOK_LEN))
+ {
+ /* Look up cmd it hooks, and verify that we got an exact match. */
+ tem = comname+HOOK_LEN;
+ hookc = lookup_cmd (&tem, cmdlist, "", -1, 0);
+ if (hookc && !STREQ (comname+HOOK_LEN, hookc->name))
+ hookc = 0;
+ if (!hookc)
+ {
+ warning ("Your new `%s' command does not hook any existing command.",
+ comname);
+ if (!query ("Proceed? ", (char *)0))
+ error ("Not confirmed.");
+ }
+ }
+
+ comname = savestring (comname, strlen (comname));
+
+ /* If the rest of the commands will be case insensitive, this one
+ should behave in the same manner. */
+ for (tem = comname; *tem; tem++)
+ if (isupper(*tem)) *tem = tolower(*tem);
+
if (from_tty)
{
printf ("Type commands for definition of \"%s\".\n\
End with a line saying just \"end\".\n", comname);
fflush (stdout);
}
- comname = savestring (comname, strlen (comname));
cmds = read_command_lines ();
if (c && c->class == class_user)
free_command_lines (&c->user_commands);
- newc = add_cmd (comname, class_user, not_just_help_class_command,
+ newc = add_cmd (comname, class_user, user_defined_command,
(c && c->class == class_user)
? c->doc : savestring ("User-defined.", 13), &cmdlist);
newc->user_commands = cmds;
+
+ /* If this new command is a hook, then mark both commands as being
+ tied. */
+ if (hookc)
+ {
+ hookc->hook = newc; /* Target gets hooked. */
+ newc->hookee = hookc; /* We are marked as hooking target cmd. */
+ }
}
static void
}
\f
static void
-print_gdb_version (shout)
- int shout;
+print_gnu_advertisement()
{
- printf ("GDB %s, Copyright (C) 1991 Free Software Foundation, Inc.\n",
- version);
- if (shout)
printf ("\
-There is ABSOLUTELY NO WARRANTY for GDB; type \"info warranty\" for details.\n\
GDB is free software and you are welcome to distribute copies of it\n\
- under certain conditions; type \"info copying\" to see the conditions.\n");
+ under certain conditions; type \"show copying\" to see the conditions.\n\
+There is absolutely no warranty for GDB; type \"show warranty\" for details.\n\
+");
+}
+
+static void
+print_gdb_version (stream)
+ FILE *stream;
+{
+ fprintf_filtered (stream, "\
+GDB %s (%s", version, host_canonical);
+
+ if (strcmp(host_canonical, target_canonical))
+ fprintf_filtered (stream, " --target %s", target_canonical);
+
+ fprintf_filtered (stream, "), ");
+ wrap_here("");
+ fprintf_filtered (stream, "Copyright 1993 Free Software Foundation, Inc.");
}
+/* ARGSUSED */
static void
show_version (args, from_tty)
char *args;
int from_tty;
{
immediate_quit++;
- print_gdb_version (0);
+ print_gnu_advertisement ();
+ print_gdb_version (stdout);
+ printf_filtered ("\n");
immediate_quit--;
}
\f
{
if (inferior_pid != 0 && target_has_execution)
{
- if (query ("The program is running. Quit anyway? "))
+ if (attach_flag)
{
- target_kill (args, from_tty);
+ if (query ("The program is running. Quit anyway (and detach it)? "))
+ target_detach (args, from_tty);
+ else
+ error ("Not confirmed.");
}
else
- error ("Not confirmed.");
+ {
+ if (query ("The program is running. Quit anyway (and kill it)? "))
+ target_kill ();
+ else
+ error ("Not confirmed.");
+ }
}
/* Save the history information if it is appropriate to do so. */
if (write_history_p && history_filename)
exit (0);
}
+/* Returns whether GDB is running on a terminal and whether the user
+ desires that questions be asked of them on that terminal. */
+
int
input_from_terminal_p ()
{
- return (instream == stdin) & caution;
+ return gdb_has_a_terminal && (instream == stdin) & caution;
}
\f
+/* ARGSUSED */
static void
pwd_command (args, from_tty)
char *args;
int from_tty;
{
if (args) error ("The \"pwd\" command does not take an argument: %s", args);
- getwd (dirbuf);
+ getcwd (dirbuf, sizeof (dirbuf));
- if (strcmp (dirbuf, current_directory))
+ if (!STREQ (dirbuf, current_directory))
printf ("Working directory %s\n (canonically %s).\n",
current_directory, dirbuf);
else
dir = tilde_expand (dir);
make_cleanup (free, dir);
+ if (chdir (dir) < 0)
+ perror_with_name (dir);
+
len = strlen (dir);
dir = savestring (dir, len - (len > 1 && dir[len-1] == '/'));
if (dir[0] == '/')
current_directory = dir;
else
{
- current_directory = concat (current_directory, "/", dir);
+ current_directory = concat (current_directory, "/", dir, NULL);
free (dir);
}
}
}
- if (chdir (dir) < 0)
- perror_with_name (dir);
-
forget_cached_source_info ();
if (from_tty)
pwd_command ((char *) 0, 1);
}
\f
+/* ARGSUSED */
static void
source_command (args, from_tty)
char *args;
struct cleanup *cleanups;
char *file = args;
- if (file == 0)
- /* Let source without arguments read .gdbinit. */
- file = gdbinit;
+ if (file == NULL)
+ {
+ error ("source command requires pathname of file to source.");
+ }
file = tilde_expand (file);
make_cleanup (free, file);
- stream = fopen (file, "r");
+ stream = fopen (file, FOPEN_RT);
if (stream == 0)
perror_with_name (file);
register int c;
if (text)
- while (c = *p++)
+ while ((c = *p++) != '\0')
{
if (c == '\\')
{
c = parse_escape (&p);
if (c >= 0)
- fputc (c, stdout);
+ printf_filtered ("%c", c);
}
else
- fputc (c, stdout);
+ printf_filtered ("%c", c);
}
+
+ /* Force this output to appear now. */
+ wrap_here ("");
fflush (stdout);
}
-/* ARGSUSED */
-static void
-dump_me_command (args, from_tty)
- char *args;
- int from_tty;
-{
- if (query ("Should GDB dump core? "))
- {
- signal (SIGQUIT, SIG_DFL);
- kill (getpid (), SIGQUIT);
- }
-}
\f
/* Functions to manipulate command line editing control variables. */
than the number of the last command). Relative to history_base. */
int hist_len;
- struct _hist_entry *history_get();
+ extern struct _hist_entry *history_get PARAMS ((int));
extern int history_base;
-#if 0
- /* This is all reported by individual "show" commands. */
- printf_filtered ("Interactive command editing is %s.\n",
- command_editing_p ? "on" : "off");
-
- printf_filtered ("History expansion of command input is %s.\n",
- history_expansion_p ? "on" : "off");
- printf_filtered ("Writing of a history record upon exit is %s.\n",
- write_history_p ? "enabled" : "disabled");
- printf_filtered ("The size of the history list (number of stored commands) is %d.\n",
- history_size);
- printf_filtered ("The name of the history record is \"%s\".\n\n",
- history_filename ? history_filename : "");
-#endif /* 0 */
-
/* Print out some of the commands from the command history. */
/* First determine the length of the history list. */
hist_len = history_size;
/* "info editing <exp>" should print around command number <exp>. */
num = (parse_and_eval_address (args) - history_base) - Hist_print / 2;
}
- /* "info editing" means print the last Hist_print commands. */
+ /* "show commands" means print the last Hist_print commands. */
else
{
num = hist_len - Hist_print;
num = 0;
}
-#if 0
- /* No need for a header now that "info editing" only prints one thing. */
- if (num == hist_len - Hist_print)
- printf_filtered ("The list of the last %d commands is:\n\n", Hist_print);
- else
- printf_filtered ("Some of the stored commands are:\n\n");
-#endif /* 0 */
-
for (offset = num; offset < num + Hist_print && offset < hist_len; offset++)
{
printf_filtered ("%5d %s\n", history_base + offset,
num += Hist_print;
/* If the user repeats this command with return, it should do what
- "info editing +" does. This is unnecessary if arg is null,
- because "info editing +" is not useful after "info editing". */
+ "show commands +" does. This is unnecessary if arg is null,
+ because "show commands +" is not useful after "show commands". */
if (from_tty && args)
{
args[0] = '+';
}
/* Called by do_setshow_command. */
+/* ARGSUSED */
static void
set_history_size_command (args, from_tty, c)
char *args;
int from_tty;
struct cmd_list_element *c;
{
- if (history_size == UINT_MAX)
+ if (history_size == INT_MAX)
unstifle_history ();
- else
+ else if (history_size >= 0)
stifle_history (history_size);
+ else
+ {
+ history_size = INT_MAX;
+ error ("History size must be non-negative");
+ }
}
+/* ARGSUSED */
static void
set_history (args, from_tty)
char *args;
help_list (sethistlist, "set history ", -1, stdout);
}
+/* ARGSUSED */
static void
show_history (args, from_tty)
char *args;
int info_verbose = 0; /* Default verbose msgs off */
/* Called by do_setshow_command. An elaborate joke. */
+/* ARGSUSED */
static void
set_verbose (args, from_tty, c)
char *args;
}
static void
-float_handler ()
+float_handler (signo)
+int signo;
{
/* This message is based on ANSI C, section 4.7. Note that integer
divide by zero causes this, so "float" is a misnomer. */
+ signal (SIGFPE, float_handler);
error ("Erroneous arithmetic operation.");
}
static void
initialize_cmd_lists ()
{
- cmdlist = (struct cmd_list_element *) 0;
- infolist = (struct cmd_list_element *) 0;
- enablelist = (struct cmd_list_element *) 0;
- disablelist = (struct cmd_list_element *) 0;
- deletelist = (struct cmd_list_element *) 0;
- enablebreaklist = (struct cmd_list_element *) 0;
- setlist = (struct cmd_list_element *) 0;
+ cmdlist = NULL;
+ infolist = NULL;
+ enablelist = NULL;
+ disablelist = NULL;
+ deletelist = NULL;
+ enablebreaklist = NULL;
+ setlist = NULL;
+ unsetlist = NULL;
showlist = NULL;
- sethistlist = (struct cmd_list_element *) 0;
+ sethistlist = NULL;
showhistlist = NULL;
- unsethistlist = (struct cmd_list_element *) 0;
+ unsethistlist = NULL;
+#if MAINTENANCE_CMDS
+ maintenancelist = NULL;
+ maintenanceinfolist = NULL;
+ maintenanceprintlist = NULL;
+#endif
+ setprintlist = NULL;
+ showprintlist = NULL;
+ setchecklist = NULL;
+ showchecklist = NULL;
+}
+
+/* Init the history buffer. Note that we are called after the init file(s)
+ * have been read so that the user can change the history file via his
+ * .gdbinit file (for instance). The GDBHISTFILE environment variable
+ * overrides all of this.
+ */
+
+static void
+initialize_history()
+{
+ char *tmpenv;
+
+ tmpenv = getenv ("HISTSIZE");
+ if (tmpenv)
+ history_size = atoi (tmpenv);
+ else if (!history_size)
+ history_size = 256;
+
+ stifle_history (history_size);
+
+ tmpenv = getenv ("GDBHISTFILE");
+ if (tmpenv)
+ history_filename = savestring (tmpenv, strlen(tmpenv));
+ else if (!history_filename) {
+ /* We include the current directory so that if the user changes
+ directories the file written will be the same as the one
+ that was read. */
+ history_filename = concat (current_directory, "/.gdb_history", NULL);
+ }
+ read_history (history_filename);
}
static void
{
struct cmd_list_element *c;
- char *tmpenv;
-
#ifdef DEFAULT_PROMPT
prompt = savestring (DEFAULT_PROMPT, strlen(DEFAULT_PROMPT));
#else
history_expansion_p = 0;
write_history_p = 0;
- if (tmpenv = getenv ("HISTSIZE"))
- history_size = atoi (tmpenv);
- else
- history_size = 256;
-
- stifle_history (history_size);
-
- if (tmpenv = getenv ("GDBHISTFILE"))
- history_filename = savestring (tmpenv, strlen(tmpenv));
- else
- /* We include the current directory so that if the user changes
- directories the file written will be the same as the one
- that was read. */
- history_filename = concat (current_directory, "/.gdb_history", "");
-
- read_history (history_filename);
-
/* Setup important stuff for command line editing. */
rl_completion_entry_function = (int (*)()) symbol_completion_function;
rl_completer_word_break_characters = gdb_completer_word_break_characters;
+ rl_completer_quote_characters = gdb_completer_quote_characters;
rl_readline_name = "gdb";
/* Define the classes of commands.
They will appear in the help list in the reverse of this order. */
+ add_cmd ("internals", class_maintenance, NO_FUNCTION,
+ "Maintenance commands.\n\
+Some gdb commands are provided just for use by gdb maintainers.\n\
+These commands are subject to frequent change, and may not be as\n\
+well documented as user commands.",
+ &cmdlist);
add_cmd ("obscure", class_obscure, NO_FUNCTION, "Obscure features.", &cmdlist);
add_cmd ("aliases", class_alias, NO_FUNCTION, "Aliases of other commands.", &cmdlist);
add_cmd ("user-defined", class_user, NO_FUNCTION, "User-defined commands.\n\
add_com ("pwd", class_files, pwd_command,
"Print working directory. This is used for your program as well.");
- add_com ("cd", class_files, cd_command,
+ c = add_cmd ("cd", class_files, cd_command,
"Set working directory to DIR for debugger and program being debugged.\n\
The change does not take effect for the program being debugged\n\
-until the next time it is started.");
+until the next time it is started.", &cmdlist);
+ c->completer = filename_completer;
add_show_from_set
(add_set_cmd ("prompt", class_support, var_string, (char *)&prompt,
Commands defined in this way do not take arguments.");
#ifdef __STDC__
- add_com ("source", class_support, source_command,
+ c = add_cmd ("source", class_support, source_command,
"Read commands from a file named FILE.\n\
Note that the file \"" GDBINIT_FILENAME "\" is read automatically in this way\n\
-when gdb is started.");
+when gdb is started.", &cmdlist);
#else
/* Punt file name, we can't help it easily. */
- add_com ("source", class_support, source_command,
+ c = add_cmd ("source", class_support, source_command,
"Read commands from a file named FILE.\n\
Note that the file \".gdbinit\" is read automatically in this way\n\
-when gdb is started.");
+when gdb is started.", &cmdlist);
#endif
+ c->completer = filename_completer;
add_com ("quit", class_support, quit_command, "Exit gdb.");
add_com ("help", class_support, help_command, "Print list of commands.");
"Set ",
&setlist),
add_show_from_set (c, &showlist);
- c->function = set_verbose;
+ c->function.sfunc = set_verbose;
set_verbose (NULL, 0, c);
- add_com ("dump-me", class_obscure, dump_me_command,
- "Get fatal error; make debugger dump its core.");
-
add_show_from_set
(add_set_cmd ("editing", class_support, var_boolean, (char *)&command_editing_p,
- "Set command line editing.\n\
+ "Set editing of command lines as they are typed.\n\
Use \"on\" to enable to enable the editing, and \"off\" to disable it.\n\
-Without an argument, command line editing is enabled.", &setlist),
+Without an argument, command line editing is enabled. To edit, use\n\
+EMACS-like or VI-like commands like control-P or ESC.", &setlist),
&showlist);
add_prefix_cmd ("history", class_support, set_history,
Without an argument, saving is enabled.", &sethistlist),
&showhistlist);
- c = add_set_cmd ("size", no_class, var_uinteger, (char *)&history_size,
+ c = add_set_cmd ("size", no_class, var_integer, (char *)&history_size,
"Set the size of the command history, \n\
ie. the number of previous commands to keep a record of.", &sethistlist);
add_show_from_set (c, &showhistlist);
- c->function = set_history_size_command;
+ c->function.sfunc = set_history_size_command;
add_show_from_set
(add_set_cmd ("filename", no_class, var_filename, (char *)&history_filename,
&showlist);
add_prefix_cmd ("info", class_info, info_command,
- "Generic command for printing status.",
+ "Generic command for showing things about the program being debugged.",
&infolist, "info ", 0, &cmdlist);
add_com_alias ("i", "info", class_info, 1);
add_prefix_cmd ("show", class_info, show_command,
- "Generic command for showing things set with \"set\".",
+ "Generic command for showing things about the debugger.",
&showlist, "show ", 0, &cmdlist);
/* Another way to get at the same thing. */
add_info ("set", show_command, "Show all GDB settings.");
- add_cmd ("commands", no_class, show_commands, "Status of command editor.",
+ add_cmd ("commands", no_class, show_commands,
+ "Show the 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,
- "Report what version of GDB this is.", &showlist);
+ "Show what version of GDB this is.", &showlist);
}