/* General utility routines for GDB, the GNU debugger.
Copyright 1986, 89, 90, 91, 92, 95, 96, 1998 Free Software Foundation, Inc.
-This file is part of GDB.
+ This file is part of GDB.
-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 2 of the License, or
-(at your option) any later version.
+ 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 2 of the License, or
+ (at your option) any later version.
-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.
+ 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 this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
#include "defs.h"
#include <ctype.h>
#include "gdb_string.h"
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
+#include "event-top.h"
#ifdef HAVE_CURSES_H
#include <curses.h>
#include <readline/readline.h>
+#undef XMALLOC
+#define XMALLOC(TYPE) ((TYPE*) xmalloc (sizeof (TYPE)))
+
/* readline defines this. */
#undef savestring
+void (*error_begin_hook) PARAMS ((void));
+
+/* Holds the last error message issued by gdb */
+
+static GDB_FILE *gdb_lasterr;
+
/* Prototypes for local functions */
-static void vfprintf_maybe_filtered PARAMS ((FILE *, const char *, va_list, int));
+static void vfprintf_maybe_filtered PARAMS ((GDB_FILE *, const char *,
+ va_list, int));
-static void fputs_maybe_filtered PARAMS ((const char *, FILE *, int));
+static void fputs_maybe_filtered PARAMS ((const char *, GDB_FILE *, int));
#if defined (USE_MMALLOC) && !defined (NO_MMCHECK)
static void malloc_botch PARAMS ((void));
#endif
-static void
-fatal_dump_core PARAMS((char *, ...));
-
static void
prompt_for_continue PARAMS ((void));
-static void
+static void
set_width_command PARAMS ((char *, int, struct cmd_list_element *));
-/* 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)))
+static void
+set_width PARAMS ((void));
+
+#ifndef GDB_FILE_ISATTY
+#define GDB_FILE_ISATTY(GDB_FILE_PTR) (gdb_file_isatty(GDB_FILE_PTR))
#endif
/* Chain of cleanup actions established with make_cleanup,
to be executed if an error happens. */
-static struct cleanup *cleanup_chain; /* cleaned up after a failed command */
-static struct cleanup *final_cleanup_chain; /* cleaned up when gdb exits */
-static struct cleanup *run_cleanup_chain; /* cleaned up on each 'run' */
+static struct cleanup *cleanup_chain; /* cleaned up after a failed command */
+static struct cleanup *final_cleanup_chain; /* cleaned up when gdb exits */
+static struct cleanup *run_cleanup_chain; /* cleaned up on each 'run' */
+static struct cleanup *exec_cleanup_chain; /* cleaned up on each execution command */
+/* cleaned up on each error from within an execution command */
+static struct cleanup *exec_error_cleanup_chain;
+
+/* Pointer to what is left to do for an execution command after the
+ target stops. Used only in asynchronous mode, by targets that
+ support async execution. The finish and until commands use it. So
+ does the target extended-remote command. */
+struct continuation *cmd_continuation;
+struct continuation *intermediate_continuation;
/* Nonzero if we have job control. */
/* String to be printed before warning messages, if any. */
char *warning_pre_print = "\nwarning: ";
+
+int pagination_enabled = 1;
\f
+
/* Add a new cleanup to the cleanup_chain,
and return the previous chain pointer
to be passed later to do_cleanups or discard_cleanups.
void (*function) PARAMS ((PTR));
PTR arg;
{
- return make_my_cleanup (&cleanup_chain, function, arg);
+ return make_my_cleanup (&cleanup_chain, function, arg);
}
struct cleanup *
void (*function) PARAMS ((PTR));
PTR arg;
{
- return make_my_cleanup (&final_cleanup_chain, function, arg);
+ return make_my_cleanup (&final_cleanup_chain, function, arg);
}
+
struct cleanup *
make_run_cleanup (function, arg)
void (*function) PARAMS ((PTR));
PTR arg;
{
- return make_my_cleanup (&run_cleanup_chain, function, arg);
+ return make_my_cleanup (&run_cleanup_chain, function, arg);
+}
+
+struct cleanup *
+make_exec_cleanup (function, arg)
+ void (*function) PARAMS ((PTR));
+ PTR arg;
+{
+ return make_my_cleanup (&exec_cleanup_chain, function, arg);
+}
+
+struct cleanup *
+make_exec_error_cleanup (function, arg)
+ void (*function) PARAMS ((PTR));
+ PTR arg;
+{
+ return make_my_cleanup (&exec_error_cleanup_chain, function, arg);
+}
+
+static void
+do_freeargv (arg)
+ void *arg;
+{
+ freeargv ((char **) arg);
+}
+
+struct cleanup *
+make_cleanup_freeargv (arg)
+ char **arg;
+{
+ return make_my_cleanup (&cleanup_chain, do_freeargv, arg);
+}
+
+static void
+do_gdb_file_delete (void *arg)
+{
+ gdb_file_delete (arg);
+}
+
+struct cleanup *
+make_cleanup_gdb_file_delete (struct gdb_file *arg)
+{
+ return make_my_cleanup (&cleanup_chain, do_gdb_file_delete, arg);
}
+
struct cleanup *
make_my_cleanup (pmy_chain, function, arg)
struct cleanup **pmy_chain;
PTR arg;
{
register struct cleanup *new
- = (struct cleanup *) xmalloc (sizeof (struct cleanup));
+ = (struct cleanup *) xmalloc (sizeof (struct cleanup));
register struct cleanup *old_chain = *pmy_chain;
new->next = *pmy_chain;
do_cleanups (old_chain)
register struct cleanup *old_chain;
{
- do_my_cleanups (&cleanup_chain, old_chain);
+ do_my_cleanups (&cleanup_chain, old_chain);
}
void
do_final_cleanups (old_chain)
register struct cleanup *old_chain;
{
- do_my_cleanups (&final_cleanup_chain, old_chain);
+ do_my_cleanups (&final_cleanup_chain, old_chain);
}
void
do_run_cleanups (old_chain)
register struct cleanup *old_chain;
{
- do_my_cleanups (&run_cleanup_chain, old_chain);
+ do_my_cleanups (&run_cleanup_chain, old_chain);
+}
+
+void
+do_exec_cleanups (old_chain)
+ register struct cleanup *old_chain;
+{
+ do_my_cleanups (&exec_cleanup_chain, old_chain);
+}
+
+void
+do_exec_error_cleanups (old_chain)
+ register struct cleanup *old_chain;
+{
+ do_my_cleanups (&exec_error_cleanup_chain, old_chain);
}
void
discard_cleanups (old_chain)
register struct cleanup *old_chain;
{
- discard_my_cleanups (&cleanup_chain, old_chain);
+ discard_my_cleanups (&cleanup_chain, old_chain);
}
void
discard_final_cleanups (old_chain)
register struct cleanup *old_chain;
{
- discard_my_cleanups (&final_cleanup_chain, old_chain);
+ discard_my_cleanups (&final_cleanup_chain, old_chain);
+}
+
+void
+discard_exec_error_cleanups (old_chain)
+ register struct cleanup *old_chain;
+{
+ discard_my_cleanups (&exec_error_cleanup_chain, old_chain);
}
void
while ((ptr = *pmy_chain) != old_chain)
{
*pmy_chain = ptr->next;
- free ((PTR)ptr);
+ free ((PTR) ptr);
}
}
struct cleanup *
save_cleanups ()
{
- return save_my_cleanups (&cleanup_chain);
+ return save_my_cleanups (&cleanup_chain);
}
struct cleanup *
save_final_cleanups ()
{
- return save_my_cleanups (&final_cleanup_chain);
+ return save_my_cleanups (&final_cleanup_chain);
}
struct cleanup *
save_my_cleanups (pmy_chain)
- struct cleanup **pmy_chain;
+ struct cleanup **pmy_chain;
{
struct cleanup *old_chain = *pmy_chain;
restore_cleanups (chain)
struct cleanup *chain;
{
- restore_my_cleanups (&cleanup_chain, chain);
+ restore_my_cleanups (&cleanup_chain, chain);
}
void
restore_final_cleanups (chain)
struct cleanup *chain;
{
- restore_my_cleanups (&final_cleanup_chain, chain);
+ restore_my_cleanups (&final_cleanup_chain, chain);
}
void
/* This function is useful for cleanups.
Do
- foo = xmalloc (...);
- old_chain = make_cleanup (free_current_contents, &foo);
+ foo = xmalloc (...);
+ old_chain = make_cleanup (free_current_contents, &foo);
to arrange to free the object thus allocated. */
/* ARGSUSED */
void
null_cleanup (arg)
- PTR arg;
+ PTR arg;
+{
+}
+
+/* Add a continuation to the continuation list, the gloabl list
+ cmd_continuation. The new continuation will be added at the front.*/
+void
+add_continuation (continuation_hook, arg_list)
+ void (*continuation_hook) PARAMS ((struct continuation_arg *));
+ struct continuation_arg *arg_list;
+{
+ struct continuation *continuation_ptr;
+
+ continuation_ptr = (struct continuation *) xmalloc (sizeof (struct continuation));
+ continuation_ptr->continuation_hook = continuation_hook;
+ continuation_ptr->arg_list = arg_list;
+ continuation_ptr->next = cmd_continuation;
+ cmd_continuation = continuation_ptr;
+}
+
+/* Walk down the cmd_continuation list, and execute all the
+ continuations. There is a problem though. In some cases new
+ continuations may be added while we are in the middle of this
+ loop. If this happens they will be added in the front, and done
+ before we have a chance of exhausting those that were already
+ there. We need to then save the beginning of the list in a pointer
+ and do the continuations from there on, instead of using the
+ global beginning of list as our iteration pointer.*/
+void
+do_all_continuations ()
+{
+ struct continuation *continuation_ptr;
+ struct continuation *saved_continuation;
+
+ /* Copy the list header into another pointer, and set the global
+ list header to null, so that the global list can change as a side
+ effect of invoking the continuations and the processing of
+ the preexisting continuations will not be affected. */
+ continuation_ptr = cmd_continuation;
+ cmd_continuation = NULL;
+
+ /* Work now on the list we have set aside. */
+ while (continuation_ptr)
+ {
+ (continuation_ptr->continuation_hook) (continuation_ptr->arg_list);
+ saved_continuation = continuation_ptr;
+ continuation_ptr = continuation_ptr->next;
+ free (saved_continuation);
+ }
+}
+
+/* Walk down the cmd_continuation list, and get rid of all the
+ continuations. */
+void
+discard_all_continuations ()
+{
+ struct continuation *continuation_ptr;
+
+ while (cmd_continuation)
+ {
+ continuation_ptr = cmd_continuation;
+ cmd_continuation = continuation_ptr->next;
+ free (continuation_ptr);
+ }
+}
+
+/* Add a continuation to the continuation list, the gloabl list
+ intermediate_continuation. The new continuation will be added at the front.*/
+void
+add_intermediate_continuation (continuation_hook, arg_list)
+ void (*continuation_hook) PARAMS ((struct continuation_arg *));
+ struct continuation_arg *arg_list;
+{
+ struct continuation *continuation_ptr;
+
+ continuation_ptr = (struct continuation *) xmalloc (sizeof (struct continuation));
+ continuation_ptr->continuation_hook = continuation_hook;
+ continuation_ptr->arg_list = arg_list;
+ continuation_ptr->next = intermediate_continuation;
+ intermediate_continuation = continuation_ptr;
+}
+
+/* Walk down the cmd_continuation list, and execute all the
+ continuations. There is a problem though. In some cases new
+ continuations may be added while we are in the middle of this
+ loop. If this happens they will be added in the front, and done
+ before we have a chance of exhausting those that were already
+ there. We need to then save the beginning of the list in a pointer
+ and do the continuations from there on, instead of using the
+ global beginning of list as our iteration pointer.*/
+void
+do_all_intermediate_continuations ()
+{
+ struct continuation *continuation_ptr;
+ struct continuation *saved_continuation;
+
+ /* Copy the list header into another pointer, and set the global
+ list header to null, so that the global list can change as a side
+ effect of invoking the continuations and the processing of
+ the preexisting continuations will not be affected. */
+ continuation_ptr = intermediate_continuation;
+ intermediate_continuation = NULL;
+
+ /* Work now on the list we have set aside. */
+ while (continuation_ptr)
+ {
+ (continuation_ptr->continuation_hook) (continuation_ptr->arg_list);
+ saved_continuation = continuation_ptr;
+ continuation_ptr = continuation_ptr->next;
+ free (saved_continuation);
+ }
+}
+
+/* Walk down the cmd_continuation list, and get rid of all the
+ continuations. */
+void
+discard_all_intermediate_continuations ()
{
+ struct continuation *continuation_ptr;
+
+ while (intermediate_continuation)
+ {
+ continuation_ptr = intermediate_continuation;
+ intermediate_continuation = continuation_ptr->next;
+ free (continuation_ptr);
+ }
}
\f
+
/* Print a warning message. Way to use this is to call warning_begin,
output the warning message (use unfiltered output to gdb_stderr),
ending in a newline. There is not currently a warning_end that you
warning_begin ()
{
target_terminal_ours ();
- wrap_here(""); /* Force out any buffered output */
+ wrap_here (""); /* Force out any buffered output */
gdb_flush (gdb_stdout);
if (warning_pre_print)
fprintf_unfiltered (gdb_stderr, warning_pre_print);
The primary difference between warnings and errors is that a warning
does not force the return to command level. */
-/* VARARGS */
void
-#ifdef ANSI_PROTOTYPES
-warning (const char *string, ...)
-#else
-warning (va_alist)
- va_dcl
-#endif
+warning (const char *string,...)
{
va_list args;
-#ifdef ANSI_PROTOTYPES
va_start (args, string);
-#else
- char *string;
-
- va_start (args);
- string = va_arg (args, char *);
-#endif
if (warning_hook)
(*warning_hook) (string, args);
else
- {
- warning_begin ();
- vfprintf_unfiltered (gdb_stderr, string, args);
- fprintf_unfiltered (gdb_stderr, "\n");
- va_end (args);
- }
+ {
+ warning_begin ();
+ vfprintf_unfiltered (gdb_stderr, string, args);
+ fprintf_unfiltered (gdb_stderr, "\n");
+ va_end (args);
+ }
}
/* Start the printing of an error message. Way to use this is to call
void
error_begin ()
{
+ if (error_begin_hook)
+ error_begin_hook ();
+
target_terminal_ours ();
- wrap_here (""); /* Force out any buffered output */
+ wrap_here (""); /* Force out any buffered output */
gdb_flush (gdb_stdout);
annotate_error_begin ();
The first argument STRING is the error message, used as a fprintf string,
and the remaining args are passed as arguments to it. */
-/* VARARGS */
NORETURN void
-#ifdef ANSI_PROTOTYPES
-error (const char *string, ...)
-#else
-error (va_alist)
- va_dcl
-#endif
+verror (const char *string, va_list args)
+{
+ char *err_string;
+ struct cleanup *err_string_cleanup;
+ /* FIXME: cagney/1999-11-10: All error calls should come here.
+ Unfortunatly some code uses the sequence: error_begin(); print
+ error message; return_to_top_level. That code should be
+ flushed. */
+ error_begin ();
+ /* NOTE: It's tempting to just do the following...
+ vfprintf_filtered (gdb_stderr, string, args);
+ and then follow with a similar looking statement to cause the message
+ to also go to gdb_lasterr. But if we do this, we'll be traversing the
+ va_list twice which works on some platforms and fails miserably on
+ others. */
+ /* Save it as the last error */
+ gdb_file_rewind (gdb_lasterr);
+ vfprintf_filtered (gdb_lasterr, string, args);
+ /* Retrieve the last error and print it to gdb_stderr */
+ err_string = error_last_message ();
+ err_string_cleanup = make_cleanup (free, err_string);
+ fputs_filtered (err_string, gdb_stderr);
+ fprintf_filtered (gdb_stderr, "\n");
+ do_cleanups (err_string_cleanup);
+ return_to_top_level (RETURN_ERROR);
+}
+
+NORETURN void
+error (const char *string,...)
{
va_list args;
-#ifdef ANSI_PROTOTYPES
va_start (args, string);
-#else
- va_start (args);
-#endif
- if (error_hook)
- (*error_hook) ();
- else
- {
- error_begin ();
-#ifdef ANSI_PROTOTYPES
- vfprintf_filtered (gdb_stderr, string, args);
-#else
- {
- char *string1;
-
- string1 = va_arg (args, char *);
- vfprintf_filtered (gdb_stderr, string1, args);
- }
-#endif
- fprintf_filtered (gdb_stderr, "\n");
- va_end (args);
- return_to_top_level (RETURN_ERROR);
- }
+ verror (string, args);
+ va_end (args);
}
+NORETURN void
+error_stream (GDB_FILE *stream)
+{
+ long size;
+ char *msg = gdb_file_xstrdup (stream, &size);
+ make_cleanup (free, msg);
+ error ("%s", msg);
+}
-/* Print an error message and exit reporting failure.
- This is for a error that we cannot continue from.
- The arguments are printed a la printf.
+/* Get the last error message issued by gdb */
- This function cannot be declared volatile (NORETURN) in an
- ANSI environment because exit() is not declared volatile. */
+char *
+error_last_message (void)
+{
+ long len;
+ return gdb_file_xstrdup (gdb_lasterr, &len);
+}
+
+/* This is to be called by main() at the very beginning */
-/* VARARGS */
-NORETURN void
-#ifdef ANSI_PROTOTYPES
-fatal (char *string, ...)
-#else
-fatal (va_alist)
- va_dcl
-#endif
+void
+error_init (void)
{
- va_list args;
-#ifdef ANSI_PROTOTYPES
- va_start (args, string);
-#else
- char *string;
- va_start (args);
- string = va_arg (args, char *);
-#endif
- fprintf_unfiltered (gdb_stderr, "\ngdb: ");
- vfprintf_unfiltered (gdb_stderr, string, args);
- fprintf_unfiltered (gdb_stderr, "\n");
- va_end (args);
- exit (1);
+ gdb_lasterr = mem_fileopen ();
}
-/* Print an error message and exit, dumping core.
- The arguments are printed a la printf (). */
+/* Print a message reporting an internal error. Ask the user if they
+ want to continue, dump core, or just exit. */
-/* VARARGS */
-static void
-#ifdef ANSI_PROTOTYPES
-fatal_dump_core (char *string, ...)
-#else
-fatal_dump_core (va_alist)
- va_dcl
-#endif
+NORETURN void
+internal_verror (const char *fmt, va_list ap)
{
- va_list args;
-#ifdef ANSI_PROTOTYPES
- va_start (args, string);
-#else
- char *string;
+ static char msg[] = "Internal GDB error: recursive internal error.\n";
+ static int dejavu = 0;
+ int continue_p;
+ int dump_core_p;
- va_start (args);
- string = va_arg (args, char *);
-#endif
- /* "internal error" is always correct, since GDB should never dump
- core, no matter what the input. */
- fprintf_unfiltered (gdb_stderr, "\ngdb internal error: ");
- vfprintf_unfiltered (gdb_stderr, string, args);
- fprintf_unfiltered (gdb_stderr, "\n");
- va_end (args);
+ /* don't allow infinite error recursion. */
+ switch (dejavu)
+ {
+ case 0:
+ dejavu = 1;
+ break;
+ case 1:
+ dejavu = 2;
+ fputs_unfiltered (msg, gdb_stderr);
+ abort ();
+ default:
+ dejavu = 3;
+ write (STDERR_FILENO, msg, sizeof (msg));
+ exit (1);
+ }
+
+ /* Try to get the message out */
+ fputs_unfiltered ("gdb-internal-error: ", gdb_stderr);
+ vfprintf_unfiltered (gdb_stderr, fmt, ap);
+ fputs_unfiltered ("\n", gdb_stderr);
+
+ /* Default (no case) is to quit GDB. When in batch mode this
+ lessens the likelhood of GDB going into an infinate loop. */
+ continue_p = query ("\
+An internal GDB error was detected. This may make make further\n\
+debugging unreliable. Continue this debugging session? ");
+
+ /* Default (no case) is to not dump core. Lessen the chance of GDB
+ leaving random core files around. */
+ dump_core_p = query ("\
+Create a core file containing the current state of GDB? ");
+
+ if (continue_p)
+ {
+ if (dump_core_p)
+ {
+ if (fork () == 0)
+ abort ();
+ }
+ }
+ else
+ {
+ if (dump_core_p)
+ abort ();
+ else
+ exit (1);
+ }
+
+ dejavu = 0;
+ return_to_top_level (RETURN_ERROR);
+}
- signal (SIGQUIT, SIG_DFL);
- kill (getpid (), SIGQUIT);
- /* We should never get here, but just in case... */
- exit (1);
+NORETURN void
+internal_error (char *string, ...)
+{
+ va_list ap;
+ va_start (ap, string);
+ internal_verror (string, ap);
+ va_end (ap);
}
/* The strerror() function can return NULL for errno values that are
bfd_set_error (bfd_error_no_error);
errno = 0;
- error ("%s.", combined);
+ error ("%s.", combined);
}
/* Print the system error message for ERRCODE, and also mention STRING
too): */
/* 1. The _filtered buffer. */
- wrap_here ((char *)0);
+ wrap_here ((char *) 0);
/* 2. The stdio buffer. */
gdb_flush (gdb_stdout);
if (quit_pre_print)
fprintf_unfiltered (gdb_stderr, quit_pre_print);
+#ifdef __MSDOS__
+ /* No steenking SIGINT will ever be coming our way when the
+ program is resumed. Don't lie. */
+ fprintf_unfiltered (gdb_stderr, "Quit\n");
+#else
if (job_control
- /* If there is no terminal switching for this target, then we can't
- possibly get screwed by the lack of job control. */
+ /* If there is no terminal switching for this target, then we can't
+ possibly get screwed by the lack of job control. */
|| current_target.to_terminal_ours == NULL)
fprintf_unfiltered (gdb_stderr, "Quit\n");
else
fprintf_unfiltered (gdb_stderr,
- "Quit (expect signal SIGINT when the program is resumed)\n");
+ "Quit (expect signal SIGINT when the program is resumed)\n");
+#endif
return_to_top_level (RETURN_QUIT);
}
-#if defined(__GO32__)
-
-/* In the absence of signals, poll keyboard for a quit.
- Called from #define QUIT pollquit() in xm-go32.h. */
-
-void
-notice_quit()
-{
- if (kbhit ())
- switch (getkey ())
- {
- case 1:
- quit_flag = 1;
- break;
- case 2:
- immediate_quit = 2;
- break;
- default:
- /* We just ignore it */
- /* FIXME!! Don't think this actually works! */
- fprintf_unfiltered (gdb_stderr, "CTRL-A to quit, CTRL-B to quit harder\n");
- break;
- }
-}
-
-#elif defined(_MSC_VER) /* should test for wingdb instead? */
+#if defined(_MSC_VER) /* should test for wingdb instead? */
/*
* Windows translates all keyboard and mouse events
* queue for the process.
*/
-void notice_quit()
+void
+notice_quit ()
{
- int k = win32pollquit();
+ int k = win32pollquit ();
if (k == 1)
quit_flag = 1;
else if (k == 2)
immediate_quit = 1;
}
-#else /* !defined(__GO32__) && !defined(_MSC_VER) */
+#else /* !defined(_MSC_VER) */
-void notice_quit()
+void
+notice_quit ()
{
/* Done by signals */
}
-#endif /* !defined(__GO32__) && !defined(_MSC_VER) */
-
-void
-pollquit()
-{
- notice_quit ();
- if (quit_flag || immediate_quit)
- quit ();
-}
+#endif /* !defined(_MSC_VER) */
/* Control C comes here */
-
void
request_quit (signo)
int signo;
#ifdef REQUEST_QUIT
REQUEST_QUIT;
#else
- if (immediate_quit)
+ if (immediate_quit)
quit ();
#endif
}
-
\f
/* Memory management stuff (malloc friends). */
PTR ptr;
size_t size;
{
- if (ptr == 0) /* Guard against old realloc's */
+ if (ptr == 0) /* Guard against old realloc's */
return malloc (size);
else
return realloc (ptr, size);
free (ptr);
}
-#endif /* USE_MMALLOC */
+#endif /* USE_MMALLOC */
#if !defined (USE_MMALLOC) || defined (NO_MMCHECK)
static void
malloc_botch ()
{
- fatal_dump_core ("Memory corruption");
+ fprintf_unfiltered (gdb_stderr, "Memory corruption\n");
+ abort ();
}
/* Attempt to install hooks in mmalloc/mrealloc/mfree for the heap specified
if (!mmcheckf (md, malloc_botch, MMCHECK_FORCE))
{
/* Don't use warning(), which relies on current_target being set
- to something other than dummy_target, until after
- initialize_all_files(). */
+ to something other than dummy_target, until after
+ initialize_all_files(). */
fprintf_unfiltered
(gdb_stderr, "warning: failed to install memory consistency checks; ");
{
if (size > 0)
{
- fatal ("virtual memory exhausted: can't allocate %ld bytes.", size);
+ internal_error ("virtual memory exhausted: can't allocate %ld bytes.", size);
}
else
{
- fatal ("virtual memory exhausted.");
+ internal_error ("virtual memory exhausted.");
}
}
{
return (xmrealloc ((PTR) NULL, ptr, size));
}
-
\f
+
/* My replacement for the read system call.
Used like `read' but keeps going if `read' returns too soon. */
void
print_spaces (n, file)
register int n;
- register FILE *file;
+ register GDB_FILE *file;
{
- while (n-- > 0)
- fputc (' ', file);
+ fputs_unfiltered (n_spaces (n), file);
}
/* Print a host address. */
void
-gdb_print_address (addr, stream)
- PTR addr;
- GDB_FILE *stream;
+gdb_print_host_address (void *addr, struct gdb_file *stream)
{
/* We could use the %p conversion specifier to fprintf if we had any
way of knowing whether this host supports it. But the following
should work on the Alpha and on 32 bit machines. */
- fprintf_filtered (stream, "0x%lx", (unsigned long)addr);
+ fprintf_filtered (stream, "0x%lx", (unsigned long) addr);
}
/* Ask user a y-or-n question and return 1 iff answer is yes.
/* VARARGS */
int
-#ifdef ANSI_PROTOTYPES
-query (char *ctlstr, ...)
-#else
-query (va_alist)
- va_dcl
-#endif
+query (char *ctlstr,...)
{
va_list args;
register int answer;
register int ans2;
int retval;
-#ifdef ANSI_PROTOTYPES
va_start (args, ctlstr);
-#else
- char *ctlstr;
- va_start (args);
- ctlstr = va_arg (args, char *);
-#endif
if (query_hook)
{
#ifdef MPW
/* If not in MacGDB, move to a new line so the entered line doesn't
- have a prompt on the front of it. */
+ have a prompt on the front of it. */
if (!mac_app)
fputs_unfiltered ("\n", gdb_stdout);
#endif /* MPW */
+ wrap_here ("");
gdb_flush (gdb_stdout);
- answer = fgetc (stdin);
+
+#if defined(TUI)
+ if (!tui_version || cmdWin == tuiWinWithFocus ())
+#endif
+ answer = fgetc (stdin);
+#if defined(TUI)
+ else
+ answer = (unsigned char) tuiBufferGetc ();
+
+#endif
clearerr (stdin); /* in case of C-d */
if (answer == EOF) /* C-d */
- {
+ {
retval = 1;
break;
}
- if (answer != '\n') /* Eat rest of input line, to EOF or newline */
- do
+ /* Eat rest of input line, to EOF or newline */
+ if ((answer != '\n') || (tui_version && answer != '\r'))
+ do
{
- ans2 = fgetc (stdin);
+#if defined(TUI)
+ if (!tui_version || cmdWin == tuiWinWithFocus ())
+#endif
+ ans2 = fgetc (stdin);
+#if defined(TUI)
+ else
+ ans2 = (unsigned char) tuiBufferGetc ();
+#endif
clearerr (stdin);
}
- while (ans2 != EOF && ans2 != '\n');
+ while (ans2 != EOF && ans2 != '\n' && ans2 != '\r');
+ TUIDO (((TuiOpaqueFuncPtr) tui_vStartNewLines, 1));
+
if (answer >= 'a')
answer -= 040;
if (answer == 'Y')
printf_filtered ("\n\032\032post-query\n");
return retval;
}
-
\f
+
/* Parse a C escape sequence. STRING_PTR points to a variable
containing a pointer to the string to parse. That pointer
should point to the character after the \. That pointer
if (c == '?')
return 0177;
return (c & 0200) | (c & 037);
-
+
case '0':
case '1':
case '2':
be call for printing things which are independent of the language
of the program being debugged. */
-void
-gdb_printchar (c, stream, quoter)
- register int c;
- FILE *stream;
+static void printchar PARAMS ((int c, void (*do_fputs) (const char *, GDB_FILE*), void (*do_fprintf) (GDB_FILE*, const char *, ...), GDB_FILE *stream, int quoter));
+
+static void
+printchar (c, do_fputs, do_fprintf, stream, quoter)
+ int c;
+ void (*do_fputs) PARAMS ((const char *, GDB_FILE*));
+ void (*do_fprintf) PARAMS ((GDB_FILE*, const char *, ...));
+ GDB_FILE *stream;
int quoter;
{
c &= 0xFF; /* Avoid sign bit follies */
- if ( c < 0x20 || /* Low control chars */
- (c >= 0x7F && c < 0xA0) || /* DEL, High controls */
- (sevenbit_strings && c >= 0x80)) { /* high order bit set */
- switch (c)
- {
- case '\n':
- fputs_filtered ("\\n", stream);
- break;
- case '\b':
- fputs_filtered ("\\b", stream);
- break;
- case '\t':
- fputs_filtered ("\\t", stream);
- break;
- case '\f':
- fputs_filtered ("\\f", stream);
- break;
- case '\r':
- fputs_filtered ("\\r", stream);
- break;
- case '\033':
- fputs_filtered ("\\e", stream);
- break;
- case '\007':
- fputs_filtered ("\\a", stream);
- break;
- default:
- fprintf_filtered (stream, "\\%.3o", (unsigned int) c);
- break;
- }
- } else {
- if (c == '\\' || c == quoter)
- fputs_filtered ("\\", stream);
- fprintf_filtered (stream, "%c", c);
- }
+ if (c < 0x20 || /* Low control chars */
+ (c >= 0x7F && c < 0xA0) || /* DEL, High controls */
+ (sevenbit_strings && c >= 0x80))
+ { /* high order bit set */
+ switch (c)
+ {
+ case '\n':
+ do_fputs ("\\n", stream);
+ break;
+ case '\b':
+ do_fputs ("\\b", stream);
+ break;
+ case '\t':
+ do_fputs ("\\t", stream);
+ break;
+ case '\f':
+ do_fputs ("\\f", stream);
+ break;
+ case '\r':
+ do_fputs ("\\r", stream);
+ break;
+ case '\033':
+ do_fputs ("\\e", stream);
+ break;
+ case '\007':
+ do_fputs ("\\a", stream);
+ break;
+ default:
+ do_fprintf (stream, "\\%.3o", (unsigned int) c);
+ break;
+ }
+ }
+ else
+ {
+ if (c == '\\' || c == quoter)
+ do_fputs ("\\", stream);
+ do_fprintf (stream, "%c", c);
+ }
}
+/* Print the character C on STREAM as part of the contents of a
+ literal string whose delimiter is QUOTER. Note that these routines
+ should only be call for printing things which are independent of
+ the language of the program being debugged. */
+void
+fputstr_filtered (str, quoter, stream)
+ const char *str;
+ int quoter;
+ GDB_FILE *stream;
+{
+ while (*str)
+ printchar (*str++, fputs_filtered, fprintf_filtered, stream, quoter);
+}
-
-static char * hexlate = "0123456789abcdef" ;
-int fmthex(inbuf,outbuff,length,linelength)
- unsigned char * inbuf ;
- unsigned char * outbuff;
- int length;
- int linelength;
+void
+fputstr_unfiltered (str, quoter, stream)
+ const char *str;
+ int quoter;
+ GDB_FILE *stream;
{
- unsigned char byte , nib ;
- int outlength = 0 ;
+ while (*str)
+ printchar (*str++, fputs_unfiltered, fprintf_unfiltered, stream, quoter);
+}
- while (length)
- {
- if (outlength >= linelength) break ;
- byte = *inbuf ;
- inbuf++ ;
- nib = byte >> 4 ;
- *outbuff++ = hexlate[nib] ;
- nib = byte &0x0f ;
- *outbuff++ = hexlate[nib] ;
- *outbuff++ = ' ' ;
- length-- ;
- outlength += 3 ;
- }
- *outbuff = '\0' ; /* null terminate our output line */
- return outlength ;
+void
+fputstrn_unfiltered (str, n, quoter, stream)
+ const char *str;
+ int n;
+ int quoter;
+ GDB_FILE *stream;
+{
+ int i;
+ for (i = 0; i < n; i++)
+ printchar (str[i], fputs_unfiltered, fprintf_unfiltered, stream, quoter);
}
\f
+
/* Number of lines per page or UINT_MAX if paging is disabled. */
static unsigned int lines_per_page;
-/* Number of chars per line or UNIT_MAX is line folding is disabled. */
+/* Number of chars per line or UNIT_MAX if line folding is disabled. */
static unsigned int chars_per_line;
/* Current count of lines printed on this page, chars on this line. */
static unsigned int lines_printed, chars_printed;
/* Column number on the screen where wrap_buffer begins, or 0 if wrapping
is not in effect. */
static int wrap_column;
+\f
-/* ARGSUSED */
-static void
-set_width_command (args, from_tty, c)
- char *args;
- int from_tty;
- struct cmd_list_element *c;
+/* Inialize the lines and chars per page */
+void
+init_page_info ()
{
- if (!wrap_buffer)
+#if defined(TUI)
+ if (tui_version && m_winPtrNotNull (cmdWin))
{
- wrap_buffer = (char *) xmalloc (chars_per_line + 2);
+ lines_per_page = cmdWin->generic.height;
+ chars_per_line = cmdWin->generic.width;
+ }
+ else
+#endif
+ {
+ /* These defaults will be used if we are unable to get the correct
+ values from termcap. */
+#if defined(__GO32__)
+ lines_per_page = ScreenRows ();
+ chars_per_line = ScreenCols ();
+#else
+ lines_per_page = 24;
+ chars_per_line = 80;
+
+#if !defined (MPW) && !defined (_WIN32)
+ /* No termcap under MPW, although might be cool to do something
+ by looking at worksheet or console window sizes. */
+ /* Initialize the screen height and width from termcap. */
+ {
+ char *termtype = getenv ("TERM");
+
+ /* Positive means success, nonpositive means failure. */
+ int status;
+
+ /* 2048 is large enough for all known terminals, according to the
+ GNU termcap manual. */
+ char term_buffer[2048];
+
+ if (termtype)
+ {
+ status = tgetent (term_buffer, termtype);
+ if (status > 0)
+ {
+ int val;
+ int running_in_emacs = getenv ("EMACS") != NULL;
+
+ val = tgetnum ("li");
+ if (val >= 0 && !running_in_emacs)
+ lines_per_page = val;
+ else
+ /* The number of lines per page is not mentioned
+ in the terminal description. This probably means
+ that paging is not useful (e.g. emacs shell window),
+ so disable paging. */
+ lines_per_page = UINT_MAX;
+
+ val = tgetnum ("co");
+ if (val >= 0)
+ chars_per_line = val;
+ }
+ }
+ }
+#endif /* MPW */
+
+#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER)
+
+ /* If there is a better way to determine the window size, use it. */
+ SIGWINCH_HANDLER (SIGWINCH);
+#endif
+#endif
+ /* If the output is not a terminal, don't paginate it. */
+ if (!GDB_FILE_ISATTY (gdb_stdout))
+ lines_per_page = UINT_MAX;
+ } /* the command_line_version */
+ set_width ();
+}
+
+static void
+set_width ()
+{
+ if (chars_per_line == 0)
+ init_page_info ();
+
+ if (!wrap_buffer)
+ {
+ wrap_buffer = (char *) xmalloc (chars_per_line + 2);
wrap_buffer[0] = '\0';
}
else
wrap_pointer = wrap_buffer; /* Start it at the beginning */
}
+/* ARGSUSED */
+static void
+set_width_command (args, from_tty, c)
+ char *args;
+ int from_tty;
+ struct cmd_list_element *c;
+{
+ set_width ();
+}
+
/* Wait, so the user can read what's on the screen. Prompt the user
to continue by pressing RETURN. */
while (*p == ' ' || *p == '\t')
++p;
if (p[0] == 'q')
- request_quit (SIGINT);
+ {
+ if (!event_loop_p)
+ request_quit (SIGINT);
+ else
+ async_request_quit (0);
+ }
free (ignore);
}
immediate_quit--;
used to force out output from the wrap_buffer. */
void
-wrap_here(indent)
+wrap_here (indent)
char *indent;
{
/* This should have been allocated, but be paranoid anyway. */
}
wrap_pointer = wrap_buffer;
wrap_buffer[0] = '\0';
- if (chars_per_line == UINT_MAX) /* No line overflow checking */
+ if (chars_per_line == UINT_MAX) /* No line overflow checking */
{
wrap_column = 0;
}
}
+/* ``struct gdb_file'' implementation that maps directly onto
+ <stdio.h>'s FILE. */
+
+static gdb_file_write_ftype stdio_file_write;
+static gdb_file_fputs_ftype stdio_file_fputs;
+static gdb_file_isatty_ftype stdio_file_isatty;
+static gdb_file_delete_ftype stdio_file_delete;
+static struct gdb_file *stdio_file_new PARAMS ((FILE * file, int close_p));
+static gdb_file_flush_ftype stdio_file_flush;
+
+static int stdio_file_magic;
+
+struct stdio_file
+ {
+ int *magic;
+ FILE *file;
+ int close_p;
+ };
+
+static struct gdb_file *
+stdio_file_new (file, close_p)
+ FILE *file;
+ int close_p;
+{
+ struct gdb_file *gdb_file = gdb_file_new ();
+ struct stdio_file *stdio = xmalloc (sizeof (struct stdio_file));
+ stdio->magic = &stdio_file_magic;
+ stdio->file = file;
+ stdio->close_p = close_p;
+ set_gdb_file_data (gdb_file, stdio, stdio_file_delete);
+ set_gdb_file_flush (gdb_file, stdio_file_flush);
+ set_gdb_file_write (gdb_file, stdio_file_write);
+ set_gdb_file_fputs (gdb_file, stdio_file_fputs);
+ set_gdb_file_isatty (gdb_file, stdio_file_isatty);
+ return gdb_file;
+}
+
+static void
+stdio_file_delete (file)
+ struct gdb_file *file;
+{
+ struct stdio_file *stdio = gdb_file_data (file);
+ if (stdio->magic != &stdio_file_magic)
+ internal_error ("stdio_file_delete: bad magic number");
+ if (stdio->close_p)
+ {
+ fclose (stdio->file);
+ }
+ free (stdio);
+}
+
+static void
+stdio_file_flush (file)
+ struct gdb_file *file;
+{
+ struct stdio_file *stdio = gdb_file_data (file);
+ if (stdio->magic != &stdio_file_magic)
+ internal_error ("stdio_file_flush: bad magic number");
+ fflush (stdio->file);
+}
+
+static void
+stdio_file_write (struct gdb_file *file, const char *buf, long length_buf)
+{
+ struct stdio_file *stdio = gdb_file_data (file);
+ if (stdio->magic != &stdio_file_magic)
+ internal_error ("stdio_file_write: bad magic number");
+ fwrite (buf, length_buf, 1, stdio->file);
+}
+
+static void
+stdio_file_fputs (linebuffer, file)
+ const char *linebuffer;
+ struct gdb_file *file;
+{
+ struct stdio_file *stdio = gdb_file_data (file);
+ if (stdio->magic != &stdio_file_magic)
+ internal_error ("stdio_file_fputs: bad magic number");
+ fputs (linebuffer, stdio->file);
+}
+
+static int
+stdio_file_isatty (file)
+ struct gdb_file *file;
+{
+ struct stdio_file *stdio = gdb_file_data (file);
+ if (stdio->magic != &stdio_file_magic)
+ internal_error ("stdio_file_isatty: bad magic number");
+ return (isatty (fileno (stdio->file)));
+}
+
+/* Like fdopen(). Create a gdb_file from a previously opened FILE. */
+
+struct gdb_file *
+stdio_fileopen (file)
+ FILE *file;
+{
+ return stdio_file_new (file, 0);
+}
+
+
+/* A pure memory based ``struct gdb_file'' that can be used an output
+ buffer. The buffers accumulated contents are available via
+ gdb_file_put(). */
+
+struct mem_file
+ {
+ int *magic;
+ char *buffer;
+ int sizeof_buffer;
+ int length_buffer;
+ };
+
+static gdb_file_rewind_ftype mem_file_rewind;
+static gdb_file_put_ftype mem_file_put;
+static gdb_file_write_ftype mem_file_write;
+static gdb_file_delete_ftype mem_file_delete;
+static struct gdb_file *mem_file_new PARAMS ((void));
+static int mem_file_magic;
+
+static struct gdb_file *
+mem_file_new (void)
+{
+ struct mem_file *stream = XMALLOC (struct mem_file);
+ struct gdb_file *file = gdb_file_new ();
+ set_gdb_file_data (file, stream, mem_file_delete);
+ set_gdb_file_rewind (file, mem_file_rewind);
+ set_gdb_file_put (file, mem_file_put);
+ set_gdb_file_write (file, mem_file_write);
+ stream->magic = &mem_file_magic;
+ stream->buffer = NULL;
+ stream->sizeof_buffer = 0;
+ stream->length_buffer = 0;
+ return file;
+}
+
+static void
+mem_file_delete (struct gdb_file *file)
+{
+ struct mem_file *stream = gdb_file_data (file);
+ if (stream->magic != &mem_file_magic)
+ internal_error ("mem_file_delete: bad magic number");
+ if (stream->buffer != NULL)
+ free (stream->buffer);
+ free (stream);
+}
+
+struct gdb_file *
+mem_fileopen (void)
+{
+ return mem_file_new ();
+}
+
+static void
+mem_file_rewind (struct gdb_file *file)
+{
+ struct mem_file *stream = gdb_file_data (file);
+ if (stream->magic != &mem_file_magic)
+ internal_error ("mem_file_rewind: bad magic number");
+ stream->length_buffer = 0;
+}
+
+static void
+mem_file_put (struct gdb_file *file,
+ gdb_file_put_method_ftype *write,
+ void *dest)
+{
+ struct mem_file *stream = gdb_file_data (file);
+ if (stream->magic != &mem_file_magic)
+ internal_error ("mem_file_put: bad magic number");
+ if (stream->length_buffer > 0)
+ write (dest, stream->buffer, stream->length_buffer);
+}
+
+void
+mem_file_write (struct gdb_file *file,
+ const char *buffer,
+ long length_buffer)
+{
+ struct mem_file *stream = gdb_file_data (file);
+ if (stream->magic != &mem_file_magic)
+ internal_error ("mem_file_write: bad magic number");
+ if (stream->buffer == NULL)
+ {
+ stream->length_buffer = length_buffer;
+ stream->sizeof_buffer = length_buffer;
+ stream->buffer = xmalloc (stream->sizeof_buffer);
+ memcpy (stream->buffer, buffer, length_buffer);
+ }
+ else
+ {
+ int new_length = stream->length_buffer + length_buffer;
+ if (new_length >= stream->sizeof_buffer)
+ {
+ stream->sizeof_buffer = new_length;
+ stream->buffer = xrealloc (stream->buffer, stream->sizeof_buffer);
+ }
+ memcpy (stream->buffer + stream->length_buffer, buffer, length_buffer);
+ stream->length_buffer = new_length;
+ }
+}
+
+/* A ``struct gdb_file'' that is compatible with all the legacy
+ code. */
+
+/* new */
+enum streamtype
+{
+ afile,
+ astring
+};
+
+/* new */
+struct tui_stream
+{
+ int *ts_magic;
+ enum streamtype ts_streamtype;
+ FILE *ts_filestream;
+ char *ts_strbuf;
+ int ts_buflen;
+};
+
+static gdb_file_flush_ftype tui_file_flush;
+extern gdb_file_fputs_ftype tui_file_fputs;
+static gdb_file_isatty_ftype tui_file_isatty;
+static gdb_file_rewind_ftype tui_file_rewind;
+static gdb_file_put_ftype tui_file_put;
+static gdb_file_delete_ftype tui_file_delete;
+static struct gdb_file *tui_file_new PARAMS ((void));
+static int tui_file_magic;
+
+static struct gdb_file *
+tui_file_new ()
+{
+ struct tui_stream *tui = xmalloc (sizeof (struct tui_stream));
+ struct gdb_file *file = gdb_file_new ();
+ set_gdb_file_data (file, tui, tui_file_delete);
+ set_gdb_file_flush (file, tui_file_flush);
+ set_gdb_file_fputs (file, tui_file_fputs);
+ set_gdb_file_isatty (file, tui_file_isatty);
+ set_gdb_file_rewind (file, tui_file_rewind);
+ set_gdb_file_put (file, tui_file_put);
+ tui->ts_magic = &tui_file_magic;
+ return file;
+}
+
+static void
+tui_file_delete (file)
+ struct gdb_file *file;
+{
+ struct tui_stream *tmpstream = gdb_file_data (file);
+ if (tmpstream->ts_magic != &tui_file_magic)
+ internal_error ("tui_file_delete: bad magic number");
+ if ((tmpstream->ts_streamtype == astring) &&
+ (tmpstream->ts_strbuf != NULL))
+ {
+ free (tmpstream->ts_strbuf);
+ }
+ free (tmpstream);
+}
+
+struct gdb_file *
+tui_fileopen (stream)
+ FILE *stream;
+{
+ struct gdb_file *file = tui_file_new ();
+ struct tui_stream *tmpstream = gdb_file_data (file);
+ tmpstream->ts_streamtype = afile;
+ tmpstream->ts_filestream = stream;
+ tmpstream->ts_strbuf = NULL;
+ tmpstream->ts_buflen = 0;
+ return file;
+}
+
+struct gdb_file *
+tui_sfileopen (n)
+ int n;
+{
+ struct gdb_file *file = tui_file_new ();
+ struct tui_stream *tmpstream = gdb_file_data (file);
+ tmpstream->ts_streamtype = astring;
+ tmpstream->ts_filestream = NULL;
+ if (n > 0)
+ {
+ tmpstream->ts_strbuf = xmalloc ((n + 1) * sizeof (char));
+ tmpstream->ts_strbuf[0] = '\0';
+ }
+ else
+ /* Do not allocate the buffer now. The first time something is printed
+ one will be allocated by tui_file_adjust_strbuf() */
+ tmpstream->ts_strbuf = NULL;
+ tmpstream->ts_buflen = n;
+ return file;
+}
+
+static int
+tui_file_isatty (file)
+ struct gdb_file *file;
+{
+ struct tui_stream *stream = gdb_file_data (file);
+ if (stream->ts_magic != &tui_file_magic)
+ internal_error ("tui_file_isatty: bad magic number");
+ if (stream->ts_streamtype == afile)
+ return (isatty (fileno (stream->ts_filestream)));
+ else
+ return 0;
+}
+
+static void
+tui_file_rewind (file)
+ struct gdb_file *file;
+{
+ struct tui_stream *stream = gdb_file_data (file);
+ if (stream->ts_magic != &tui_file_magic)
+ internal_error ("tui_file_rewind: bad magic number");
+ stream->ts_strbuf[0] = '\0';
+}
+
+static void
+tui_file_put (struct gdb_file *file,
+ gdb_file_put_method_ftype *write,
+ void *dest)
+{
+ struct tui_stream *stream = gdb_file_data (file);
+ if (stream->ts_magic != &tui_file_magic)
+ internal_error ("tui_file_put: bad magic number");
+ if (stream->ts_streamtype == astring)
+ write (dest, stream->ts_strbuf, strlen (stream->ts_strbuf));
+}
+
+/* All TUI I/O sent to the *_filtered and *_unfiltered functions
+ eventually ends up here. The fputs_unfiltered_hook is primarily
+ used by GUIs to collect all output and send it to the GUI, instead
+ of the controlling terminal. Only output to gdb_stdout and
+ gdb_stderr are sent to the hook. Everything else is sent on to
+ fputs to allow file I/O to be handled appropriately. */
+
+/* FIXME: Should be broken up and moved to a TUI specific file. */
+
+void
+tui_file_fputs (linebuffer, file)
+ const char *linebuffer;
+ GDB_FILE *file;
+{
+ struct tui_stream *stream = gdb_file_data (file);
+#if defined(TUI)
+ extern int tui_owns_terminal;
+#endif
+ /* NOTE: cagney/1999-10-13: The use of fputs_unfiltered_hook is
+ seriously discouraged. Those wanting to hook output should
+ instead implement their own gdb_file object and install that. See
+ also tui_file_flush(). */
+ if (fputs_unfiltered_hook
+ && (file == gdb_stdout
+ || file == gdb_stderr))
+ fputs_unfiltered_hook (linebuffer, file);
+ else
+ {
+#if defined(TUI)
+ if (tui_version && tui_owns_terminal)
+ {
+ /* If we get here somehow while updating the TUI (from
+ * within a tuiDo(), then we need to temporarily
+ * set up the terminal for GDB output. This probably just
+ * happens on error output.
+ */
+
+ if (stream->ts_streamtype == astring)
+ {
+ tui_file_adjust_strbuf (strlen (linebuffer), stream);
+ strcat (stream->ts_strbuf, linebuffer);
+ }
+ else
+ {
+ tuiTermUnsetup (0, (tui_version) ? cmdWin->detail.commandInfo.curch : 0);
+ fputs (linebuffer, stream->ts_filestream);
+ tuiTermSetup (0);
+ if (linebuffer[strlen (linebuffer) - 1] == '\n')
+ tuiClearCommandCharCount ();
+ else
+ tuiIncrCommandCharCountBy (strlen (linebuffer));
+ }
+ }
+ else
+ {
+ /* The normal case - just do a fputs() */
+ if (stream->ts_streamtype == astring)
+ {
+ tui_file_adjust_strbuf (strlen (linebuffer), stream);
+ strcat (stream->ts_strbuf, linebuffer);
+ }
+ else
+ fputs (linebuffer, stream->ts_filestream);
+ }
+
+
+#else
+ if (stream->ts_streamtype == astring)
+ {
+ tui_file_adjust_strbuf (strlen (linebuffer), file);
+ strcat (stream->ts_strbuf, linebuffer);
+ }
+ else
+ fputs (linebuffer, stream->ts_filestream);
+#endif
+ }
+}
+
+char *
+tui_file_get_strbuf (struct gdb_file *file)
+{
+ struct tui_stream *stream = gdb_file_data (file);
+ if (stream->ts_magic != &tui_file_magic)
+ internal_error ("tui_file_get_strbuf: bad magic number");
+ return (stream->ts_strbuf);
+}
+
+/* adjust the length of the buffer by the amount necessary
+ to accomodate appending a string of length N to the buffer contents */
+void
+tui_file_adjust_strbuf (int n, struct gdb_file *file)
+{
+ struct tui_stream *stream = gdb_file_data (file);
+ int non_null_chars;
+ if (stream->ts_magic != &tui_file_magic)
+ internal_error ("tui_file_adjust_strbuf: bad magic number");
+
+ if (stream->ts_streamtype != astring)
+ return;
+
+ if (stream->ts_strbuf)
+ {
+ /* There is already a buffer allocated */
+ non_null_chars = strlen (stream->ts_strbuf);
+
+ if (n > (stream->ts_buflen - non_null_chars - 1))
+ {
+ stream->ts_buflen = n + non_null_chars + 1;
+ stream->ts_strbuf = xrealloc (stream->ts_strbuf, stream->ts_buflen);
+ }
+ }
+ else
+ /* No buffer yet, so allocate one of the desired size */
+ stream->ts_strbuf = xmalloc ((n + 1) * sizeof (char));
+}
+
GDB_FILE *
gdb_fopen (name, mode)
- char * name;
- char * mode;
+ char *name;
+ char *mode;
{
- return fopen (name, mode);
+ FILE *f = fopen (name, mode);
+ if (f == NULL)
+ return NULL;
+ return stdio_file_new (f, 1);
+}
+
+static void
+tui_file_flush (file)
+ GDB_FILE *file;
+{
+ struct tui_stream *stream = gdb_file_data (file);
+ if (stream->ts_magic != &tui_file_magic)
+ internal_error ("tui_file_flush: bad magic number");
+
+ /* NOTE: cagney/1999-10-12: If we've been linked with code that uses
+ fputs_unfiltered_hook then we assume that it doesn't need to know
+ about flushes. Code that does need to know about flushes can
+ implement a proper gdb_file object. */
+ if (fputs_unfiltered_hook)
+ return;
+
+ switch (stream->ts_streamtype)
+ {
+ case astring:
+ break;
+ case afile:
+ fflush (stream->ts_filestream);
+ break;
+ }
+}
+
+/* Implement the ``struct gdb_file'' object. */
+
+static gdb_file_isatty_ftype null_file_isatty;
+static gdb_file_write_ftype null_file_write;
+static gdb_file_fputs_ftype null_file_fputs;
+static gdb_file_flush_ftype null_file_flush;
+static gdb_file_delete_ftype null_file_delete;
+static gdb_file_rewind_ftype null_file_rewind;
+static gdb_file_put_ftype null_file_put;
+
+struct gdb_file
+ {
+ int *magic;
+ gdb_file_flush_ftype *to_flush;
+ gdb_file_write_ftype *to_write;
+ gdb_file_fputs_ftype *to_fputs;
+ gdb_file_delete_ftype *to_delete;
+ gdb_file_isatty_ftype *to_isatty;
+ gdb_file_rewind_ftype *to_rewind;
+ gdb_file_put_ftype *to_put;
+ void *to_data;
+ };
+int gdb_file_magic;
+
+struct gdb_file *
+gdb_file_new ()
+{
+ struct gdb_file *file = xmalloc (sizeof (struct gdb_file));
+ file->magic = &gdb_file_magic;
+ set_gdb_file_data (file, NULL, null_file_delete);
+ set_gdb_file_flush (file, null_file_flush);
+ set_gdb_file_write (file, null_file_write);
+ set_gdb_file_fputs (file, null_file_fputs);
+ set_gdb_file_isatty (file, null_file_isatty);
+ set_gdb_file_rewind (file, null_file_rewind);
+ set_gdb_file_put (file, null_file_put);
+ return file;
}
void
-gdb_flush (stream)
- FILE *stream;
+gdb_file_delete (file)
+ struct gdb_file *file;
+{
+ file->to_delete (file);
+ free (file);
+}
+
+static int
+null_file_isatty (file)
+ struct gdb_file *file;
+{
+ return 0;
+}
+
+static void
+null_file_rewind (file)
+ struct gdb_file *file;
+{
+ return;
+}
+
+static void
+null_file_put (struct gdb_file *file,
+ gdb_file_put_method_ftype *write,
+ void *dest)
+{
+ return;
+}
+
+static void
+null_file_flush (file)
+ struct gdb_file *file;
{
- if (flush_hook
- && (stream == gdb_stdout
- || stream == gdb_stderr))
+ return;
+}
+
+static void
+null_file_write (struct gdb_file *file,
+ const char *buf,
+ long sizeof_buf)
+{
+ if (file->to_fputs == null_file_fputs)
+ /* Both the write and fputs methods are null. Discard the
+ request. */
+ return;
+ else
{
- flush_hook (stream);
+ /* The fputs method isn't null, slowly pass the write request
+ onto that. FYI, this isn't as bad as it may look - the
+ current (as of 1999-11-07) printf_* function calls fputc and
+ fputc does exactly the below. By having a write function it
+ is possible to clean up that code. */
+ int i;
+ char b[2];
+ b[1] = '\0';
+ for (i = 0; i < sizeof_buf; i++)
+ {
+ b[0] = buf[i];
+ file->to_fputs (b, file);
+ }
return;
}
+}
+
+static void
+null_file_fputs (buf, file)
+ const char *buf;
+ struct gdb_file *file;
+{
+ if (file->to_write == null_file_write)
+ /* Both the write and fputs methods are null. Discard the
+ request. */
+ return;
+ else
+ {
+ /* The write method was implemented, use that. */
+ file->to_write (file, buf, strlen (buf));
+ }
+}
+
+static void
+null_file_delete (file)
+ struct gdb_file *file;
+{
+ return;
+}
+
+void *
+gdb_file_data (file)
+ struct gdb_file *file;
+{
+ if (file->magic != &gdb_file_magic)
+ internal_error ("gdb_file_data: bad magic number");
+ return file->to_data;
+}
+
+void
+gdb_flush (file)
+ struct gdb_file *file;
+{
+ file->to_flush (file);
+}
+
+int
+gdb_file_isatty (file)
+ struct gdb_file *file;
+{
+ return file->to_isatty (file);
+}
+
+void
+gdb_file_rewind (file)
+ struct gdb_file *file;
+{
+ file->to_rewind (file);
+}
+
+void
+gdb_file_put (struct gdb_file *file,
+ gdb_file_put_method_ftype *write,
+ void *dest)
+{
+ file->to_put (file, write, dest);
+}
+
+void
+gdb_file_write (struct gdb_file *file,
+ const char *buf,
+ long length_buf)
+{
+ file->to_write (file, buf, length_buf);
+}
+
+void
+fputs_unfiltered (buf, file)
+ const char *buf;
+ struct gdb_file *file;
+{
+ file->to_fputs (buf, file);
+}
+
+void
+set_gdb_file_flush (file, flush)
+ struct gdb_file *file;
+ gdb_file_flush_ftype *flush;
+{
+ file->to_flush = flush;
+}
+
+void
+set_gdb_file_isatty (file, isatty)
+ struct gdb_file *file;
+ gdb_file_isatty_ftype *isatty;
+{
+ file->to_isatty = isatty;
+}
- fflush (stream);
+void
+set_gdb_file_rewind (file, rewind)
+ struct gdb_file *file;
+ gdb_file_rewind_ftype *rewind;
+{
+ file->to_rewind = rewind;
+}
+
+void
+set_gdb_file_put (file, put)
+ struct gdb_file *file;
+ gdb_file_put_ftype *put;
+{
+ file->to_put = put;
+}
+
+void
+set_gdb_file_write (struct gdb_file *file,
+ gdb_file_write_ftype *write)
+{
+ file->to_write = write;
+}
+
+void
+set_gdb_file_fputs (file, fputs)
+ struct gdb_file *file;
+ gdb_file_fputs_ftype *fputs;
+{
+ file->to_fputs = fputs;
+}
+
+void
+set_gdb_file_data (file, data, delete)
+ struct gdb_file *file;
+ void *data;
+ gdb_file_delete_ftype *delete;
+{
+ file->to_data = data;
+ file->to_delete = delete;
+}
+
+/* gdb_file utility function for converting a ``struct gdb_file'' into
+ a memory buffer''. */
+
+struct accumulated_gdb_file
+{
+ char *buffer;
+ long length;
+};
+
+static void
+do_gdb_file_xstrdup (void *context, const char *buffer, long length)
+{
+ struct accumulated_gdb_file *acc = context;
+ if (acc->buffer == NULL)
+ acc->buffer = xmalloc (length + 1);
+ else
+ acc->buffer = xrealloc (acc->buffer, acc->length + length + 1);
+ memcpy (acc->buffer + acc->length, buffer, length);
+ acc->length += length;
+ acc->buffer[acc->length] = '\0';
+}
+
+char *
+gdb_file_xstrdup (struct gdb_file *file,
+ long *length)
+{
+ struct accumulated_gdb_file acc;
+ acc.buffer = NULL;
+ acc.length = 0;
+ gdb_file_put (file, do_gdb_file_xstrdup, &acc);
+ if (acc.buffer == NULL)
+ acc.buffer = xstrdup ("");
+ *length = acc.length;
+ return acc.buffer;
}
+
/* Like fputs but if FILTER is true, pause after every screenful.
Regardless of FILTER can wrap at points other than the final
static void
fputs_maybe_filtered (linebuffer, stream, filter)
const char *linebuffer;
- FILE *stream;
+ GDB_FILE *stream;
int filter;
{
const char *lineptr;
return;
/* Don't do any filtering if it is disabled. */
- if (stream != gdb_stdout
- || (lines_per_page == UINT_MAX && chars_per_line == UINT_MAX))
+ if ((stream != gdb_stdout) || !pagination_enabled
+ || (lines_per_page == UINT_MAX && chars_per_line == UINT_MAX))
{
fputs_unfiltered (linebuffer, stream);
return;
/* Go through and output each character. Show line extension
when this is necessary; prompt user for new page when this is
necessary. */
-
+
lineptr = linebuffer;
while (*lineptr)
{
fputc_unfiltered ('\t', stream);
/* Shifting right by 3 produces the number of tab stops
we have already passed, and then adding one and
- shifting left 3 advances to the next tab stop. */
+ shifting left 3 advances to the next tab stop. */
chars_printed = ((chars_printed >> 3) + 1) << 3;
lineptr++;
}
if (wrap_column)
*wrap_pointer++ = *lineptr;
else
- fputc_unfiltered (*lineptr, stream);
+ fputc_unfiltered (*lineptr, stream);
chars_printed++;
lineptr++;
}
-
+
if (chars_printed >= chars_per_line)
{
unsigned int save_chars = chars_printed;
chars_printed = 0;
lines_printed++;
/* If we aren't actually wrapping, don't output newline --
- if chars_per_line is right, we probably just overflowed
- anyway; if it's wrong, let us keep going. */
+ if chars_per_line is right, we probably just overflowed
+ anyway; if it's wrong, let us keep going. */
if (wrap_column)
fputc_unfiltered ('\n', stream);
if (wrap_column)
{
fputs_unfiltered (wrap_indent, stream);
- *wrap_pointer = '\0'; /* Null-terminate saved stuff */
- fputs_unfiltered (wrap_buffer, stream); /* and eject it */
+ *wrap_pointer = '\0'; /* Null-terminate saved stuff */
+ fputs_unfiltered (wrap_buffer, stream); /* and eject it */
/* FIXME, this strlen is what prevents wrap_indent from
containing tabs. However, if we recurse to print it
and count its chars, we risk trouble if wrap_indent is
Note also that this can set chars_printed > chars_per_line
if we are printing a long string. */
chars_printed = strlen (wrap_indent)
- + (save_chars - wrap_column);
+ + (save_chars - wrap_column);
wrap_pointer = wrap_buffer; /* Reset buffer */
wrap_buffer[0] = '\0';
- wrap_column = 0; /* And disable fancy wrap */
- }
+ wrap_column = 0; /* And disable fancy wrap */
+ }
}
}
if (*lineptr == '\n')
{
chars_printed = 0;
- wrap_here ((char *)0); /* Spit out chars, cancel further wraps */
+ wrap_here ((char *) 0); /* Spit out chars, cancel further wraps */
lines_printed++;
fputc_unfiltered ('\n', stream);
lineptr++;
void
fputs_filtered (linebuffer, stream)
const char *linebuffer;
- FILE *stream;
+ GDB_FILE *stream;
{
fputs_maybe_filtered (linebuffer, stream, 1);
}
putchar_unfiltered (c)
int c;
{
- char buf[2];
-
- buf[0] = c;
- buf[1] = 0;
- fputs_unfiltered (buf, gdb_stdout);
+ char buf = c;
+ gdb_file_write (gdb_stdout, &buf, 1);
return c;
}
int
fputc_unfiltered (c, stream)
int c;
- FILE * stream;
+ GDB_FILE *stream;
{
- char buf[2];
-
- buf[0] = c;
- buf[1] = 0;
- fputs_unfiltered (buf, stream);
+ char buf = c;
+ gdb_file_write (stream, &buf, 1);
return c;
}
int
fputc_filtered (c, stream)
int c;
- FILE * stream;
+ GDB_FILE *stream;
{
char buf[2];
/* If the prefix is changing, print the previous suffix, a new line,
and the new prefix. */
- if ((return_p || (strcmp(prev_prefix, prefix) != 0)) && !new_line)
+ if ((return_p || (strcmp (prev_prefix, prefix) != 0)) && !new_line)
{
- fputs_unfiltered (prev_suffix, gdb_stderr);
- fputs_unfiltered ("\n", gdb_stderr);
- fputs_unfiltered (prefix, gdb_stderr);
+ fputs_unfiltered (prev_suffix, gdb_stdlog);
+ fputs_unfiltered ("\n", gdb_stdlog);
+ fputs_unfiltered (prefix, gdb_stdlog);
}
/* Print prefix if we printed a newline during the previous call. */
if (new_line)
{
new_line = 0;
- fputs_unfiltered (prefix, gdb_stderr);
+ fputs_unfiltered (prefix, gdb_stdlog);
}
prev_prefix = prefix;
while ((ch = *string++) != '\0')
{
switch (ch)
- {
+ {
default:
if (isprint (ch))
- fputc_unfiltered (ch, gdb_stderr);
+ fputc_unfiltered (ch, gdb_stdlog);
else
- fprintf_unfiltered (gdb_stderr, "\\x%02x", ch & 0xff);
+ fprintf_unfiltered (gdb_stdlog, "\\x%02x", ch & 0xff);
break;
- case '\\': fputs_unfiltered ("\\\\", gdb_stderr); break;
- case '\b': fputs_unfiltered ("\\b", gdb_stderr); break;
- case '\f': fputs_unfiltered ("\\f", gdb_stderr); break;
- case '\n': new_line = 1;
- fputs_unfiltered ("\\n", gdb_stderr); break;
- case '\r': fputs_unfiltered ("\\r", gdb_stderr); break;
- case '\t': fputs_unfiltered ("\\t", gdb_stderr); break;
- case '\v': fputs_unfiltered ("\\v", gdb_stderr); break;
- }
+ case '\\':
+ fputs_unfiltered ("\\\\", gdb_stdlog);
+ break;
+ case '\b':
+ fputs_unfiltered ("\\b", gdb_stdlog);
+ break;
+ case '\f':
+ fputs_unfiltered ("\\f", gdb_stdlog);
+ break;
+ case '\n':
+ new_line = 1;
+ fputs_unfiltered ("\\n", gdb_stdlog);
+ break;
+ case '\r':
+ fputs_unfiltered ("\\r", gdb_stdlog);
+ break;
+ case '\t':
+ fputs_unfiltered ("\\t", gdb_stdlog);
+ break;
+ case '\v':
+ fputs_unfiltered ("\\v", gdb_stdlog);
+ break;
+ }
return_p = ch == '\r';
}
/* Print suffix if we printed a newline. */
if (new_line)
{
- fputs_unfiltered (suffix, gdb_stderr);
- fputs_unfiltered ("\n", gdb_stderr);
+ fputs_unfiltered (suffix, gdb_stdlog);
+ fputs_unfiltered ("\n", gdb_stdlog);
}
}
static void
vfprintf_maybe_filtered (stream, format, args, filter)
- FILE *stream;
+ GDB_FILE *stream;
const char *format;
va_list args;
int filter;
void
vfprintf_filtered (stream, format, args)
- FILE *stream;
+ GDB_FILE *stream;
const char *format;
va_list args;
{
void
vfprintf_unfiltered (stream, format, args)
- FILE *stream;
+ GDB_FILE *stream;
const char *format;
va_list args;
{
vfprintf_unfiltered (gdb_stdout, format, args);
}
-/* VARARGS */
void
-#ifdef ANSI_PROTOTYPES
-fprintf_filtered (FILE *stream, const char *format, ...)
-#else
-fprintf_filtered (va_alist)
- va_dcl
-#endif
+fprintf_filtered (GDB_FILE * stream, const char *format,...)
{
va_list args;
-#ifdef ANSI_PROTOTYPES
va_start (args, format);
-#else
- FILE *stream;
- char *format;
-
- va_start (args);
- stream = va_arg (args, FILE *);
- format = va_arg (args, char *);
-#endif
vfprintf_filtered (stream, format, args);
va_end (args);
}
-/* VARARGS */
void
-#ifdef ANSI_PROTOTYPES
-fprintf_unfiltered (FILE *stream, const char *format, ...)
-#else
-fprintf_unfiltered (va_alist)
- va_dcl
-#endif
+fprintf_unfiltered (GDB_FILE * stream, const char *format,...)
{
va_list args;
-#ifdef ANSI_PROTOTYPES
va_start (args, format);
-#else
- FILE *stream;
- char *format;
-
- va_start (args);
- stream = va_arg (args, FILE *);
- format = va_arg (args, char *);
-#endif
vfprintf_unfiltered (stream, format, args);
va_end (args);
}
/* Like fprintf_filtered, but prints its result indented.
Called as fprintfi_filtered (spaces, stream, format, ...); */
-/* VARARGS */
void
-#ifdef ANSI_PROTOTYPES
-fprintfi_filtered (int spaces, FILE *stream, const char *format, ...)
-#else
-fprintfi_filtered (va_alist)
- va_dcl
-#endif
+fprintfi_filtered (int spaces, GDB_FILE * stream, const char *format,...)
{
va_list args;
-#ifdef ANSI_PROTOTYPES
va_start (args, format);
-#else
- int spaces;
- FILE *stream;
- char *format;
-
- va_start (args);
- spaces = va_arg (args, int);
- stream = va_arg (args, FILE *);
- format = va_arg (args, char *);
-#endif
print_spaces_filtered (spaces, stream);
vfprintf_filtered (stream, format, args);
}
-/* VARARGS */
void
-#ifdef ANSI_PROTOTYPES
-printf_filtered (const char *format, ...)
-#else
-printf_filtered (va_alist)
- va_dcl
-#endif
+printf_filtered (const char *format,...)
{
va_list args;
-#ifdef ANSI_PROTOTYPES
va_start (args, format);
-#else
- char *format;
-
- va_start (args);
- format = va_arg (args, char *);
-#endif
vfprintf_filtered (gdb_stdout, format, args);
va_end (args);
}
-/* VARARGS */
void
-#ifdef ANSI_PROTOTYPES
-printf_unfiltered (const char *format, ...)
-#else
-printf_unfiltered (va_alist)
- va_dcl
-#endif
+printf_unfiltered (const char *format,...)
{
va_list args;
-#ifdef ANSI_PROTOTYPES
va_start (args, format);
-#else
- char *format;
-
- va_start (args);
- format = va_arg (args, char *);
-#endif
vfprintf_unfiltered (gdb_stdout, format, args);
va_end (args);
}
/* Like printf_filtered, but prints it's result indented.
Called as printfi_filtered (spaces, format, ...); */
-/* VARARGS */
void
-#ifdef ANSI_PROTOTYPES
-printfi_filtered (int spaces, const char *format, ...)
-#else
-printfi_filtered (va_alist)
- va_dcl
-#endif
+printfi_filtered (int spaces, const char *format,...)
{
va_list args;
-#ifdef ANSI_PROTOTYPES
va_start (args, format);
-#else
- int spaces;
- char *format;
-
- va_start (args);
- spaces = va_arg (args, int);
- format = va_arg (args, char *);
-#endif
print_spaces_filtered (spaces, gdb_stdout);
vfprintf_filtered (gdb_stdout, format, args);
va_end (args);
n_spaces (n)
int n;
{
- register char *t;
- static char *spaces;
- static int max_spaces;
+ char *t;
+ static char *spaces = 0;
+ static int max_spaces = -1;
if (n > max_spaces)
{
if (spaces)
free (spaces);
- spaces = (char *) xmalloc (n+1);
- for (t = spaces+n; t != spaces;)
+ spaces = (char *) xmalloc (n + 1);
+ for (t = spaces + n; t != spaces;)
*--t = ' ';
spaces[n] = '\0';
max_spaces = n;
void
print_spaces_filtered (n, stream)
int n;
- FILE *stream;
+ GDB_FILE *stream;
{
fputs_filtered (n_spaces (n), stream);
}
void
fprintf_symbol_filtered (stream, name, lang, arg_mode)
- FILE *stream;
+ GDB_FILE *stream;
char *name;
enum language lang;
int arg_mode;
case language_cplus:
demangled = cplus_demangle (name, arg_mode);
break;
- /* start-sanitize-java */
case language_java:
demangled = cplus_demangle (name, arg_mode | DMGL_JAVA);
break;
- /* end-sanitize-java */
case language_chill:
demangled = chill_demangle (name);
break;
/* Do a strcmp() type operation on STRING1 and STRING2, ignoring any
differences in whitespace. Returns 0 if they match, non-zero if they
don't (slightly different than strcmp()'s range of return values).
-
+
As an extra hack, string1=="FOO(ARGS)" matches string2=="FOO".
This "feature" is useful when searching for matching C++ function names
(such as if the user types 'break FOO', where FOO is a mangled C++
}
return (*string1 != '\0' && *string1 != '(') || (*string2 != '\0');
}
+\f
+/*
+ ** subset_compare()
+ ** Answer whether string_to_compare is a full or partial match to
+ ** template_string. The partial match must be in sequence starting
+ ** at index 0.
+ */
+int
+subset_compare (string_to_compare, template_string)
+ char *string_to_compare;
+ char *template_string;
+{
+ int match;
+ if (template_string != (char *) NULL && string_to_compare != (char *) NULL &&
+ strlen (string_to_compare) <= strlen (template_string))
+ match = (strncmp (template_string,
+ string_to_compare,
+ strlen (string_to_compare)) == 0);
+ else
+ match = 0;
+ return match;
+}
+
+
+static void pagination_on_command PARAMS ((char *arg, int from_tty));
+static void
+pagination_on_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ pagination_enabled = 1;
+}
+
+static void pagination_on_command PARAMS ((char *arg, int from_tty));
+static void
+pagination_off_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ pagination_enabled = 0;
+}
\f
+
void
initialize_utils ()
{
struct cmd_list_element *c;
- c = add_set_cmd ("width", class_support, var_uinteger,
- (char *)&chars_per_line,
- "Set number of characters gdb thinks are in a line.",
- &setlist);
+ c = add_set_cmd ("width", class_support, var_uinteger,
+ (char *) &chars_per_line,
+ "Set number of characters gdb thinks are in a line.",
+ &setlist);
add_show_from_set (c, &showlist);
c->function.sfunc = set_width_command;
add_show_from_set
(add_set_cmd ("height", class_support,
- var_uinteger, (char *)&lines_per_page,
+ var_uinteger, (char *) &lines_per_page,
"Set number of lines gdb thinks are in a page.", &setlist),
&showlist);
-
- /* These defaults will be used if we are unable to get the correct
- values from termcap. */
-#if defined(__GO32__)
- lines_per_page = ScreenRows();
- chars_per_line = ScreenCols();
-#else
- lines_per_page = 24;
- chars_per_line = 80;
-
-#if !defined (MPW) && !defined (_WIN32)
- /* No termcap under MPW, although might be cool to do something
- by looking at worksheet or console window sizes. */
- /* Initialize the screen height and width from termcap. */
- {
- char *termtype = getenv ("TERM");
- /* Positive means success, nonpositive means failure. */
- int status;
+ init_page_info ();
- /* 2048 is large enough for all known terminals, according to the
- GNU termcap manual. */
- char term_buffer[2048];
-
- if (termtype)
- {
- status = tgetent (term_buffer, termtype);
- if (status > 0)
- {
- int val;
-
- val = tgetnum ("li");
- if (val >= 0)
- lines_per_page = val;
- else
- /* The number of lines per page is not mentioned
- in the terminal description. This probably means
- that paging is not useful (e.g. emacs shell window),
- so disable paging. */
- lines_per_page = UINT_MAX;
-
- val = tgetnum ("co");
- if (val >= 0)
- chars_per_line = val;
- }
- }
- }
-#endif /* MPW */
-
-#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER)
-
- /* If there is a better way to determine the window size, use it. */
- SIGWINCH_HANDLER (SIGWINCH);
-#endif
-#endif
/* If the output is not a terminal, don't paginate it. */
- if (!ISATTY (gdb_stdout))
+ if (!GDB_FILE_ISATTY (gdb_stdout))
lines_per_page = UINT_MAX;
- set_width_command ((char *)NULL, 0, c);
+ set_width_command ((char *) NULL, 0, c);
add_show_from_set
- (add_set_cmd ("demangle", class_support, var_boolean,
- (char *)&demangle,
- "Set demangling of encoded C++ names when displaying symbols.",
+ (add_set_cmd ("demangle", class_support, var_boolean,
+ (char *) &demangle,
+ "Set demangling of encoded C++ names when displaying symbols.",
&setprintlist),
&showprintlist);
add_show_from_set
- (add_set_cmd ("sevenbit-strings", class_support, var_boolean,
- (char *)&sevenbit_strings,
- "Set printing of 8-bit characters in strings as \\nnn.",
+ (add_set_cmd ("pagination", class_support,
+ var_boolean, (char *) &pagination_enabled,
+ "Set state of pagination.", &setlist),
+ &showlist);
+ if (xdb_commands)
+ {
+ add_com ("am", class_support, pagination_on_command,
+ "Enable pagination");
+ add_com ("sm", class_support, pagination_off_command,
+ "Disable pagination");
+ }
+
+ add_show_from_set
+ (add_set_cmd ("sevenbit-strings", class_support, var_boolean,
+ (char *) &sevenbit_strings,
+ "Set printing of 8-bit characters in strings as \\nnn.",
&setprintlist),
&showprintlist);
add_show_from_set
- (add_set_cmd ("asm-demangle", class_support, var_boolean,
- (char *)&asm_demangle,
- "Set demangling of C++ names in disassembly listings.",
+ (add_set_cmd ("asm-demangle", class_support, var_boolean,
+ (char *) &asm_demangle,
+ "Set demangling of C++ names in disassembly listings.",
&setprintlist),
&showprintlist);
}
/* Machine specific function to handle SIGWINCH signal. */
#ifdef SIGWINCH_HANDLER_BODY
- SIGWINCH_HANDLER_BODY
+SIGWINCH_HANDLER_BODY
#endif
\f
/* Support for converting target fp numbers into host DOUBLEST format. */
this field. */
result |=
(*(data + cur_byte) & ((1 << (len - cur_bitshift)) - 1))
- << cur_bitshift;
+ << cur_bitshift;
else
result |= *(data + cur_byte) << cur_bitshift;
cur_bitshift += FLOATFORMAT_CHAR_BIT;
}
return result;
}
-
+
/* Convert from FMT to a DOUBLEST.
FROM is the address of the extended float.
Store the DOUBLEST in *TO. */
char *from;
DOUBLEST *to;
{
- unsigned char *ufrom = (unsigned char *)from;
+ unsigned char *ufrom = (unsigned char *) from;
DOUBLEST dto;
long exponent;
unsigned long mant;
than sizeof(long) for the target. FIXME: Assumes sizeof(long)
for the target is 4. */
- if (fmt -> byteorder == floatformat_littlebyte_bigword)
+ if (fmt->byteorder == floatformat_littlebyte_bigword)
{
static unsigned char *newfrom;
unsigned char *swapin, *swapout;
int longswaps;
- longswaps = fmt -> totalsize / FLOATFORMAT_CHAR_BIT;
+ longswaps = fmt->totalsize / FLOATFORMAT_CHAR_BIT;
longswaps >>= 3;
-
+
if (newfrom == NULL)
{
- newfrom = (unsigned char *) xmalloc (fmt -> totalsize);
+ newfrom = (unsigned char *) xmalloc (fmt->totalsize);
}
swapout = newfrom;
swapin = ufrom;
special_exponent = exponent == 0 || exponent == fmt->exp_nan;
-/* Don't bias zero's, denorms or NaNs. */
+/* Don't bias NaNs. Use minimum exponent for denorms. For simplicity,
+ we don't check for zero as the exponent doesn't matter. */
if (!special_exponent)
exponent -= fmt->exp_bias;
+ else if (exponent == 0)
+ exponent = 1 - fmt->exp_bias;
/* Build the result algebraically. Might go infinite, underflow, etc;
who cares. */
increment the exponent by one to account for the integer bit. */
if (!special_exponent)
- if (fmt->intbit == floatformat_intbit_no)
- dto = ldexp (1.0, exponent);
- else
- exponent++;
+ {
+ if (fmt->intbit == floatformat_intbit_no)
+ dto = ldexp (1.0, exponent);
+ else
+ exponent++;
+ }
while (mant_bits_left > 0)
{
mant_bits = min (mant_bits_left, 32);
mant = get_field (ufrom, fmt->byteorder, fmt->totalsize,
- mant_off, mant_bits);
+ mant_off, mant_bits);
- dto += ldexp ((double)mant, exponent - mant_bits);
+ dto += ldexp ((double) mant, exponent - mant_bits);
exponent -= mant_bits;
mant_off += mant_bits;
mant_bits_left -= mant_bits;
}
*eptr = exp;
- return value/tmp;
+ return value / tmp;
}
#endif /* HAVE_LONG_DOUBLE */
DOUBLEST mant;
unsigned int mant_bits, mant_off;
int mant_bits_left;
- unsigned char *uto = (unsigned char *)to;
+ unsigned char *uto = (unsigned char *) to;
memcpy (&dfrom, from, sizeof (dfrom));
memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT);
mant_bits = mant_bits_left < 32 ? mant_bits_left : 32;
mant *= 4294967296.0;
- mant_long = (unsigned long)mant;
+ mant_long = (unsigned long) mant;
mant -= mant_long;
/* If the integer bit is implicit, then we need to discard it.
- If we are discarding a zero, we should be (but are not) creating
- a denormalized number which means adjusting the exponent
- (I think). */
+ If we are discarding a zero, we should be (but are not) creating
+ a denormalized number which means adjusting the exponent
+ (I think). */
if (mant_bits_left == fmt->man_len
&& fmt->intbit == floatformat_intbit_no)
{
mant_off += mant_bits;
mant_bits_left -= mant_bits;
}
- if (fmt -> byteorder == floatformat_littlebyte_bigword)
+ if (fmt->byteorder == floatformat_littlebyte_bigword)
{
int count;
unsigned char *swaplow = uto;
/* temporary storage using circular buffer */
#define NUMCELLS 16
#define CELLSIZE 32
-static char*
-get_cell()
+static char *
+get_cell ()
{
static char buf[NUMCELLS][CELLSIZE];
- static int cell=0;
- if (++cell>=NUMCELLS) cell=0;
+ static int cell = 0;
+ if (++cell >= NUMCELLS)
+ cell = 0;
return buf[cell];
}
*/
-static int thirty_two = 32; /* eliminate warning from compiler on 32-bit systems */
+int
+strlen_paddr (void)
+{
+ return (TARGET_PTR_BIT / 8 * 2);
+}
-char*
-paddr(addr)
- t_addr addr;
+
+/* eliminate warning from compiler on 32-bit systems */
+static int thirty_two = 32;
+
+char *
+paddr (CORE_ADDR addr)
{
- char *paddr_str=get_cell();
- switch (sizeof(t_addr))
+ char *paddr_str = get_cell ();
+ switch (TARGET_PTR_BIT / 8)
{
- case 8:
- sprintf (paddr_str, "%08lx%08lx",
- (unsigned long) (addr >> thirty_two), (unsigned long) (addr & 0xffffffff));
- break;
- case 4:
- sprintf (paddr_str, "%08lx", (unsigned long) addr);
- break;
- case 2:
- sprintf (paddr_str, "%04x", (unsigned short) (addr & 0xffff));
- break;
- default:
- sprintf (paddr_str, "%lx", (unsigned long) addr);
+ case 8:
+ sprintf (paddr_str, "%08lx%08lx",
+ (unsigned long) (addr >> thirty_two), (unsigned long) (addr & 0xffffffff));
+ break;
+ case 4:
+ sprintf (paddr_str, "%08lx", (unsigned long) addr);
+ break;
+ case 2:
+ sprintf (paddr_str, "%04x", (unsigned short) (addr & 0xffff));
+ break;
+ default:
+ sprintf (paddr_str, "%lx", (unsigned long) addr);
}
return paddr_str;
}
-char*
-preg(reg)
- t_reg reg;
+char *
+paddr_nz (CORE_ADDR addr)
{
- char *preg_str=get_cell();
- switch (sizeof(t_reg))
+ char *paddr_str = get_cell ();
+ switch (TARGET_PTR_BIT / 8)
{
- case 8:
- sprintf (preg_str, "%08lx%08lx",
- (unsigned long) (reg >> thirty_two), (unsigned long) (reg & 0xffffffff));
- break;
- case 4:
- sprintf (preg_str, "%08lx", (unsigned long) reg);
- break;
- case 2:
- sprintf (preg_str, "%04x", (unsigned short) (reg & 0xffff));
+ case 8:
+ {
+ unsigned long high = (unsigned long) (addr >> thirty_two);
+ if (high == 0)
+ sprintf (paddr_str, "%lx", (unsigned long) (addr & 0xffffffff));
+ else
+ sprintf (paddr_str, "%lx%08lx",
+ high, (unsigned long) (addr & 0xffffffff));
break;
- default:
- sprintf (preg_str, "%lx", (unsigned long) reg);
+ }
+ case 4:
+ sprintf (paddr_str, "%lx", (unsigned long) addr);
+ break;
+ case 2:
+ sprintf (paddr_str, "%x", (unsigned short) (addr & 0xffff));
+ break;
+ default:
+ sprintf (paddr_str, "%lx", (unsigned long) addr);
}
- return preg_str;
+ return paddr_str;
}
-char*
-paddr_nz(addr)
- t_addr addr;
+static void
+decimal2str (char *paddr_str, char *sign, ULONGEST addr)
{
- char *paddr_str=get_cell();
- switch (sizeof(t_addr))
+ /* steal code from valprint.c:print_decimal(). Should this worry
+ about the real size of addr as the above does? */
+ unsigned long temp[3];
+ int i = 0;
+ do
{
- case 8:
- {
- unsigned long high = (unsigned long) (addr >> thirty_two);
- if (high == 0)
- sprintf (paddr_str, "%lx", (unsigned long) (addr & 0xffffffff));
- else
- sprintf (paddr_str, "%lx%08lx",
- high, (unsigned long) (addr & 0xffffffff));
- break;
- }
- case 4:
- sprintf (paddr_str, "%lx", (unsigned long) addr);
- break;
- case 2:
- sprintf (paddr_str, "%x", (unsigned short) (addr & 0xffff));
- break;
- default:
- sprintf (paddr_str,"%lx", (unsigned long) addr);
+ temp[i] = addr % (1000 * 1000 * 1000);
+ addr /= (1000 * 1000 * 1000);
+ i++;
}
+ while (addr != 0 && i < (sizeof (temp) / sizeof (temp[0])));
+ switch (i)
+ {
+ case 1:
+ sprintf (paddr_str, "%s%lu",
+ sign, temp[0]);
+ break;
+ case 2:
+ sprintf (paddr_str, "%s%lu%09lu",
+ sign, temp[1], temp[0]);
+ break;
+ case 3:
+ sprintf (paddr_str, "%s%lu%09lu%09lu",
+ sign, temp[2], temp[1], temp[0]);
+ break;
+ default:
+ abort ();
+ }
+}
+
+char *
+paddr_u (CORE_ADDR addr)
+{
+ char *paddr_str = get_cell ();
+ decimal2str (paddr_str, "", addr);
+ return paddr_str;
+}
+
+char *
+paddr_d (LONGEST addr)
+{
+ char *paddr_str = get_cell ();
+ if (addr < 0)
+ decimal2str (paddr_str, "-", -addr);
+ else
+ decimal2str (paddr_str, "", addr);
return paddr_str;
}
-char*
-preg_nz(reg)
- t_reg reg;
+char *
+preg (reg)
+ t_reg reg;
{
- char *preg_str=get_cell();
- switch (sizeof(t_reg))
+ char *preg_str = get_cell ();
+ switch (sizeof (t_reg))
{
- case 8:
- {
- unsigned long high = (unsigned long) (reg >> thirty_two);
- if (high == 0)
- sprintf (preg_str, "%lx", (unsigned long) (reg & 0xffffffff));
- else
- sprintf (preg_str, "%lx%08lx",
- high, (unsigned long) (reg & 0xffffffff));
- break;
- }
- case 4:
- sprintf (preg_str, "%lx", (unsigned long) reg);
- break;
- case 2:
- sprintf (preg_str, "%x", (unsigned short) (reg & 0xffff));
+ case 8:
+ sprintf (preg_str, "%08lx%08lx",
+ (unsigned long) (reg >> thirty_two), (unsigned long) (reg & 0xffffffff));
+ break;
+ case 4:
+ sprintf (preg_str, "%08lx", (unsigned long) reg);
+ break;
+ case 2:
+ sprintf (preg_str, "%04x", (unsigned short) (reg & 0xffff));
+ break;
+ default:
+ sprintf (preg_str, "%lx", (unsigned long) reg);
+ }
+ return preg_str;
+}
+
+char *
+preg_nz (reg)
+ t_reg reg;
+{
+ char *preg_str = get_cell ();
+ switch (sizeof (t_reg))
+ {
+ case 8:
+ {
+ unsigned long high = (unsigned long) (reg >> thirty_two);
+ if (high == 0)
+ sprintf (preg_str, "%lx", (unsigned long) (reg & 0xffffffff));
+ else
+ sprintf (preg_str, "%lx%08lx",
+ high, (unsigned long) (reg & 0xffffffff));
break;
- default:
- sprintf (preg_str, "%lx", (unsigned long) reg);
+ }
+ case 4:
+ sprintf (preg_str, "%lx", (unsigned long) reg);
+ break;
+ case 2:
+ sprintf (preg_str, "%x", (unsigned short) (reg & 0xffff));
+ break;
+ default:
+ sprintf (preg_str, "%lx", (unsigned long) reg);
}
return preg_str;
}
+
+/* Helper functions for INNER_THAN */
+int
+core_addr_lessthan (lhs, rhs)
+ CORE_ADDR lhs;
+ CORE_ADDR rhs;
+{
+ return (lhs < rhs);
+}
+
+int
+core_addr_greaterthan (lhs, rhs)
+ CORE_ADDR lhs;
+ CORE_ADDR rhs;
+{
+ return (lhs > rhs);
+}