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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "gdbcmd.h"
#include "symtab.h"
#include "value.h"
#include <ctype.h>
-#include <string.h>
+#include "gdb_string.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
/* Prototypes for local functions */
show_user PARAMS ((char *, int));
static void
-show_user_1 PARAMS ((struct cmd_list_element *, FILE *));
+show_user_1 PARAMS ((struct cmd_list_element *, GDB_FILE *));
static void
make_command PARAMS ((char *, int));
parse_binary_operation PARAMS ((char *));
static void
-print_doc_line PARAMS ((FILE *, char *));
+print_doc_line PARAMS ((GDB_FILE *, char *));
-/* Add element named NAME to command list *LIST.
+/* Add element named NAME.
+ CLASS is the top level category into which commands are broken down
+ for "help" purposes.
FUN should be the function to execute the command;
it will get a character string as argument, with leading
and trailing blanks already eliminated.
DOC is a documentation string for the command.
Its first line should be a complete sentence.
It should start with ? for a command that is an abbreviation
- or with * for a command that most users don't need to know about. */
+ or with * for a command that most users don't need to know about.
+
+ Add this command to command list *LIST. */
struct cmd_list_element *
add_cmd (name, class, fun, doc, list)
return c;
}
-/* ARGSUSED */
+/* This is an empty "cfunc". */
void
not_just_help_class_command (args, from_tty)
char *args;
{
}
+/* This is an empty "sfunc". */
+static void empty_sfunc PARAMS ((char *, int, struct cmd_list_element *));
+
+static void
+empty_sfunc (args, from_tty, c)
+ char *args;
+ int from_tty;
+ struct cmd_list_element *c;
+{
+}
+
/* Add element named NAME to command list LIST (the list for set
or some sublist thereof).
CLASS is as in add_cmd.
char *doc;
struct cmd_list_element **list;
{
- /* For set/show, we have to call do_setshow_command
- differently than an ordinary function (take commandlist as
- well as arg), so the function field isn't helpful. However,
- function == NULL means that it's a help class, so set the function
- to not_just_help_class_command. */
struct cmd_list_element *c
- = add_cmd (name, class, not_just_help_class_command, doc, list);
+ = add_cmd (name, class, NO_FUNCTION, doc, list);
c->type = set_cmd;
c->var_type = var_type;
c->var = var;
+ /* This needs to be something besides NO_FUNCTION so that this isn't
+ treated as a help class. */
+ c->function.sfunc = empty_sfunc;
+ return c;
+}
+
+/* Add element named NAME to command list LIST (the list for set
+ or some sublist thereof).
+ CLASS is as in add_cmd.
+ ENUMLIST is a list of strings which may follow NAME.
+ VAR is address of the variable which will contain the matching string
+ (from ENUMLIST).
+ DOC is the documentation string. */
+
+struct cmd_list_element *
+add_set_enum_cmd (name, class, enumlist, var, doc, list)
+ char *name;
+ enum command_class class;
+ char *enumlist[];
+ char *var;
+ char *doc;
+ struct cmd_list_element **list;
+{
+ struct cmd_list_element *c
+ = add_set_cmd (name, class, var_enum, var, doc, list);
+
+ c->enums = enumlist;
+
return c;
}
&& setcmd->doc[2] == 't' && setcmd->doc[3] == ' ')
showcmd->doc = concat ("Show ", setcmd->doc + 4, NULL);
else
- fprintf (stderr, "GDB internal error: Bad docstring for set command\n");
+ fprintf_unfiltered (gdb_stderr, "GDB internal error: Bad docstring for set command\n");
showcmd->next = *list;
*list = showcmd;
void
help_cmd (command, stream)
char *command;
- FILE *stream;
+ GDB_FILE *stream;
{
struct cmd_list_element *c;
extern struct cmd_list_element *cmdlist;
struct cmd_list_element *list;
char *cmdtype;
enum command_class class;
- FILE *stream;
+ GDB_FILE *stream;
{
int len;
char *cmdtype1, *cmdtype2;
/* Print only the first line of STR on STREAM. */
static void
print_doc_line (stream, str)
- FILE *stream;
+ GDB_FILE *stream;
char *str;
{
static char *line_buffer = 0;
enum command_class class;
char *prefix;
int recurse;
- FILE *stream;
+ GDB_FILE *stream;
{
register struct cmd_list_element *c;
"info" matches without ambiguity, but "a" could be "args" or "address", so
*RESULT_LIST is set to the cmd_list_element for "info". So in this case
RESULT_LIST should not be interpeted as a pointer to the beginning of a
- list; it simply points to a specific command.
+ list; it simply points to a specific command. In the case of an ambiguous
+ return *TEXT is advanced past the last non-ambiguous prefix (e.g.
+ "info t" can be "info types" or "info target"; upon return *TEXT has been
+ advanced past "info ").
If RESULT_LIST is NULL, don't set *RESULT_LIST (but don't otherwise
affect the operation).
struct cmd_list_element *last_list = 0;
struct cmd_list_element *c =
lookup_cmd_1 (line, list, &last_list, ignore_help_classes);
+#if 0
+ /* This is wrong for complete_command. */
char *ptr = (*line) + strlen (*line) - 1;
/* Clear off trailing whitespace. */
while (ptr >= *line && (*ptr == ' ' || *ptr == '\t'))
ptr--;
*(ptr + 1) = '\0';
+#endif
if (!c)
{
/* Helper function for SYMBOL_COMPLETION_FUNCTION. */
/* Return a vector of char pointers which point to the different
- possible completions in LIST of TEXT. */
+ possible completions in LIST of TEXT.
+
+ WORD points in the same buffer as TEXT, and completions should be
+ returned relative to this position. For example, suppose TEXT is "foo"
+ and we want to complete to "foobar". If WORD is "oo", return
+ "oobar"; if WORD is "baz/foo", return "baz/foobar". */
char **
-complete_on_cmdlist (list, text)
+complete_on_cmdlist (list, text, word)
struct cmd_list_element *list;
char *text;
+ char *word;
{
struct cmd_list_element *ptr;
char **matchlist;
}
matchlist[matches] = (char *)
- xmalloc (strlen (ptr->name) + 1);
- strcpy (matchlist[matches++], ptr->name);
+ xmalloc (strlen (word) + strlen (ptr->name) + 1);
+ if (word == text)
+ strcpy (matchlist[matches], ptr->name);
+ else if (word > text)
+ {
+ /* Return some portion of ptr->name. */
+ strcpy (matchlist[matches], ptr->name + (word - text));
+ }
+ else
+ {
+ /* Return some of text plus ptr->name. */
+ strncpy (matchlist[matches], word, text - word);
+ matchlist[matches][text - word] = '\0';
+ strcat (matchlist[matches], ptr->name);
+ }
+ ++matches;
+ }
+
+ if (matches == 0)
+ {
+ free ((PTR)matchlist);
+ matchlist = 0;
+ }
+ else
+ {
+ matchlist = (char **) xrealloc ((char *)matchlist, ((matches + 1)
+ * sizeof (char *)));
+ matchlist[matches] = (char *) 0;
+ }
+
+ return matchlist;
+}
+
+/* Helper function for SYMBOL_COMPLETION_FUNCTION. */
+
+/* Return a vector of char pointers which point to the different
+ possible completions in CMD of TEXT.
+
+ WORD points in the same buffer as TEXT, and completions should be
+ returned relative to this position. For example, suppose TEXT is "foo"
+ and we want to complete to "foobar". If WORD is "oo", return
+ "oobar"; if WORD is "baz/foo", return "baz/foobar". */
+
+char **
+complete_on_enum (enumlist, text, word)
+ char **enumlist;
+ char *text;
+ char *word;
+{
+ char **matchlist;
+ int sizeof_matchlist;
+ int matches;
+ int textlen = strlen (text);
+ int i;
+ char *name;
+
+ sizeof_matchlist = 10;
+ matchlist = (char **) xmalloc (sizeof_matchlist * sizeof (char *));
+ matches = 0;
+
+ for (i = 0; name = enumlist[i]; i++)
+ if (strncmp (name, text, textlen) == 0)
+ {
+ if (matches == sizeof_matchlist)
+ {
+ sizeof_matchlist *= 2;
+ matchlist = (char **) xrealloc ((char *)matchlist,
+ (sizeof_matchlist
+ * sizeof (char *)));
+ }
+
+ matchlist[matches] = (char *)
+ xmalloc (strlen (word) + strlen (name) + 1);
+ if (word == text)
+ strcpy (matchlist[matches], name);
+ else if (word > text)
+ {
+ /* Return some portion of name. */
+ strcpy (matchlist[matches], name + (word - text));
+ }
+ else
+ {
+ /* Return some of text plus name. */
+ strncpy (matchlist[matches], word, text - word);
+ matchlist[matches][text - word] = '\0';
+ strcat (matchlist[matches], name);
+ }
+ ++matches;
}
if (matches == 0)
{
/* \ at end of argument is used after spaces
so they won't be lost. */
+ /* This is obsolete now that we no longer strip
+ trailing whitespace and actually, the backslash
+ didn't get here in my test, readline or
+ something did something funky with a backslash
+ right before a newline. */
if (*p == 0)
break;
ch = parse_escape (&p);
else
*q++ = ch;
}
+#if 0
if (*(p - 1) != '\\')
*q++ = ' ';
+#endif
*q++ = '\0';
new = (char *) xrealloc (new, q - new);
if (*(char **)c->var != NULL)
error_no_arg ("integer to set it to.");
*(int *) c->var = parse_and_eval_address (arg);
break;
+ case var_enum:
+ {
+ int i;
+ int len;
+ int nmatches;
+ char *match;
+ char *p;
+
+ p = strchr (arg, ' ');
+
+ if (p)
+ len = p - arg;
+ else
+ len = strlen (arg);
+
+ nmatches = 0;
+ for (i = 0; c->enums[i]; i++)
+ if (strncmp (arg, c->enums[i], len) == 0)
+ {
+ match = c->enums[i];
+ nmatches++;
+ }
+
+ if (nmatches <= 0)
+ error ("Undefined item: \"%s\".", arg);
+
+ if (nmatches > 1)
+ error ("Ambiguous item \"%s\".", arg);
+
+ *(char **)c->var = match;
+ }
+ break;
default:
error ("gdb internal error: bad var_type in do_setshow_command");
}
else if (c->type == show_cmd)
{
/* Print doc minus "show" at start. */
- print_doc_line (stdout, c->doc + 5);
+ print_doc_line (gdb_stdout, c->doc + 5);
- fputs_filtered (" is ", stdout);
+ fputs_filtered (" is ", gdb_stdout);
wrap_here (" ");
switch (c->var_type)
{
case var_string:
{
unsigned char *p;
- fputs_filtered ("\"", stdout);
+ fputs_filtered ("\"", gdb_stdout);
for (p = *(unsigned char **) c->var; *p != '\0'; p++)
- gdb_printchar (*p, stdout, '"');
- fputs_filtered ("\"", stdout);
+ gdb_printchar (*p, gdb_stdout, '"');
+ fputs_filtered ("\"", gdb_stdout);
}
break;
case var_string_noescape:
case var_filename:
- fputs_filtered ("\"", stdout);
- fputs_filtered (*(char **) c->var, stdout);
- fputs_filtered ("\"", stdout);
+ case var_enum:
+ fputs_filtered ("\"", gdb_stdout);
+ fputs_filtered (*(char **) c->var, gdb_stdout);
+ fputs_filtered ("\"", gdb_stdout);
break;
case var_boolean:
- fputs_filtered (*(int *) c->var ? "on" : "off", stdout);
+ fputs_filtered (*(int *) c->var ? "on" : "off", gdb_stdout);
break;
case var_uinteger:
if (*(unsigned int *) c->var == UINT_MAX) {
- fputs_filtered ("unlimited", stdout);
+ fputs_filtered ("unlimited", gdb_stdout);
break;
}
/* else fall through */
case var_zinteger:
- fprintf_filtered (stdout, "%u", *(unsigned int *) c->var);
+ fprintf_filtered (gdb_stdout, "%u", *(unsigned int *) c->var);
break;
case var_integer:
if (*(int *) c->var == INT_MAX)
{
- fputs_filtered ("unlimited", stdout);
+ fputs_filtered ("unlimited", gdb_stdout);
}
else
- fprintf_filtered (stdout, "%d", *(int *) c->var);
+ fprintf_filtered (gdb_stdout, "%d", *(int *) c->var);
break;
default:
error ("gdb internal error: bad var_type in do_setshow_command");
}
- fputs_filtered (".\n", stdout);
+ fputs_filtered (".\n", gdb_stdout);
}
else
error ("gdb internal error: bad cmd_type in do_setshow_command");
cmd_show_list (*list->prefixlist, from_tty, list->prefixname + 5);
if (list->type == show_cmd)
{
- fputs_filtered (prefix, stdout);
- fputs_filtered (list->name, stdout);
- fputs_filtered (": ", stdout);
+ fputs_filtered (prefix, gdb_stdout);
+ fputs_filtered (list->name, gdb_stdout);
+ fputs_filtered (": ", gdb_stdout);
do_setshow_command ((char *)NULL, from_tty, list);
}
}
}
-#ifndef CANT_FORK
/* ARGSUSED */
static void
shell_escape (arg, from_tty)
char *arg;
int from_tty;
{
+#ifdef CANT_FORK
+ /* FIXME: what about errors (I don't know how GO32 system() handles
+ them)? */
+ system (arg);
+#else /* Can fork. */
int rc, status, pid;
char *p, *user_shell;
else
execl (user_shell, p, "-c", arg, 0);
- fprintf (stderr, "Exec of shell failed\n");
- exit (0);
+ fprintf_unfiltered (gdb_stderr, "Cannot execute %s: %s\n", user_shell,
+ safe_strerror (errno));
+ gdb_flush (gdb_stderr);
+ _exit (0177);
}
if (pid != -1)
;
else
error ("Fork failed");
+#endif /* Can fork. */
}
-#endif
-#ifndef CANT_FORK
static void
make_command (arg, from_tty)
char *arg;
shell_escape (p, from_tty);
}
-#endif
static void
show_user_1 (c, stream)
struct cmd_list_element *c;
- FILE *stream;
+ GDB_FILE *stream;
{
register struct command_line *cmdlines;
fputs_filtered ("User command ", stream);
fputs_filtered (c->name, stream);
fputs_filtered (":\n", stream);
+
while (cmdlines)
{
- fputs_filtered (cmdlines->line, stream);
- fputs_filtered ("\n", stream);
+ print_command_line (cmdlines, 4);
cmdlines = cmdlines->next;
}
fputs_filtered ("\n", stream);
c = lookup_cmd (&args, cmdlist, "", 0, 1);
if (c->class != class_user)
error ("Not a user command.");
- show_user_1 (c, stdout);
+ show_user_1 (c, gdb_stdout);
}
else
{
for (c = cmdlist; c; c = c->next)
{
if (c->class == class_user)
- show_user_1 (c, stdout);
+ show_user_1 (c, gdb_stdout);
}
}
}
void
_initialize_command ()
{
-#ifndef CANT_FORK
add_com ("shell", class_support, shell_escape,
"Execute the rest of the line as a shell command. \n\
With no arguments, run an inferior shell.");
-#endif
-#ifndef CANT_FORK
add_com ("make", class_support, make_command,
"Run the ``make'' program using the rest of the line as arguments.");
-#endif
add_cmd ("user", no_class, show_user,
"Show definitions of user defined commands.\n\
Argument is the name of the user defined command.\n\