1092 lines
23 KiB
C
1092 lines
23 KiB
C
/*-
|
||
* This code is derived from software copyrighted by the Free Software
|
||
* Foundation.
|
||
*
|
||
* Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
|
||
* Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
|
||
*/
|
||
|
||
#ifndef lint
|
||
/*static char sccsid[] = "from: @(#)utils.c 6.4 (Berkeley) 5/8/91";*/
|
||
static char rcsid[] = "$Id: utils.c,v 1.3 1993/12/07 19:58:35 mycroft Exp $";
|
||
#endif /* not lint */
|
||
|
||
/* General utility routines for GDB, the GNU debugger.
|
||
Copyright (C) 1986, 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 "param.h"
|
||
|
||
#include <stdio.h>
|
||
#include <ctype.h>
|
||
#include <signal.h>
|
||
#include <sys/ioctl.h>
|
||
#include <sys/param.h>
|
||
#include <sys/errno.h>
|
||
#include <pwd.h>
|
||
#include "defs.h"
|
||
#ifdef HAVE_TERMIO
|
||
#include <termio.h>
|
||
#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 FILE *instream;
|
||
|
||
void error ();
|
||
void fatal ();
|
||
|
||
/* Chain of cleanup actions established with make_cleanup,
|
||
to be executed if an error happens. */
|
||
|
||
static struct cleanup *cleanup_chain;
|
||
|
||
/* Nonzero means a quit has been requested. */
|
||
|
||
int quit_flag;
|
||
|
||
/* Nonzero means quit immediately if Control-C is typed now,
|
||
rather than waiting until QUIT is executed. */
|
||
|
||
int immediate_quit;
|
||
|
||
/* Add a new cleanup to the cleanup_chain,
|
||
and return the previous chain pointer
|
||
to be passed later to do_cleanups or discard_cleanups.
|
||
Args are FUNCTION to clean up with, and ARG to pass to it. */
|
||
|
||
struct cleanup *
|
||
make_cleanup (function, arg)
|
||
void (*function) ();
|
||
int arg;
|
||
{
|
||
register struct cleanup *new
|
||
= (struct cleanup *) xmalloc (sizeof (struct cleanup));
|
||
register struct cleanup *old_chain = cleanup_chain;
|
||
|
||
new->next = cleanup_chain;
|
||
new->function = function;
|
||
new->arg = arg;
|
||
cleanup_chain = new;
|
||
|
||
return old_chain;
|
||
}
|
||
|
||
/* Discard cleanups and do the actions they describe
|
||
until we get back to the point OLD_CHAIN in the cleanup_chain. */
|
||
|
||
void
|
||
do_cleanups (old_chain)
|
||
register struct cleanup *old_chain;
|
||
{
|
||
register struct cleanup *ptr;
|
||
while ((ptr = cleanup_chain) != old_chain)
|
||
{
|
||
(*ptr->function) (ptr->arg);
|
||
cleanup_chain = ptr->next;
|
||
free (ptr);
|
||
}
|
||
}
|
||
|
||
/* Discard cleanups, not doing the actions they describe,
|
||
until we get back to the point OLD_CHAIN in the cleanup_chain. */
|
||
|
||
void
|
||
discard_cleanups (old_chain)
|
||
register struct cleanup *old_chain;
|
||
{
|
||
register struct cleanup *ptr;
|
||
while ((ptr = cleanup_chain) != old_chain)
|
||
{
|
||
cleanup_chain = ptr->next;
|
||
free (ptr);
|
||
}
|
||
}
|
||
|
||
/* Set the cleanup_chain to 0, and return the old cleanup chain. */
|
||
struct cleanup *
|
||
save_cleanups ()
|
||
{
|
||
struct cleanup *old_chain = cleanup_chain;
|
||
|
||
cleanup_chain = 0;
|
||
return old_chain;
|
||
}
|
||
|
||
/* Restore the cleanup chain from a previously saved chain. */
|
||
void
|
||
restore_cleanups (chain)
|
||
struct cleanup *chain;
|
||
{
|
||
cleanup_chain = chain;
|
||
}
|
||
|
||
/* This function is useful for cleanups.
|
||
Do
|
||
|
||
foo = xmalloc (...);
|
||
old_chain = make_cleanup (free_current_contents, &foo);
|
||
|
||
to arrange to free the object thus allocated. */
|
||
|
||
void
|
||
free_current_contents (location)
|
||
char **location;
|
||
{
|
||
free (*location);
|
||
}
|
||
|
||
/* Generally useful subroutines used throughout the program. */
|
||
|
||
/* Like malloc but get error if no storage available. */
|
||
|
||
char *
|
||
xmalloc (size)
|
||
long size;
|
||
{
|
||
register char *val = (char *) malloc (size);
|
||
if (!val)
|
||
fatal ("virtual memory exhausted.", 0);
|
||
return val;
|
||
}
|
||
|
||
/* Like realloc but get error if no storage available. */
|
||
|
||
char *
|
||
xrealloc (ptr, size)
|
||
char *ptr;
|
||
long size;
|
||
{
|
||
register char *val = (char *) realloc (ptr, size);
|
||
if (!val)
|
||
fatal ("virtual memory exhausted.", 0);
|
||
return val;
|
||
}
|
||
|
||
/* Print the system error message for errno, and also mention STRING
|
||
as the file name for which the error was encountered.
|
||
Then return to command level. */
|
||
|
||
void
|
||
perror_with_name (string)
|
||
char *string;
|
||
{
|
||
const char *err;
|
||
char *combined;
|
||
|
||
if (errno < sys_nerr)
|
||
err = sys_errlist[errno];
|
||
else
|
||
err = "unknown error";
|
||
|
||
combined = (char *) alloca (strlen (err) + strlen (string) + 3);
|
||
strcpy (combined, string);
|
||
strcat (combined, ": ");
|
||
strcat (combined, err);
|
||
|
||
error ("%s.", combined);
|
||
}
|
||
|
||
/* Print the system error message for ERRCODE, and also mention STRING
|
||
as the file name for which the error was encountered. */
|
||
|
||
void
|
||
print_sys_errmsg (string, errcode)
|
||
char *string;
|
||
int errcode;
|
||
{
|
||
const char *err;
|
||
char *combined;
|
||
|
||
if (errcode < sys_nerr)
|
||
err = sys_errlist[errcode];
|
||
else
|
||
err = "unknown error";
|
||
|
||
combined = (char *) alloca (strlen (err) + strlen (string) + 3);
|
||
strcpy (combined, string);
|
||
strcat (combined, ": ");
|
||
strcat (combined, err);
|
||
|
||
printf ("%s.\n", combined);
|
||
}
|
||
|
||
void
|
||
quit ()
|
||
{
|
||
#ifdef HAVE_TERMIO
|
||
ioctl (fileno (stdout), TCFLSH, 1);
|
||
#else /* not HAVE_TERMIO */
|
||
ioctl (fileno (stdout), TIOCFLUSH, 0);
|
||
#endif /* not HAVE_TERMIO */
|
||
#ifdef TIOCGPGRP
|
||
error ("Quit");
|
||
#else
|
||
error ("Quit (expect signal %d when inferior is resumed)", SIGINT);
|
||
#endif /* TIOCGPGRP */
|
||
}
|
||
|
||
/* Control C comes here */
|
||
|
||
void
|
||
request_quit ()
|
||
{
|
||
extern int remote_debugging;
|
||
|
||
quit_flag = 1;
|
||
|
||
#ifdef USG
|
||
/* Restore the signal handler. */
|
||
signal (SIGINT, request_quit);
|
||
#endif
|
||
|
||
if (immediate_quit)
|
||
quit();
|
||
}
|
||
|
||
/* Print an error message and return to command level.
|
||
STRING is the error message, used as a fprintf string,
|
||
and ARG is passed as an argument to it. */
|
||
|
||
void
|
||
error (string, arg1, arg2, arg3)
|
||
char *string;
|
||
int arg1, arg2, arg3;
|
||
{
|
||
terminal_ours (); /* Should be ok even if no inf. */
|
||
fflush (stdout);
|
||
fprintf (stderr, string, arg1, arg2, arg3);
|
||
fprintf (stderr, "\n");
|
||
return_to_top_level ();
|
||
}
|
||
|
||
/* Print an error message and exit reporting failure.
|
||
This is for a error that we cannot continue from.
|
||
STRING and ARG are passed to fprintf. */
|
||
|
||
void
|
||
fatal (string, arg)
|
||
char *string;
|
||
int arg;
|
||
{
|
||
fprintf (stderr, "gdb: ");
|
||
fprintf (stderr, string, arg);
|
||
fprintf (stderr, "\n");
|
||
exit (1);
|
||
}
|
||
|
||
/* Print an error message and exit, dumping core.
|
||
STRING is a printf-style control string, and ARG is a corresponding
|
||
argument. */
|
||
void
|
||
fatal_dump_core (string, arg)
|
||
char *string;
|
||
int arg;
|
||
{
|
||
/* "internal error" is always correct, since GDB should never dump
|
||
core, no matter what the input. */
|
||
fprintf (stderr, "gdb internal error: ");
|
||
fprintf (stderr, string, arg);
|
||
fprintf (stderr, "\n");
|
||
signal (SIGQUIT, SIG_DFL);
|
||
kill (getpid (), SIGQUIT);
|
||
/* We should never get here, but just in case... */
|
||
exit (1);
|
||
}
|
||
|
||
/* Make a copy of the string at PTR with SIZE characters
|
||
(and add a null character at the end in the copy).
|
||
Uses malloc to get the space. Returns the address of the copy. */
|
||
|
||
char *
|
||
savestring (ptr, size)
|
||
char *ptr;
|
||
int size;
|
||
{
|
||
register char *p = (char *) xmalloc (size + 1);
|
||
bcopy (ptr, p, size);
|
||
p[size] = 0;
|
||
return p;
|
||
}
|
||
|
||
char *
|
||
concat (s1, s2, s3)
|
||
char *s1, *s2, *s3;
|
||
{
|
||
register int len = strlen (s1) + strlen (s2) + strlen (s3) + 1;
|
||
register char *val = (char *) xmalloc (len);
|
||
strcpy (val, s1);
|
||
strcat (val, s2);
|
||
strcat (val, s3);
|
||
return val;
|
||
}
|
||
|
||
void
|
||
print_spaces (n, file)
|
||
register int n;
|
||
register FILE *file;
|
||
{
|
||
while (n-- > 0)
|
||
fputc (' ', file);
|
||
}
|
||
|
||
/* Ask user a y-or-n question and return 1 iff answer is yes.
|
||
Takes three args which are given to printf to print the question.
|
||
The first, a control string, should end in "? ".
|
||
It should not say how to answer, because we do that. */
|
||
|
||
int
|
||
query (ctlstr, arg1, arg2)
|
||
char *ctlstr;
|
||
{
|
||
register int answer;
|
||
|
||
/* Automatically answer "yes" if input is not from a terminal. */
|
||
if (!input_from_terminal_p ())
|
||
return 1;
|
||
|
||
while (1)
|
||
{
|
||
printf (ctlstr, arg1, arg2);
|
||
printf ("(y or n) ");
|
||
fflush (stdout);
|
||
answer = fgetc (stdin);
|
||
clearerr (stdin); /* in case of C-d */
|
||
if (answer != '\n')
|
||
while (fgetc (stdin) != '\n') clearerr (stdin);
|
||
if (answer >= 'a')
|
||
answer -= 040;
|
||
if (answer == 'Y')
|
||
return 1;
|
||
if (answer == 'N')
|
||
return 0;
|
||
printf ("Please answer y or n.\n");
|
||
}
|
||
}
|
||
|
||
/* Parse a C escape sequence. STRING_PTR points to a variable
|
||
containing a pointer to the string to parse. That pointer
|
||
is updated past the characters we use. The value of the
|
||
escape sequence is returned.
|
||
|
||
A negative value means the sequence \ newline was seen,
|
||
which is supposed to be equivalent to nothing at all.
|
||
|
||
If \ is followed by a null character, we return a negative
|
||
value and leave the string pointer pointing at the null character.
|
||
|
||
If \ is followed by 000, we return 0 and leave the string pointer
|
||
after the zeros. A value of 0 does not mean end of string. */
|
||
|
||
int
|
||
parse_escape (string_ptr)
|
||
char **string_ptr;
|
||
{
|
||
register int c = *(*string_ptr)++;
|
||
switch (c)
|
||
{
|
||
case 'a':
|
||
return '\a';
|
||
case 'b':
|
||
return '\b';
|
||
case 'e':
|
||
return 033;
|
||
case 'f':
|
||
return '\f';
|
||
case 'n':
|
||
return '\n';
|
||
case 'r':
|
||
return '\r';
|
||
case 't':
|
||
return '\t';
|
||
case 'v':
|
||
return '\v';
|
||
case '\n':
|
||
return -2;
|
||
case 0:
|
||
(*string_ptr)--;
|
||
return 0;
|
||
case '^':
|
||
c = *(*string_ptr)++;
|
||
if (c == '\\')
|
||
c = parse_escape (string_ptr);
|
||
if (c == '?')
|
||
return 0177;
|
||
return (c & 0200) | (c & 037);
|
||
|
||
case '0':
|
||
case '1':
|
||
case '2':
|
||
case '3':
|
||
case '4':
|
||
case '5':
|
||
case '6':
|
||
case '7':
|
||
{
|
||
register int i = c - '0';
|
||
register int count = 0;
|
||
while (++count < 3)
|
||
{
|
||
if ((c = *(*string_ptr)++) >= '0' && c <= '7')
|
||
{
|
||
i *= 8;
|
||
i += c - '0';
|
||
}
|
||
else
|
||
{
|
||
(*string_ptr)--;
|
||
break;
|
||
}
|
||
}
|
||
return i;
|
||
}
|
||
default:
|
||
return c;
|
||
}
|
||
}
|
||
|
||
/* Print the character CH on STREAM as part of the contents
|
||
of a literal string whose delimiter is QUOTER. */
|
||
|
||
void
|
||
printchar (ch, stream, quoter)
|
||
unsigned char ch;
|
||
FILE *stream;
|
||
int quoter;
|
||
{
|
||
register int c = ch;
|
||
if (c < 040 || c >= 0177)
|
||
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);
|
||
}
|
||
}
|
||
|
||
static int lines_per_page, lines_printed, chars_per_line, chars_printed;
|
||
|
||
/* Set values of page and line size. */
|
||
static void
|
||
set_screensize_command (arg, from_tty)
|
||
char *arg;
|
||
int from_tty;
|
||
{
|
||
char *p = arg;
|
||
char *p1;
|
||
int tolinesize = lines_per_page;
|
||
int tocharsize = chars_per_line;
|
||
|
||
if (p == 0)
|
||
error_no_arg ("set screensize");
|
||
|
||
while (*p >= '0' && *p <= '9')
|
||
p++;
|
||
|
||
if (*p && *p != ' ' && *p != '\t')
|
||
error ("Non-integral argument given to \"set screensize\".");
|
||
|
||
tolinesize = atoi (arg);
|
||
|
||
while (*p == ' ' || *p == '\t')
|
||
p++;
|
||
|
||
if (*p)
|
||
{
|
||
p1 = p;
|
||
while (*p1 >= '0' && *p1 <= '9')
|
||
p1++;
|
||
|
||
if (*p1)
|
||
error ("Non-integral second argument given to \"set screensize\".");
|
||
|
||
tocharsize = atoi (p);
|
||
}
|
||
|
||
lines_per_page = tolinesize;
|
||
chars_per_line = tocharsize;
|
||
}
|
||
|
||
static void
|
||
instream_cleanup(stream)
|
||
FILE *stream;
|
||
{
|
||
instream = stream;
|
||
}
|
||
|
||
static void
|
||
prompt_for_continue ()
|
||
{
|
||
if (ISATTY(stdin) && ISATTY(stdout))
|
||
{
|
||
struct cleanup *old_chain = make_cleanup(instream_cleanup, instream);
|
||
char *cp, *gdb_readline();
|
||
|
||
instream = stdin;
|
||
immediate_quit++;
|
||
if (cp = gdb_readline ("---Type <return> to continue---"))
|
||
free(cp);
|
||
chars_printed = lines_printed = 0;
|
||
immediate_quit--;
|
||
do_cleanups(old_chain);
|
||
}
|
||
}
|
||
|
||
/* Reinitialize filter; ie. tell it to reset to original values. */
|
||
|
||
void
|
||
reinitialize_more_filter ()
|
||
{
|
||
lines_printed = 0;
|
||
chars_printed = 0;
|
||
}
|
||
|
||
static void
|
||
screensize_info (arg, from_tty)
|
||
char *arg;
|
||
int from_tty;
|
||
{
|
||
if (arg)
|
||
error ("\"info screensize\" does not take any arguments.");
|
||
|
||
if (!lines_per_page)
|
||
printf ("Output more filtering is disabled.\n");
|
||
else
|
||
{
|
||
printf ("Output more filtering is enabled with\n");
|
||
printf ("%d lines per page and %d characters per line.\n",
|
||
lines_per_page, chars_per_line);
|
||
}
|
||
}
|
||
|
||
/* Like fputs but pause after every screenful.
|
||
Unlike fputs, fputs_filtered does not return a value.
|
||
It is OK for LINEBUFFER to be NULL, in which case just don't print
|
||
anything.
|
||
|
||
Note that a longjmp to top level may occur in this routine
|
||
(since prompt_for_continue may do so) so this routine should not be
|
||
called when cleanups are not in place. */
|
||
|
||
void
|
||
fputs_filtered (linebuffer, stream)
|
||
char *linebuffer;
|
||
FILE *stream;
|
||
{
|
||
char *lineptr;
|
||
|
||
if (linebuffer == 0)
|
||
return;
|
||
|
||
/* Don't do any filtering if it is disabled. */
|
||
if (stream != stdout || !ISATTY(stdout) || lines_per_page == 0)
|
||
{
|
||
fputs (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)
|
||
{
|
||
/* Possible new page. */
|
||
if (lines_printed >= lines_per_page - 1)
|
||
prompt_for_continue ();
|
||
|
||
while (*lineptr && *lineptr != '\n')
|
||
{
|
||
/* Print a single line. */
|
||
if (*lineptr == '\t')
|
||
{
|
||
putc ('\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. */
|
||
chars_printed = ((chars_printed >> 3) + 1) << 3;
|
||
lineptr++;
|
||
}
|
||
else
|
||
{
|
||
putc (*lineptr, stream);
|
||
chars_printed++;
|
||
lineptr++;
|
||
}
|
||
|
||
if (chars_printed >= chars_per_line)
|
||
{
|
||
chars_printed = 0;
|
||
lines_printed++;
|
||
/* Possible new page. */
|
||
if (lines_printed >= lines_per_page - 1)
|
||
prompt_for_continue ();
|
||
}
|
||
}
|
||
|
||
if (*lineptr == '\n')
|
||
{
|
||
lines_printed++;
|
||
putc ('\n', stream);
|
||
lineptr++;
|
||
chars_printed = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* fputs_demangled is a variant of fputs_filtered that
|
||
demangles g++ names.*/
|
||
|
||
void
|
||
fputs_demangled (linebuffer, stream, arg_mode)
|
||
char *linebuffer;
|
||
FILE *stream;
|
||
{
|
||
#ifdef __STDC__
|
||
extern char *cplus_demangle (const char *, int);
|
||
#else
|
||
extern char *cplus_demangle ();
|
||
#endif
|
||
#define SYMBOL_MAX 1024
|
||
|
||
#define SYMBOL_CHAR(c) (isascii(c) && (isalnum(c) || (c) == '_' || (c) == '$'))
|
||
|
||
char buf[SYMBOL_MAX+1];
|
||
char *p;
|
||
|
||
if (linebuffer == NULL)
|
||
return;
|
||
|
||
p = linebuffer;
|
||
|
||
while ( *p != (char) 0 ) {
|
||
int i = 0;
|
||
|
||
/* collect non-interesting characters into buf */
|
||
while ( *p != (char) 0 && !SYMBOL_CHAR(*p) ) {
|
||
buf[i++] = *p;
|
||
p++;
|
||
}
|
||
if (i > 0) {
|
||
/* output the non-interesting characters without demangling */
|
||
buf[i] = (char) 0;
|
||
fputs_filtered(buf, stream);
|
||
i = 0; /* reset buf */
|
||
}
|
||
|
||
/* and now the interesting characters */
|
||
while (i < SYMBOL_MAX && *p != (char) 0 && SYMBOL_CHAR(*p) ) {
|
||
buf[i++] = *p;
|
||
p++;
|
||
}
|
||
buf[i] = (char) 0;
|
||
if (i > 0) {
|
||
char * result;
|
||
|
||
if ( (result = cplus_demangle(buf, arg_mode)) != NULL ) {
|
||
fputs_filtered(result, stream);
|
||
free(result);
|
||
}
|
||
else {
|
||
fputs_filtered(buf, stream);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Print ARG1, ARG2, and ARG3 on stdout using format FORMAT. If this
|
||
information is going to put the amount written since the last call
|
||
to INIIALIZE_MORE_FILTER or the last page break over the page size,
|
||
print out a pause message and do a gdb_readline to get the users
|
||
permision to continue.
|
||
|
||
Unlike fprintf, this function does not return a value.
|
||
|
||
Note that this routine has a restriction that the length of the
|
||
final output line must be less than 255 characters *or* it must be
|
||
less than twice the size of the format string. This is a very
|
||
arbitrary restriction, but it is an internal restriction, so I'll
|
||
put it in. This means that the %s format specifier is almost
|
||
useless; unless the caller can GUARANTEE that the string is short
|
||
enough, fputs_filtered should be used instead.
|
||
|
||
Note also that a longjmp to top level may occur in this routine
|
||
(since prompt_for_continue may do so) so this routine should not be
|
||
called when cleanups are not in place. */
|
||
|
||
void
|
||
fprintf_filtered (stream, format, arg1, arg2, arg3, arg4, arg5, arg6)
|
||
FILE *stream;
|
||
char *format;
|
||
int arg1, arg2, arg3, arg4, arg5, arg6;
|
||
{
|
||
static char *linebuffer = (char *) 0;
|
||
static int line_size;
|
||
int format_length = strlen (format);
|
||
int numchars;
|
||
|
||
/* Allocated linebuffer for the first time. */
|
||
if (!linebuffer)
|
||
{
|
||
linebuffer = (char *) xmalloc (255);
|
||
line_size = 255;
|
||
}
|
||
|
||
/* Reallocate buffer to a larger size if this is necessary. */
|
||
if (format_length * 2 > line_size)
|
||
{
|
||
line_size = format_length * 2;
|
||
|
||
/* You don't have to copy. */
|
||
free (linebuffer);
|
||
linebuffer = (char *) xmalloc (line_size);
|
||
}
|
||
|
||
/* This won't blow up if the restrictions described above are
|
||
followed. */
|
||
(void) sprintf (linebuffer, format, arg1, arg2, arg3, arg4, arg5, arg6);
|
||
|
||
fputs_filtered (linebuffer, stream);
|
||
}
|
||
|
||
void
|
||
printf_filtered (format, arg1, arg2, arg3, arg4, arg5, arg6)
|
||
char *format;
|
||
int arg1, arg2, arg3, arg4, arg5, arg6;
|
||
{
|
||
fprintf_filtered (stdout, format, arg1, arg2, arg3, arg4, arg5, arg6);
|
||
}
|
||
|
||
/* Print N spaces. */
|
||
void
|
||
print_spaces_filtered (n, stream)
|
||
int n;
|
||
FILE *stream;
|
||
{
|
||
register char *s = (char *) alloca (n + 1);
|
||
register char *t = s;
|
||
|
||
while (n--)
|
||
*t++ = ' ';
|
||
*t = '\0';
|
||
|
||
fputs_filtered (s, stream);
|
||
}
|
||
|
||
|
||
#ifdef USG
|
||
bcopy (from, to, count)
|
||
char *from, *to;
|
||
{
|
||
memcpy (to, from, count);
|
||
}
|
||
|
||
bcmp (from, to, count)
|
||
{
|
||
return (memcmp (to, from, count));
|
||
}
|
||
|
||
bzero (to, count)
|
||
char *to;
|
||
{
|
||
while (count--)
|
||
*to++ = 0;
|
||
}
|
||
|
||
getwd (buf)
|
||
char *buf;
|
||
{
|
||
getcwd (buf, MAXPATHLEN);
|
||
}
|
||
|
||
char *
|
||
index (s, c)
|
||
char *s;
|
||
{
|
||
char *strchr ();
|
||
return strchr (s, c);
|
||
}
|
||
|
||
char *
|
||
rindex (s, c)
|
||
char *s;
|
||
{
|
||
char *strrchr ();
|
||
return strrchr (s, c);
|
||
}
|
||
|
||
#ifndef USG
|
||
char *sys_siglist[32] = {
|
||
"SIG0",
|
||
"SIGHUP",
|
||
"SIGINT",
|
||
"SIGQUIT",
|
||
"SIGILL",
|
||
"SIGTRAP",
|
||
"SIGIOT",
|
||
"SIGEMT",
|
||
"SIGFPE",
|
||
"SIGKILL",
|
||
"SIGBUS",
|
||
"SIGSEGV",
|
||
"SIGSYS",
|
||
"SIGPIPE",
|
||
"SIGALRM",
|
||
"SIGTERM",
|
||
"SIGUSR1",
|
||
"SIGUSR2",
|
||
"SIGCLD",
|
||
"SIGPWR",
|
||
"SIGWIND",
|
||
"SIGPHONE",
|
||
"SIGPOLL",
|
||
};
|
||
#endif
|
||
|
||
/* Queue routines */
|
||
|
||
struct queue {
|
||
struct queue *forw;
|
||
struct queue *back;
|
||
};
|
||
|
||
insque (item, after)
|
||
struct queue *item;
|
||
struct queue *after;
|
||
{
|
||
item->forw = after->forw;
|
||
after->forw->back = item;
|
||
|
||
item->back = after;
|
||
after->forw = item;
|
||
}
|
||
|
||
remque (item)
|
||
struct queue *item;
|
||
{
|
||
item->forw->back = item->back;
|
||
item->back->forw = item->forw;
|
||
}
|
||
#endif /* USG */
|
||
|
||
#ifdef USG
|
||
/* There is too much variation in Sys V signal numbers and names, so
|
||
we must initialize them at runtime. */
|
||
static char undoc[] = "(undocumented)";
|
||
|
||
char *sys_siglist[NSIG];
|
||
#endif /* USG */
|
||
|
||
extern struct cmd_list_element *setlist;
|
||
|
||
void
|
||
_initialize_utils ()
|
||
{
|
||
int i;
|
||
add_cmd ("screensize", class_support, set_screensize_command,
|
||
"Change gdb's notion of the size of the output screen.\n\
|
||
The first argument is the number of lines on a page.\n\
|
||
The second argument (optional) is the number of characters on a line.",
|
||
&setlist);
|
||
add_info ("screensize", screensize_info,
|
||
"Show gdb's current notion of the size of the output screen.");
|
||
|
||
/* These defaults will be used if we are unable to get the correct
|
||
values from termcap. */
|
||
lines_per_page = 24;
|
||
chars_per_line = 80;
|
||
/* Initialize the screen height and width from termcap. */
|
||
{
|
||
int 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;
|
||
|
||
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 = 0;
|
||
|
||
val = tgetnum ("co");
|
||
if (val >= 0)
|
||
chars_per_line = val;
|
||
}
|
||
}
|
||
}
|
||
|
||
#ifdef USG
|
||
/* Initialize signal names. */
|
||
for (i = 0; i < NSIG; i++)
|
||
sys_siglist[i] = undoc;
|
||
|
||
#ifdef SIGHUP
|
||
sys_siglist[SIGHUP ] = "SIGHUP";
|
||
#endif
|
||
#ifdef SIGINT
|
||
sys_siglist[SIGINT ] = "SIGINT";
|
||
#endif
|
||
#ifdef SIGQUIT
|
||
sys_siglist[SIGQUIT ] = "SIGQUIT";
|
||
#endif
|
||
#ifdef SIGILL
|
||
sys_siglist[SIGILL ] = "SIGILL";
|
||
#endif
|
||
#ifdef SIGTRAP
|
||
sys_siglist[SIGTRAP ] = "SIGTRAP";
|
||
#endif
|
||
#ifdef SIGIOT
|
||
sys_siglist[SIGIOT ] = "SIGIOT";
|
||
#endif
|
||
#ifdef SIGEMT
|
||
sys_siglist[SIGEMT ] = "SIGEMT";
|
||
#endif
|
||
#ifdef SIGFPE
|
||
sys_siglist[SIGFPE ] = "SIGFPE";
|
||
#endif
|
||
#ifdef SIGKILL
|
||
sys_siglist[SIGKILL ] = "SIGKILL";
|
||
#endif
|
||
#ifdef SIGBUS
|
||
sys_siglist[SIGBUS ] = "SIGBUS";
|
||
#endif
|
||
#ifdef SIGSEGV
|
||
sys_siglist[SIGSEGV ] = "SIGSEGV";
|
||
#endif
|
||
#ifdef SIGSYS
|
||
sys_siglist[SIGSYS ] = "SIGSYS";
|
||
#endif
|
||
#ifdef SIGPIPE
|
||
sys_siglist[SIGPIPE ] = "SIGPIPE";
|
||
#endif
|
||
#ifdef SIGALRM
|
||
sys_siglist[SIGALRM ] = "SIGALRM";
|
||
#endif
|
||
#ifdef SIGTERM
|
||
sys_siglist[SIGTERM ] = "SIGTERM";
|
||
#endif
|
||
#ifdef SIGUSR1
|
||
sys_siglist[SIGUSR1 ] = "SIGUSR1";
|
||
#endif
|
||
#ifdef SIGUSR2
|
||
sys_siglist[SIGUSR2 ] = "SIGUSR2";
|
||
#endif
|
||
#ifdef SIGCLD
|
||
sys_siglist[SIGCLD ] = "SIGCLD";
|
||
#endif
|
||
#ifdef SIGCHLD
|
||
sys_siglist[SIGCHLD ] = "SIGCHLD";
|
||
#endif
|
||
#ifdef SIGPWR
|
||
sys_siglist[SIGPWR ] = "SIGPWR";
|
||
#endif
|
||
#ifdef SIGTSTP
|
||
sys_siglist[SIGTSTP ] = "SIGTSTP";
|
||
#endif
|
||
#ifdef SIGTTIN
|
||
sys_siglist[SIGTTIN ] = "SIGTTIN";
|
||
#endif
|
||
#ifdef SIGTTOU
|
||
sys_siglist[SIGTTOU ] = "SIGTTOU";
|
||
#endif
|
||
#ifdef SIGSTOP
|
||
sys_siglist[SIGSTOP ] = "SIGSTOP";
|
||
#endif
|
||
#ifdef SIGXCPU
|
||
sys_siglist[SIGXCPU ] = "SIGXCPU";
|
||
#endif
|
||
#ifdef SIGXFSZ
|
||
sys_siglist[SIGXFSZ ] = "SIGXFSZ";
|
||
#endif
|
||
#ifdef SIGVTALRM
|
||
sys_siglist[SIGVTALRM ] = "SIGVTALRM";
|
||
#endif
|
||
#ifdef SIGPROF
|
||
sys_siglist[SIGPROF ] = "SIGPROF";
|
||
#endif
|
||
#ifdef SIGWINCH
|
||
sys_siglist[SIGWINCH ] = "SIGWINCH";
|
||
#endif
|
||
#ifdef SIGCONT
|
||
sys_siglist[SIGCONT ] = "SIGCONT";
|
||
#endif
|
||
#ifdef SIGURG
|
||
sys_siglist[SIGURG ] = "SIGURG";
|
||
#endif
|
||
#ifdef SIGIO
|
||
sys_siglist[SIGIO ] = "SIGIO";
|
||
#endif
|
||
#ifdef SIGWIND
|
||
sys_siglist[SIGWIND ] = "SIGWIND";
|
||
#endif
|
||
#ifdef SIGPHONE
|
||
sys_siglist[SIGPHONE ] = "SIGPHONE";
|
||
#endif
|
||
#ifdef SIGPOLL
|
||
sys_siglist[SIGPOLL ] = "SIGPOLL";
|
||
#endif
|
||
#endif /* USG */
|
||
}
|