aboutsummaryrefslogtreecommitdiff
path: root/gdb/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/main.c')
-rw-r--r--gdb/main.c1126
1 files changed, 830 insertions, 296 deletions
diff --git a/gdb/main.c b/gdb/main.c
index 5cd5e80..ee923c4 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -1,22 +1,22 @@
/* Top level for GDB, the GNU debugger.
- Copyright (C) 1986, 1987, 1988 Free Software Foundation, Inc.
-
-GDB is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY. No author or distributor accepts responsibility to anyone
-for the consequences of using it or for whether it serves any
-particular purpose or works at all, unless he says so in writing.
-Refer to the GDB General Public License for full details.
-
-Everyone is granted permission to copy, modify and redistribute GDB,
-but only under the conditions described in the GDB General Public
-License. A copy of this license is supposed to have been given to you
-along with GDB so you can know your rights and responsibilities. It
-should be in a file named COPYING. Among other things, the copyright
-notice and this notice must be preserved on all copies.
-
-In other words, go ahead and share GDB, but don't try to stop
-anyone else from sharing it farther. Help stamp out software hoarding!
-*/
+ Copyright (C) 1986, 1987, 1988, 1989 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+GDB 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.
+
+GDB 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. */
+
#include "defs.h"
#include "command.h"
#include "param.h"
@@ -31,14 +31,24 @@ anyone else from sharing it farther. Help stamp out software hoarding!
#include <setjmp.h>
#include <signal.h>
#include <sys/param.h>
+#include <sys/stat.h>
#ifdef SET_STACK_LIMIT_HUGE
#include <sys/time.h>
#include <sys/resource.h>
+#include <ctype.h>
int original_stack_limit;
#endif
+/* If this definition isn't overridden by the header files, assume
+ that isatty and fileno exist on this system. */
+#ifndef ISATTY
+#define ISATTY(FP) (isatty (fileno (FP)))
+#endif
+
+extern void free ();
+
/* Version number of GDB, as a string. */
extern char *version;
@@ -75,6 +85,14 @@ struct cmd_list_element *enablebreaklist;
struct cmd_list_element *setlist;
+/* Chain containing all defined \"set history\". */
+
+struct cmd_list_element *sethistlist;
+
+/* Chain containing all defined \"unset history\". */
+
+struct cmd_list_element *unsethistlist;
+
/* stdio stream that command input is being read from. */
FILE *instream;
@@ -86,6 +104,10 @@ char *current_directory;
/* The directory name is actually stored here (usually). */
static char dirbuf[MAXPATHLEN];
+/* The number of lines on a page, and the number of spaces
+ in a line. */
+int linesize, pagesize;
+
/* Nonzero if we should refrain from using an X window. */
int inhibit_windows = 0;
@@ -97,14 +119,20 @@ int inhibit_windows = 0;
void (*window_hook) ();
extern int frame_file_full_name;
+int xgdb_verbose;
void free_command_lines ();
-char *gdb_read_line ();
-static void init_main ();
-static void init_cmd_lists ();
+char *gdb_readline ();
+char *command_line_input ();
+static void initialize_main ();
+static void initialize_cmd_lists ();
void command_loop ();
static void source_command ();
static void print_gdb_version ();
+static void float_handler ();
+static void cd_command ();
+
+char *getenv ();
/* gdb prints this when reading a command interactively */
static char *prompt;
@@ -114,6 +142,15 @@ static char *prompt;
char *line;
int linesize;
+
+
+/* Signal to catch ^Z typed while reading a command: SIGTSTP or SIGCONT. */
+
+#ifndef STOP_SIGNAL
+#ifdef SIGTSTP
+#define STOP_SIGNAL SIGTSTP
+#endif
+#endif
/* This is how `error' returns to command level. */
@@ -126,7 +163,7 @@ return_to_top_level ()
immediate_quit = 0;
clear_breakpoint_commands ();
clear_momentary_breakpoints ();
- delete_current_display ();
+ disable_current_display ();
do_cleanups (0);
longjmp (to_top_level, 1);
}
@@ -196,7 +233,6 @@ main (argc, argv, envp)
char **argv;
char **envp;
{
- extern void request_quit ();
int count;
int inhibit_gdbinit = 0;
int quiet = 0;
@@ -238,20 +274,18 @@ main (argc, argv, envp)
batch = 1, quiet = 1;
else if (!strcmp (argv[i], "-fullname"))
frame_file_full_name = 1;
+ else if (!strcmp (argv[i], "-xgdb_verbose"))
+ xgdb_verbose = 1;
else if (argv[i][0] == '-')
i++;
}
/* Run the init function of each source file */
- init_cmd_lists (); /* This needs to be done first */
- init_all_files ();
- init_main (); /* But that omits this file! Do it now */
-
- signal (SIGINT, request_quit);
- signal (SIGQUIT, SIG_IGN);
- if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
- signal (SIGHUP, disconnect);
+ initialize_cmd_lists (); /* This needs to be done first */
+ initialize_all_files ();
+ initialize_main (); /* But that omits this file! Do it now */
+ initialize_signals ();
if (!quiet)
print_gdb_version ();
@@ -272,7 +306,8 @@ main (argc, argv, envp)
if (!strcmp (arg, "-q") || !strcmp (arg, "-nx")
|| !strcmp (arg, "-quiet") || !strcmp (arg, "-batch")
- || !strcmp (arg, "-fullname"))
+ || !strcmp (arg, "-fullname") || !strcmp (arg, "-nw")
+ || !strcmp (arg, "-xgdb_verbose"))
/* Already processed above */
continue;
@@ -306,11 +341,7 @@ main (argc, argv, envp)
GDB remembers the precise string FOO as the dirname. */
else if (!strcmp (arg, "-cd"))
{
- int len = strlen (argv[i]);
- current_directory = argv[i];
- if (len > 1 && current_directory[len - 1] == '/')
- current_directory = savestring (current_directory, len-1);
- chdir (current_directory);
+ cd_command (argv[i], 0);
init_source_path ();
}
/* -t /def/ttyp1: use /dev/ttyp1 for inferior I/O. */
@@ -345,25 +376,54 @@ main (argc, argv, envp)
}
}
- /* Read init file, if it exists in home directory */
- if (getenv ("HOME"))
- {
- char *s;
- s = (char *) xmalloc (strlen (getenv ("HOME")) + 10);
- strcpy (s, getenv ("HOME"));
- strcat (s, "/.gdbinit");
- if (!inhibit_gdbinit && access (s, R_OK) == 0)
- if (!setjmp (to_top_level))
- source_command (s);
- }
+ {
+ struct stat homebuf, cwdbuf;
+ char *homedir, *homeinit;
- /* Read init file, if it exists in current directory. */
- if (!inhibit_gdbinit && access (".gdbinit", R_OK) == 0)
- if (!setjmp (to_top_level))
- source_command (".gdbinit");
+ /* Read init file, if it exists in home directory */
+ homedir = getenv ("HOME");
+ if (homedir)
+ {
+ homeinit = (char *) alloca (strlen (getenv ("HOME")) + 10);
+ strcpy (homeinit, getenv ("HOME"));
+ strcat (homeinit, "/.gdbinit");
+ if (!inhibit_gdbinit && access (homeinit, R_OK) == 0)
+ if (!setjmp (to_top_level))
+ source_command (homeinit);
+
+ /* 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 (guarantees that they
+ won't match if either exits). */
+
+ 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))
+ source_command (".gdbinit");
+ }
if (batch)
- fatal ("Attempt to read commands from stdin in batch mode.");
+ {
+#if 0
+ fatal ("Attempt to read commands from stdin in batch mode.");
+#endif
+ /* We have hit the end of the batch file. */
+ exit (0);
+ }
if (!quiet)
printf ("Type \"help\" for a list of commands.\n");
@@ -393,7 +453,7 @@ execute_command (p, from_tty)
while (*p == ' ' || *p == '\t') p++;
if (*p)
{
- c = lookup_cmd (&p, cmdlist, "", 0);
+ c = lookup_cmd (&p, cmdlist, "", 0, 1);
if (c->function == 0)
error ("That is not a command, just a help topic.");
else if (c->class == (int) class_user)
@@ -441,8 +501,10 @@ command_loop ()
(*window_hook) (instream, prompt);
quit_flag = 0;
+ if (instream == stdin && ISATTY (stdin))
+ reinitialize_more_filter ();
old_chain = make_cleanup (do_nothing, 0);
- execute_command (gdb_read_line (instream == stdin ? prompt : 0,
+ execute_command (command_line_input (instream == stdin ? prompt : 0,
instream == stdin),
instream == stdin);
/* Do any commands attached to breakpoint we stopped at. */
@@ -451,102 +513,448 @@ command_loop ()
}
}
-#ifdef SIGTSTP
+/* Commands call this if they do not want to be repeated by null lines. */
+
+void
+dont_repeat ()
+{
+ /* If we aren't reading from standard input, we are saving the last
+ thing read from stdin in line and don't want to delete it. Null lines
+ won't repeat here in any case. */
+ if (instream == stdin)
+ *line = 0;
+}
+
+/* Read a line from the stream "instream" without command line editing.
+
+ It prints PROMPT once at the start.
+
+ 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. */
+char *
+gdb_readline (prompt, return_result)
+ char *prompt;
+ int return_result;
+{
+ int c;
+ char *result;
+ int input_index = 0;
+ int result_size = 80;
+
+ if (prompt)
+ {
+ printf (prompt);
+ fflush (stdout);
+ }
+
+ if (return_result)
+ result = (char *) xmalloc (result_size);
+
+ while (1)
+ {
+ c = fgetc (instream);
+ if (c == -1 || c == '\n')
+ break;
+ if (return_result)
+ {
+ result[input_index++] = c;
+ while (input_index >= result_size)
+ {
+ result_size *= 2;
+ result = (char *) xrealloc (result, result_size);
+ }
+ }
+ }
+ if (return_result)
+ {
+ result[input_index++] = '\0';
+ return result;
+ }
+ else
+ return (char *) 0;
+}
+
+/* Declaration for fancy readline with command line editing. */
+char *readline ();
+
+/* Variables which control command line editing and history
+ substitution. These variables are given default values at the end
+ of this file. */
+static int command_editing_p;
+static int history_expansion_p;
+static int write_history_p;
+static int history_size;
+static char *history_filename;
+
+/* Variables which are necessary for fancy command line editing. */
+char *gdb_completer_word_break_characters =
+ " \t\n!@#$%^&*()-+=|~`}{[]\"';:?/>.<,";
+
+/* Functions that are used as part of the fancy command line editing. */
+
+/* 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. */
+char *
+symbol_completion_function (text, state)
+ char *text;
+ int state;
+{
+ char **make_symbol_completion_list ();
+ static char **list = (char **)NULL;
+ static int index;
+ char *output;
+ extern char *rl_line_buffer;
+ extern int rl_point;
+ char *tmp_command, *p;
+ struct cmd_list_element *c, *result_list;
+
+ if (!state)
+ {
+ /* Free the storage used by LIST, but not by the strings inside. This is
+ because rl_complete_internal () frees the strings. */
+ if (list)
+ free (list);
+ list = 0;
+ index = 0;
+
+ /* Decide whether to complete on a list of gdb commands or on
+ symbols. */
+ tmp_command = (char *) alloca (rl_point + 1);
+ p = tmp_command;
+
+ strncpy (tmp_command, rl_line_buffer, rl_point);
+ tmp_command[rl_point] = '\0';
+
+ if (rl_point == 0)
+ {
+ /* 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);
+
+ /* Move p up to the next interesting thing. */
+ while (*p == ' ' || *p == '\t')
+ p++;
+
+ if (!c)
+ /* He's typed something unrecognizable. Sigh. */
+ list = (char **) 0;
+ else if (c == (struct cmd_list_element *) -1)
+ {
+ if (p + strlen(text) != tmp_command + rl_point)
+ error ("Unrecognized command.");
+
+ /* He's typed something ambiguous. This is easier. */
+ if (result_list)
+ list = complete_on_cmdlist (*result_list->prefixlist, text);
+ else
+ list = complete_on_cmdlist (cmdlist, text);
+ }
+ else
+ {
+ /* If we've gotten this far, gdb has recognized a full
+ command. There are several possibilities:
+
+ 1) We need to complete on the command.
+ 2) We need to complete on the possibilities coming after
+ the command.
+ 2) We need to complete the text of what comes after the
+ command. */
+
+ if (!*p && *text)
+ /* Always (might be longer versions of thie command). */
+ list = complete_on_cmdlist (result_list, text);
+ else if (!*p && !*text)
+ {
+ if (c->prefixlist)
+ list = complete_on_cmdlist (*c->prefixlist, "");
+ else
+ list = make_symbol_completion_list ("");
+ }
+ else
+ {
+ if (c->prefixlist && !c->allow_unknown)
+ {
+ *p = '\0';
+ error ("\"%s\" command requires a subcommand.",
+ tmp_command);
+ }
+ else
+ list = make_symbol_completion_list (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);
+
+ output = list[index];
+ if (output)
+ index++;
+
+ return (output);
+}
+
+#ifdef STOP_SIGNAL
static void
stop_sig ()
{
+#if STOP_SIGNAL == SIGTSTP
signal (SIGTSTP, SIG_DFL);
sigsetmask (0);
kill (getpid (), SIGTSTP);
signal (SIGTSTP, stop_sig);
+#else
+ signal (STOP_SIGNAL, stop_sig);
+#endif
printf ("%s", prompt);
fflush (stdout);
/* Forget about any previous command -- null line now will do nothing. */
- *line = 0;
+ dont_repeat ();
}
-#endif /* SIGTSTP */
+#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
+ };
-/* Commands call this if they do not want to be repeated by null lines. */
+#define TERMSIGS_LENGTH (sizeof (terminating_signals) / sizeof (int))
-void
-dont_repeat ()
+static void
+catch_termination (sig)
+ int sig;
{
- *line = 0;
+ /* 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. */
+initialize_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
+ GDB process as well as the inferior (the signal handling tables
+ being shared between the two, apparently). 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);
+}
+
/* Read one line from the command input stream `instream'
- into the buffer `line' (whose current length is `linesize').
+ into the local static buffer `linebuffer' (whose current length
+ is `linelength').
The buffer is made bigger as necessary.
- Returns the address of the start of the line. */
+ Returns the address of the start of the line.
+
+ *If* the instream == stdin & stdin is a terminal, the line read
+ is copied into the file line saver (global var char *line,
+ length linesize) so that it can be duplicated.
+
+ This routine either uses fancy command line editing or
+ simple input as the user has requested. */
char *
-gdb_read_line (prompt, repeat)
+command_line_input (prompt, repeat)
char *prompt;
int repeat;
{
- register char *p = line;
- register char *p1;
+ static char *linebuffer = 0;
+ static int linelength = 0;
+ register char *p;
+ register char *p1, *rl;
+ char *local_prompt = prompt;
register int c;
char *nline;
+ if (linebuffer == 0)
+ {
+ linelength = 80;
+ linebuffer = (char *) xmalloc (linelength);
+ }
+
+ p = linebuffer;
+
/* Control-C quits instantly if typed while in this loop
since it should not wait until the user types a newline. */
immediate_quit++;
-#ifdef SIGTSTP
- signal (SIGTSTP, stop_sig);
+#ifdef STOP_SIGNAL
+ signal (STOP_SIGNAL, stop_sig);
#endif
- if (prompt)
- {
- printf (prompt);
- fflush (stdout);
- }
-
while (1)
{
- c = fgetc (instream);
- if (c == -1 || c == '\n')
- break;
- /* Ignore backslash-newline; keep adding to the same line. */
- else if (c == '\\')
- {
- int c1 = fgetc (instream);
- if (c1 == '\n')
- continue;
- else
- ungetc (c1, instream);
- }
+ /* 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);
- if (p - line == linesize - 1)
+ if (!rl || rl == (char *) EOF) break;
+ if (strlen(rl) + 1 + (p - linebuffer) > linelength)
{
- linesize *= 2;
- nline = (char *) xrealloc (line, linesize);
- p += nline - line;
- line = nline;
+ linelength = strlen(rl) + 1 + (p - linebuffer);
+ nline = (char *) xrealloc (linebuffer, linelength);
+ p += nline - linebuffer;
+ linebuffer = nline;
}
- *p++ = c;
- }
+ p1 = rl;
+ /* Copy line. Don't copy null at end. (Leaves line alone
+ if this was just a newline) */
+ while (*p1)
+ *p++ = *p1++;
-#ifdef SIGTSTP
+ free (rl); /* Allocated in readline. */
+
+ if (p == linebuffer || *(p - 1) != '\\')
+ break;
+
+ p--; /* Put on top of '\'. */
+ local_prompt = (char *) 0;
+ }
+
+#ifdef STOP_SIGNAL
signal (SIGTSTP, SIG_DFL);
#endif
immediate_quit--;
+ /* Do history expansion if that is wished. */
+ if (history_expansion_p && instream == stdin
+ && ISATTY (instream))
+ {
+ char *history_value;
+ int expanded;
+
+ *p = '\0'; /* Insert null now. */
+ expanded = history_expand (linebuffer, &history_value);
+ if (expanded)
+ {
+ /* Print the changes. */
+ printf ("%s\n", history_value);
+
+ /* If there was an error, call this function again. */
+ if (expanded < 0)
+ {
+ free (history_value);
+ return command_line_input (prompt, repeat);
+ }
+ if (strlen (history_value) > linelength)
+ {
+ linelength = strlen (history_value) + 1;
+ linebuffer = (char *) xrealloc (linebuffer, linelength);
+ }
+ strcpy (linebuffer, history_value);
+ p = linebuffer + strlen(linebuffer);
+ free (history_value);
+ }
+ }
+
/* If we just got an empty line, and that is supposed
- to repeat the previous command, leave the last input unchanged. */
- if (p == line && repeat)
- return line;
+ to repeat the previous command, return the value in the
+ global buffer. */
+ if (repeat)
+ {
+ if (p == linebuffer)
+ return line;
+ p1 = linebuffer;
+ while (*p1 == ' ' || *p1 == '\t')
+ p1++;
+ if (!*p1)
+ return line;
+ }
+
+ *p = 0;
+
+ /* Add line to history if appropriate. */
+ if (instream == stdin
+ && ISATTY (stdin) && *linebuffer)
+ add_history (linebuffer);
/* If line is a comment, clear it out. */
- p1 = line;
+ /* Note: comments are added to the command history.
+ This is useful when you type a command, and then realize
+ you don't want to execute it quite yet. You can comment out the
+ command and then later fetch it from the value history and
+ remove the '#'. */
+ p1 = linebuffer;
while ((c = *p1) == ' ' || c == '\t') p1++;
if (c == '#')
- p = line;
+ *linebuffer = 0;
- *p = 0;
+ /* Save into global buffer if appropriate. */
+ if (repeat)
+ {
+ if (linelength > linesize)
+ {
+ line = xrealloc (line, linelength);
+ linesize = linelength;
+ }
+ strcpy (line, linebuffer);
+ return line;
+ }
- return line;
+ return linebuffer;
}
/* Read lines from the input stream
@@ -564,7 +972,7 @@ read_command_lines ()
while (1)
{
dont_repeat ();
- p = gdb_read_line (0, 1);
+ p = command_line_input (0, instream == stdin);
/* Remove leading and trailing blanks. */
while (*p == ' ' || *p == '\t') p++;
p1 = p + strlen (p);
@@ -723,7 +1131,7 @@ define_command (comname, from_tty)
validate_comname (comname);
- c = lookup_cmd (&tem, cmdlist, "", -1);
+ c = lookup_cmd (&tem, cmdlist, "", -1, 1);
if (c)
{
if (c->class == (int) class_user || c->class == (int) class_alias)
@@ -763,7 +1171,7 @@ document_command (comname, from_tty)
validate_comname (comname);
- c = lookup_cmd (&tem, cmdlist, "", 0);
+ c = lookup_cmd (&tem, cmdlist, "", 0, 1);
if (c->class != (int) class_user)
error ("Command \"%s\" is built-in.", comname);
@@ -798,192 +1206,9 @@ End with a line saying just \"end\".\n", comname);
}
static void
-copying_info ()
-{
- immediate_quit++;
- printf (" GDB GENERAL PUBLIC LICENSE\n\
- (Clarified 11 Feb 1988)\n\
-\n\
- Copyright (C) 1988 Richard M. Stallman\n\
- Everyone is permitted to copy and distribute verbatim copies\n\
- of this license, but changing it is not allowed.\n\
- You can also use this wording to make the terms for other programs.\n\
-\n\
- The license agreements of most software companies keep you at the\n\
-mercy of those companies. By contrast, our general public license is\n\
-intended to give everyone the right to share GDB. To make sure that\n\
-you get the rights we want you to have, we need to make restrictions\n\
-that forbid anyone to deny you these rights or to ask you to surrender\n\
-the rights. Hence this license agreement.\n\
-\n\
- Specifically, we want to make sure that you have the right to give\n\
-away copies of GDB, that you receive source code or else can get it\n\
-if you want it, that you can change GDB or use pieces of it in new\n\
-free programs, and that you know you can do these things.\n\
---Type Return to print more--");
- fflush (stdout);
- gdb_read_line (0, 0);
-
- printf ("\
- To make sure that everyone has such rights, we have to forbid you to\n\
-deprive anyone else of these rights. For example, if you distribute\n\
-copies of GDB, you must give the recipients all the rights that you\n\
-have. You must make sure that they, too, receive or can get the\n\
-source code. And you must tell them their rights.\n\
-\n\
- Also, for our own protection, we must make certain that everyone\n\
-finds out that there is no warranty for GDB. If GDB is modified by\n\
-someone else and passed on, we want its recipients to know that what\n\
-they have is not what we distributed, so that any problems introduced\n\
-by others will not reflect on our reputation.\n\
-\n\
- Therefore we (Richard Stallman and the Free Software Foundation,\n\
-Inc.) make the following terms which say what you must do to be\n\
-allowed to distribute or change GDB.\n\
---Type Return to print more--");
- fflush (stdout);
- gdb_read_line (0, 0);
-
- printf ("\
- COPYING POLICIES\n\
-\n\
- 1. You may copy and distribute verbatim copies of GDB source code as\n\
-you receive it, in any medium, provided that you conspicuously and\n\
-appropriately publish on each copy a valid copyright notice \"Copyright\n\
-\(C) 1988 Free Software Foundation, Inc.\" (or with whatever year is\n\
-appropriate); keep intact the notices on all files that refer\n\
-to this License Agreement and to the absence of any warranty; and give\n\
-any other recipients of the GDB program a copy of this License\n\
-Agreement along with the program. You may charge a distribution fee\n\
-for the physical act of transferring a copy.\n\
-\n\
- 2. You may modify your copy or copies of GDB or any portion of it,\n\
-and copy and distribute such modifications under the terms of\n\
-Paragraph 1 above, provided that you also do the following:\n\
-\n\
- a) cause the modified files to carry prominent notices stating\n\
- that you changed the files and the date of any change; and\n\
---Type Return to print more--");
- fflush (stdout);
- gdb_read_line (0, 0);
-
- printf ("\
- b) cause the whole of any work that you distribute or publish,\n\
- that in whole or in part contains or is a derivative of GDB\n\
- or any part thereof, to be licensed to all third parties on terms\n\
- identical to those contained in this License Agreement (except that\n\
- you may choose to grant more extensive warranty protection to some\n\
- or all third parties, at your option).\n\
-\n");
- printf ("\
- c) if the modified program serves as a debugger, cause it\n\
- when started running in the simplest and usual way, to print\n\
- an announcement including a valid copyright notice\n\
- \"Copyright (C) 1988 Free Software Foundation, Inc.\" (or with\n\
- the year that is appropriate), saying that there is no warranty\n\
- (or else, saying that you provide a warranty) and that users may\n\
- redistribute the program under these conditions, and telling the user\n\
- how to view a copy of this License Agreement.\n\
-\n\
- d) You may charge a distribution fee for the physical act of\n\
- transferring a copy, and you may at your option offer warranty\n\
- protection in exchange for a fee.\n\
-\n\
-Mere aggregation of another unrelated program with this program (or its\n\
-derivative) on a volume of a storage or distribution medium does not bring\n\
-the other program under the scope of these terms.\n\
---Type Return to print more--");
- fflush (stdout);
- gdb_read_line (0, 0);
-
- printf ("\
- 3. You may copy and distribute GDB (or a portion or derivative of it,\n\
-under Paragraph 2) in object code or executable form under the terms of\n\
-Paragraphs 1 and 2 above provided that you also do one of the following:\n\
-\n\
- a) accompany it with the complete corresponding machine-readable\n\
- source code, which must be distributed under the terms of\n\
- Paragraphs 1 and 2 above; or,\n\
-\n\
- b) accompany it with a written offer, valid for at least three\n\
- years, to give any third party free (except for a nominal\n\
- shipping charge) a complete machine-readable copy of the\n\
- corresponding source code, to be distributed under the terms of\n\
- Paragraphs 1 and 2 above; or,\n\n");
-
- printf ("\
- c) accompany it with the information you received as to where the\n\
- corresponding source code may be obtained. (This alternative is\n\
- allowed only for noncommercial distribution and only if you\n\
- received the program in object code or executable form alone.)\n\
-\n\
-For an executable file, complete source code means all the source code for\n\
-all modules it contains; but, as a special exception, it need not include\n\
-source code for modules which are standard libraries that accompany the\n\
-operating system on which the executable file runs.\n\
---Type Return to print more--");
- fflush (stdout);
- gdb_read_line (0, 0);
-
- printf ("\
- 4. You may not copy, sublicense, distribute or transfer GDB\n\
-except as expressly provided under this License Agreement. Any attempt\n\
-otherwise to copy, sublicense, distribute or transfer GDB is void and\n\
-your rights to use the program under this License agreement shall be\n\
-automatically terminated. However, parties who have received computer\n\
-software programs from you with this License Agreement will not have\n\
-their licenses terminated so long as such parties remain in full compliance.\n\
-\n\
-");
- printf ("\
- 5. If you wish to incorporate parts of GDB into other free\n\
-programs whose distribution conditions are different, write to the Free\n\
-Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet\n\
-worked out a simple rule that can be stated here, but we will often permit\n\
-this. We will be guided by the two goals of preserving the free status of\n\
-all derivatives of our free software and of promoting the sharing and reuse\n\
-of software.\n\
-\n\
-In other words, go ahead and share GDB, but don't try to stop\n\
-anyone else from sharing it farther. Help stamp out software hoarding!\n\
-");
- immediate_quit--;
-}
-
-static void
-warranty_info ()
-{
- immediate_quit++;
- printf (" NO WARRANTY\n\
-\n\
- BECAUSE GDB IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY NO\n\
-WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT\n\
-WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,\n\
-RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE GDB \"AS IS\" WITHOUT\n\
-WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT\n\
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n\
-A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND\n\
-PERFORMANCE OF GDB IS WITH YOU. SHOULD GDB PROVE DEFECTIVE, YOU\n\
-ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n");
-
- printf ("\
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.\n\
-STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY\n\
-WHO MAY MODIFY AND REDISTRIBUTE GDB, BE LIABLE TO\n\
-YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR OTHER\n\
-SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR\n\
-INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA\n\
-BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR A\n\
-FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) GDB, EVEN\n\
-IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR FOR\n\
-ANY CLAIM BY ANY OTHER PARTY.\n");
- immediate_quit--;
-}
-
-static void
print_gdb_version ()
{
- printf ("GDB %s, Copyright (C) 1988 Free Software Foundation, Inc.\n\
+ printf ("GDB %s, Copyright (C) 1989 Free Software Foundation, Inc.\n\
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",
@@ -1062,6 +1287,9 @@ quit_command ()
else
error ("Not confirmed.");
}
+ /* Save the history information if it is appropriate to do so. */
+ if (write_history_p && history_filename)
+ write_history (history_filename);
exit (0);
}
@@ -1097,6 +1325,9 @@ cd_command (dir, from_tty)
if (dir == 0)
error_no_arg ("new working directory");
+ dir = tilde_expand (dir);
+ make_cleanup (free, dir);
+
len = strlen (dir);
dir = savestring (dir, len - (len > 1 && dir[len-1] == '/'));
if (dir[0] == '/')
@@ -1144,14 +1375,20 @@ cd_command (dir, from_tty)
}
static void
-source_command (file)
- char *file;
+source_command (arg, from_tty)
+ char *arg;
+ int from_tty;
{
FILE *stream;
struct cleanup *cleanups;
+ char *file = arg;
if (file == 0)
- error_no_arg ("file to read commands from");
+ /* Let source without arguments read .gdbinit. */
+ file = ".gdbinit";
+
+ file = tilde_expand (file);
+ make_cleanup (free, file);
stream = fopen (file, "r");
if (stream == 0)
@@ -1202,8 +1439,237 @@ dump_me_command ()
}
}
+int
+parse_binary_operation (caller, arg)
+ char *caller, *arg;
+{
+ int length;
+
+ if (!arg || !*arg)
+ return 1;
+
+ length = strlen (arg);
+
+ while (arg[length - 1] == ' ' || arg[length - 1] == '\t')
+ length--;
+
+ if (!strncmp (arg, "on", length)
+ || !strncmp (arg, "1", length)
+ || !strncmp (arg, "yes", length))
+ return 1;
+ else
+ if (!strncmp (arg, "off", length)
+ || !strncmp (arg, "0", length)
+ || !strncmp (arg, "no", length))
+ return 0;
+ else
+ error ("\"%s\" not given a binary valued argument.", caller);
+}
+
+/* Functions to manipulate command line editing control variables. */
+
+static void
+set_editing (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ command_editing_p = parse_binary_operation ("set command-editing", arg);
+}
+
+/* Number of commands to print in each call to editing_info. */
+#define Hist_print 10
+static void
+editing_info (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ /* Index for history commands. Relative to history_base. */
+ int offset;
+
+ /* Number of the history entry which we are planning to display next.
+ Relative to history_base. */
+ static int num = 0;
+
+ /* The first command in the history which doesn't exist (i.e. one more
+ than the number of the last command). Relative to history_base. */
+ int hist_len;
+
+ struct _hist_entry {
+ char *line;
+ char *data;
+ } *history_get();
+ extern int history_base;
+
+ 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 : "");
+
+ /* Print out some of the commands from the command history. */
+ /* First determine the length of the history list. */
+ hist_len = history_size;
+ for (offset = 0; offset < history_size; offset++)
+ {
+ if (!history_get (history_base + offset))
+ {
+ hist_len = offset;
+ break;
+ }
+ }
+
+ if (arg)
+ {
+ if (arg[0] == '+' && arg[1] == '\0')
+ /* "info editing +" should print from the stored position. */
+ ;
+ else
+ /* "info editing <exp>" should print around command number <exp>. */
+ num = (parse_and_eval_address (arg) - history_base) - Hist_print / 2;
+ }
+ /* "info editing" means print the last Hist_print commands. */
+ else
+ {
+ num = hist_len - Hist_print;
+ }
+
+ if (num < 0)
+ num = 0;
+
+ /* If there are at least Hist_print commands, we want to display the last
+ Hist_print rather than, say, the last 6. */
+ if (hist_len - num < Hist_print)
+ {
+ num = hist_len - Hist_print;
+ if (num < 0)
+ num = 0;
+ }
+
+ 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");
+
+ for (offset = num; offset < num + Hist_print && offset < hist_len; offset++)
+ {
+ printf_filtered ("%5d %s\n", history_base + offset,
+ (history_get (history_base + offset))->line);
+ }
+
+ /* The next command we want to display is the next one that we haven't
+ displayed yet. */
+ 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". */
+ if (from_tty && arg)
+ {
+ arg[0] = '+';
+ arg[1] = '\0';
+ }
+}
+
+static void
+set_history_expansion (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ history_expansion_p = parse_binary_operation ("set history expansion", arg);
+}
+
+static void
+set_history_write (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ write_history_p = parse_binary_operation ("set history write", arg);
+}
+
+static void
+set_history (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ printf ("\"set history\" must be followed by the name of a history subcommand.\n");
+ help_list (sethistlist, "set history ", -1, stdout);
+}
+
+static void
+set_history_size (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ if (!*arg)
+ error_no_arg ("set history size");
+
+ history_size = atoi (arg);
+}
+
+static void
+set_history_filename (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ int i;
+
+ if (!arg)
+ error_no_arg ("history file name");
+
+ arg = tilde_expand (arg);
+ make_cleanup (free, arg);
+
+ i = strlen (arg) - 1;
+
+ free (history_filename);
+
+ while (i > 0 && (arg[i] == ' ' || arg[i] == '\t'))
+ i--;
+
+ if (!*arg)
+ history_filename = (char *) 0;
+ else
+ history_filename = savestring (arg, i + 1);
+ history_filename[i] = '\0';
+}
+
+int info_verbose;
+
+static void
+set_verbose_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ info_verbose = parse_binary_operation ("set verbose", arg);
+}
+
+static void
+verbose_info (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ if (arg)
+ error ("\"info verbose\" does not take any arguments.\n");
+
+ printf ("Verbose printing of information is %s.\n",
+ info_verbose ? "on" : "off");
+}
+
+static void
+float_handler ()
+{
+ error ("Invalid floating value encountered or computed.");
+}
+
+
static void
-init_cmd_lists ()
+initialize_cmd_lists ()
{
cmdlist = (struct cmd_list_element *) 0;
infolist = (struct cmd_list_element *) 0;
@@ -1212,13 +1678,49 @@ init_cmd_lists ()
deletelist = (struct cmd_list_element *) 0;
enablebreaklist = (struct cmd_list_element *) 0;
setlist = (struct cmd_list_element *) 0;
+ sethistlist = (struct cmd_list_element *) 0;
+ unsethistlist = (struct cmd_list_element *) 0;
}
static void
-init_main ()
+initialize_main ()
{
+ char *tmpenv;
+ /* Command line editing externals. */
+ extern int (*rl_completion_entry_function)();
+ extern char *rl_completer_word_break_characters;
+
+ /* Set default verbose mode on. */
+ info_verbose = 1;
+
prompt = savestring ("(gdb) ", 6);
+ /* Set the important stuff up for command editing. */
+ command_editing_p = 1;
+ 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;
+
/* Define the classes of commands.
They will appear in the help list in the reverse of this order. */
@@ -1280,15 +1782,47 @@ when gdb is started.");
add_com_alias ("q", "quit", class_support, 1);
add_com_alias ("h", "help", class_support, 1);
+ add_cmd ("verbose", class_support, set_verbose_command,
+ "Change the number of informational messages gdb prints.",
+ &setlist);
+ add_info ("verbose", verbose_info,
+ "Status of gdb's verbose printing option.\n");
+
add_com ("dump-me", class_obscure, dump_me_command,
"Get fatal error; make debugger dump its core.");
+ add_cmd ("editing", class_support, set_editing,
+ "Enable or disable command line editing.\n\
+Use \"on\" to enable to enable the editing, and \"off\" to disable it.\n\
+Without an argument, command line editing is enabled.", &setlist);
+
+ add_prefix_cmd ("history", class_support, set_history,
+ "Generic command for setting command history parameters.",
+ &sethistlist, "set history ", 0, &setlist);
+
+ add_cmd ("expansion", no_class, set_history_expansion,
+ "Enable or disable history expansion on command input.\n\
+Without an argument, history expansion is enabled.", &sethistlist);
+
+ add_cmd ("write", no_class, set_history_write,
+ "Enable or disable saving of the history record on exit.\n\
+Use \"on\" to enable to enable the saving, and \"off\" to disable it.\n\
+Without an argument, saving is enabled.", &sethistlist);
+
+ add_cmd ("size", no_class, set_history_size,
+ "Set the size of the command history, \n\
+ie. the number of previous commands to keep a record of.", &sethistlist);
+
+ add_cmd ("filename", no_class, set_history_filename,
+ "Set the filename in which to record the command history\n\
+ (the list of previous commands of which a record is kept).", &sethistlist);
+
add_prefix_cmd ("info", class_info, info_command,
"Generic command for printing status.",
&infolist, "info ", 0, &cmdlist);
add_com_alias ("i", "info", class_info, 1);
- add_info ("copying", copying_info, "Conditions for redistributing copies of GDB.");
- add_info ("warranty", warranty_info, "Various kinds of warranty you do not have.");
+ add_info ("editing", editing_info, "Status of command editor.");
+
add_info ("version", version_info, "Report what version of GDB this is.");
}