* values.c, value.h (modify_field), callers: Make fieldval a LONGEST.
[deliverable/binutils-gdb.git] / gdb / main.c
index 8fc5d185f49447fa1a5e40553af970637fd912a0..5e00b8639ad8437ab5e111aa146c4737559f4e86 100644 (file)
@@ -1,5 +1,6 @@
 /* Top level `main' program for GDB, the GNU debugger.
-   Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+   Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992
+   Free Software Foundation, Inc.
 
 This file is part of GDB.
 
@@ -19,6 +20,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include "defs.h"
 #include "gdbcmd.h"
+#include "call-cmds.h"
 #include "symtab.h"
 #include "inferior.h"
 #include "signals.h"
@@ -70,19 +72,19 @@ static void
 command_loop_marker PARAMS ((int));
 
 static void
-print_gdb_version PARAMS ((void));
+print_gdb_version PARAMS ((FILE *));
 
 static void
 quit_command PARAMS ((char *, int));
 
 static void
-initialize_main PARAMS ((void));
+init_main PARAMS ((void));
 
 static void
-initialize_history PARAMS ((void));
+init_history PARAMS ((void));
 
 static void
-initialize_cmd_lists PARAMS ((void));
+init_cmd_lists PARAMS ((void));
 
 static void
 float_handler PARAMS ((int));
@@ -117,9 +119,6 @@ set_history_size_command PARAMS ((char *, int, struct cmd_list_element *));
 static void
 show_commands PARAMS ((char *, int));
 
-static void
-dump_me_command PARAMS ((char *, int));
-
 static void
 echo_command PARAMS ((char *, int));
 
@@ -150,6 +149,9 @@ info_command PARAMS ((char *, int));
 static void
 do_nothing PARAMS ((int));
 
+static int
+quit_cover PARAMS ((char *));
+
 static void
 disconnect PARAMS ((int));
 
@@ -167,7 +169,8 @@ source_cleanup PARAMS ((FILE *));
 #ifndef        GDBINIT_FILENAME
 #define        GDBINIT_FILENAME        ".gdbinit"
 #endif
-char gdbinit[] = GDBINIT_FILENAME;
+static char gdbinit[] = GDBINIT_FILENAME;
+static int inhibit_gdbinit = 0;
 
 #define        ALL_CLEANUPS    ((struct cleanup *)0)
 
@@ -175,6 +178,14 @@ char gdbinit[] = GDBINIT_FILENAME;
 
 extern char *version;
 
+/* Canonical host name as a string. */
+
+extern char *host_canonical;
+
+/* Canonical target name as a string. */
+
+extern char *target_canonical;
+
 /* Message to be printed before the error message, when an error occurs.  */
 
 extern char *error_pre_print;
@@ -225,7 +236,12 @@ struct cmd_list_element *enablebreaklist;
 
 struct cmd_list_element *setlist;
 
+/* Chain containing all defined unset subcommands */
+
+struct cmd_list_element *unsetlist;
+
 /* Chain containing all defined show subcommands.  */
+
 struct cmd_list_element *showlist;
 
 /* Chain containing all defined \"set history\".  */
@@ -233,12 +249,39 @@ struct cmd_list_element *showlist;
 struct cmd_list_element *sethistlist;
 
 /* Chain containing all defined \"show history\".  */
+
 struct cmd_list_element *showhistlist;
 
 /* Chain containing all defined \"unset history\".  */
 
 struct cmd_list_element *unsethistlist;
 
+/* Chain containing all defined maintenance subcommands. */
+
+#if MAINTENANCE_CMDS
+struct cmd_list_element *maintenancelist;
+#endif
+
+/* Chain containing all defined "maintenance info" subcommands. */
+
+#if MAINTENANCE_CMDS
+struct cmd_list_element *maintenanceinfolist;
+#endif
+
+/* Chain containing all defined "maintenance print" subcommands. */
+
+#if MAINTENANCE_CMDS
+struct cmd_list_element *maintenanceprintlist;
+#endif
+
+struct cmd_list_element *setprintlist;
+
+struct cmd_list_element *showprintlist;
+
+struct cmd_list_element *setchecklist;
+
+struct cmd_list_element *showchecklist;
+
 /* stdio stream that command input is being read from.  */
 
 FILE *instream;
@@ -256,7 +299,6 @@ static char dirbuf[1024];
 
 void (*window_hook) PARAMS ((FILE *, char *));
 
-extern int frame_file_full_name;
 extern int mapped_symbol_files;
 extern int readnow_symbol_files;
 
@@ -295,33 +337,63 @@ static void stop_sig PARAMS ((int));
 #define sigsetmask(n)
 #endif
 \f
-/* This is how `error' returns to command level.  */
+/* Where to go for return_to_top_level (RETURN_ERROR).  */
+static jmp_buf error_return;
+/* Where to go for return_to_top_level (RETURN_QUIT).  */
+static jmp_buf quit_return;
+
+/* Temporary variable for SET_TOP_LEVEL.  */
+static int top_level_val;
+
+/* Do a setjmp on error_return and quit_return.  catch_errors is
+   generally a cleaner way to do this, but main() would look pretty
+   ugly if it had to use catch_errors each time.  */
+
+#define SET_TOP_LEVEL() \
+  (((top_level_val = setjmp (error_return)) \
+    ? (PTR) 0 : (PTR) memcpy (quit_return, error_return, sizeof (jmp_buf))) \
+   , top_level_val)
 
-jmp_buf to_top_level;
+/* Return for reason REASON.  This generally gets back to the command
+   loop, but can be caught via catch_errors.  */
 
 NORETURN void
-return_to_top_level ()
+return_to_top_level (reason)
+     enum return_reason reason;
 {
   quit_flag = 0;
   immediate_quit = 0;
   bpstat_clear_actions(stop_bpstat);   /* Clear queued breakpoint commands */
   disable_current_display ();
   do_cleanups (ALL_CLEANUPS);
-  (NORETURN void) longjmp (to_top_level, 1);
+  (NORETURN void) longjmp
+    (reason == RETURN_ERROR ? error_return : quit_return, 1);
 }
 
-/* Call FUNC with arg ARGS, catching any errors.
-   If there is no error, return the value returned by FUNC.
-   If there is an error, print ERRSTRING, print the specific error message,
-                        then return zero.  */
+/* Call FUNC with arg ARGS, catching any errors.  If there is no
+   error, return the value returned by FUNC.  If there is an error,
+   print ERRSTRING, print the specific error message, then return
+   zero.
+
+   MASK specifies what to catch; it is normally set to
+   RETURN_MASK_ALL, if for no other reason than that the code which
+   calls catch_errors might not be set up to deal with a quit which
+   isn't caught.  But if the code can deal with it, it generally
+   should be RETURN_MASK_ERROR, unless for some reason it is more
+   useful to abort only the portion of the operation inside the
+   catch_errors.  Note that quit should return to the command line
+   fairly quickly, even if some further processing is being done.  */
 
 int
-catch_errors (func, args, errstring)
+catch_errors (func, args, errstring, mask)
      int (*func) PARAMS ((char *));
-     char *args;
+     PTR args;
      char *errstring;
+     return_mask mask;
 {
-  jmp_buf saved;
+  jmp_buf saved_error;
+  jmp_buf saved_quit;
+  jmp_buf tmp_jmp;
   int val;
   struct cleanup *saved_cleanup_chain;
   char *saved_error_pre_print;
@@ -329,18 +401,30 @@ catch_errors (func, args, errstring)
   saved_cleanup_chain = save_cleanups ();
   saved_error_pre_print = error_pre_print;
 
-  memcpy ((char *)saved, (char *)to_top_level, sizeof (jmp_buf));
+  if (mask & RETURN_MASK_ERROR)
+    memcpy ((char *)saved_error, (char *)error_return, sizeof (jmp_buf));
+  if (mask & RETURN_MASK_QUIT)
+    memcpy (saved_quit, quit_return, sizeof (jmp_buf));
   error_pre_print = errstring;
 
-  if (setjmp (to_top_level) == 0)
-    val = (*func) (args);
+  if (setjmp (tmp_jmp) == 0)
+    {
+      if (mask & RETURN_MASK_ERROR)
+       memcpy (error_return, tmp_jmp, sizeof (jmp_buf));
+      if (mask & RETURN_MASK_QUIT)
+       memcpy (quit_return, tmp_jmp, sizeof (jmp_buf));
+      val = (*func) (args);
+    }
   else
     val = 0;
 
   restore_cleanups (saved_cleanup_chain);
 
   error_pre_print = saved_error_pre_print;
-  memcpy ((char *)to_top_level, (char *)saved, sizeof (jmp_buf));
+  if (mask & RETURN_MASK_ERROR)
+    memcpy (error_return, saved_error, sizeof (jmp_buf));
+  if (mask & RETURN_MASK_QUIT)
+    memcpy (quit_return, saved_quit, sizeof (jmp_buf));
   return val;
 }
 
@@ -350,10 +434,23 @@ static void
 disconnect (signo)
 int signo;
 {
-  kill_inferior_fast ();
-  signal (signo, SIG_DFL);
+  catch_errors (quit_cover, NULL,
+               "Could not kill the program being debugged", RETURN_MASK_ALL);
+  signal (SIGHUP, SIG_DFL);
   kill (getpid (), SIGHUP);
 }
+
+/* Just a little helper function for disconnect().  */
+
+static int
+quit_cover (s)
+char *s;
+{
+  caution = 0;         /* Throw caution to the wind -- we're exiting.
+                          This prevents asking the user dumb questions.  */
+  quit_command((char *)0, 0);
+  return 0;
+}
 \f
 /* Clean up on error during a "source" command (or execution of a
    user-defined command).  */
@@ -385,7 +482,6 @@ main (argc, argv)
      char **argv;
 {
   int count;
-  static int inhibit_gdbinit = 0;
   static int quiet = 0;
   static int batch = 0;
 
@@ -410,6 +506,9 @@ main (argc, argv)
   /* Number of elements used.  */
   int ndir;
   
+  struct stat homebuf, cwdbuf;
+  char *homedir, *homeinit;
+
   register int i;
 
   /* This needs to happen before the first use of malloc.  */
@@ -422,7 +521,7 @@ main (argc, argv)
 #endif
 
   /* If error() is called from initialization code, just exit */
-  if (setjmp (to_top_level)) {
+  if (SET_TOP_LEVEL ()) {
     exit(1);
   }
 
@@ -469,6 +568,7 @@ main (argc, argv)
        {"m", no_argument, &mapped_symbol_files, 1},
        {"quiet", no_argument, &quiet, 1},
        {"q", no_argument, &quiet, 1},
+       {"silent", no_argument, &quiet, 1},
        {"nx", no_argument, &inhibit_gdbinit, 1},
        {"n", no_argument, &inhibit_gdbinit, 1},
        {"batch", no_argument, &batch, 1},
@@ -563,20 +663,19 @@ main (argc, argv)
 #endif
          case '?':
            fprintf (stderr,
-                    "Use `%s +help' for a complete list of options.\n",
+                    "Use `%s --help' for a complete list of options.\n",
                     argv[0]);
            exit (1);
          }
-
       }
+
     if (print_help)
       {
-       fputs ("\
-This is GDB, the GNU debugger.  Use the command\n\
-    gdb [options] [executable [core-file]]\n\
-to enter the debugger.\n\
-\n\
-Options available are:\n\
+       print_gdb_version(stderr);
+       fputs ("\n\
+This is the GNU debugger.  Usage:\n\
+    gdb [options] [executable-file [core-file or process-id]]\n\
+Options:\n\
   -help             Print this message.\n\
   -quiet            Do not print version number on startup.\n\
   -fullname         Output information used by emacs-GDB interface.\n\
@@ -630,9 +729,9 @@ GDB manual (available as on-line info or a printed manual).\n", stderr);
 
   /* Run the init function of each source file */
 
-  initialize_cmd_lists ();     /* This needs to be done first */
+  init_cmd_lists ();   /* This needs to be done first */
   initialize_all_files ();
-  initialize_main ();          /* But that omits this file!  Do it now */
+  init_main ();                /* But that omits this file!  Do it now */
   init_signals ();
 
   if (!quiet)
@@ -640,7 +739,7 @@ GDB manual (available as on-line info or a printed manual).\n", stderr);
       /* Print all the junk at the top, with trailing "..." if we are about
         to read a symbol file (possibly slowly).  */
       print_gnu_advertisement ();
-      print_gdb_version ();
+      print_gdb_version (stdout);
       if (symarg)
        printf_filtered ("..");
       wrap_here("");
@@ -648,12 +747,51 @@ GDB manual (available as on-line info or a printed manual).\n", stderr);
     }
 
   error_pre_print = "\n\n";
-  warning_pre_print = "\n\nwarning: ";
+  /* We may get more than one warning, don't double space all of them... */
+  warning_pre_print = "\nwarning: ";
 
+  /* We need a default language for parsing expressions, so simple things like
+     "set width 0" won't fail if no language is explicitly set in a config file
+     or implicitly set by reading an executable during startup. */
+  set_language (language_c);
+  expected_language = current_language;        /* don't warn about the change.  */
+
+  /* Read and execute $HOME/.gdbinit file, if it exists.  This is done
+     *before* all the command line arguments are processed; it sets
+     global parameters, which are independent of what file you are
+     debugging or what directory you are in.  */
+  homedir = getenv ("HOME");
+  if (homedir)
+    {
+      homeinit = (char *) alloca (strlen (getenv ("HOME")) +
+                                 strlen (gdbinit) + 10);
+      strcpy (homeinit, getenv ("HOME"));
+      strcat (homeinit, "/");
+      strcat (homeinit, gdbinit);
+      if (!inhibit_gdbinit && access (homeinit, R_OK) == 0)
+       {
+         if (!SET_TOP_LEVEL ())
+           source_command (homeinit, 0);
+       }
+      do_cleanups (ALL_CLEANUPS);
+
+      /* Do stats; no need to do them elsewhere since we'll only
+        need them if homedir is set.  Make sure that they are
+        zero in case one of them fails (this guarantees that they
+        won't match if either exists).  */
+      
+      memset (&homebuf, 0, sizeof (struct stat));
+      memset (&cwdbuf, 0, sizeof (struct stat));
+      
+      stat (homeinit, &homebuf);
+      stat (gdbinit, &cwdbuf); /* We'll only need this if
+                                      homedir was set.  */
+    }
+  
   /* Now perform all the actions indicated by the arguments.  */
   if (cdarg != NULL)
     {
-      if (!setjmp (to_top_level))
+      if (!SET_TOP_LEVEL ())
        {
          cd_command (cdarg, 0);
          init_source_path ();
@@ -662,18 +800,18 @@ GDB manual (available as on-line info or a printed manual).\n", stderr);
   do_cleanups (ALL_CLEANUPS);
 
   for (i = 0; i < ndir; i++)
-    if (!setjmp (to_top_level))
+    if (!SET_TOP_LEVEL ())
       directory_command (dirarg[i], 0);
-  free (dirarg);
+  free ((PTR)dirarg);
   do_cleanups (ALL_CLEANUPS);
 
   if (execarg != NULL
       && symarg != NULL
-      && strcmp (execarg, symarg) == 0)
+      && STREQ (execarg, symarg))
     {
       /* The exec file and the symbol-file are the same.  If we can't open
         it, better only print one error message.  */
-      if (!setjmp (to_top_level))
+      if (!SET_TOP_LEVEL ())
        {
          exec_file_command (execarg, !batch);
          symbol_file_command (symarg, 0);
@@ -682,10 +820,10 @@ GDB manual (available as on-line info or a printed manual).\n", stderr);
   else
     {
       if (execarg != NULL)
-       if (!setjmp (to_top_level))
+       if (!SET_TOP_LEVEL ())
          exec_file_command (execarg, !batch);
       if (symarg != NULL)
-       if (!setjmp (to_top_level))
+       if (!SET_TOP_LEVEL ())
          symbol_file_command (symarg, 0);
     }
   do_cleanups (ALL_CLEANUPS);
@@ -698,34 +836,15 @@ GDB manual (available as on-line info or a printed manual).\n", stderr);
   error_pre_print = "\n";
   warning_pre_print = "\nwarning: ";
 
-  /* Set the initial language. */
-  {
-    struct partial_symtab *pst = find_main_psymtab ();
-    enum language lang = language_unknown;     
-    if (pst == NULL) ;
-#if 0
-    /* A better solution would set the language when reading the psymtab.
-       This would win for symbol file formats that encode the langauge,
-       such as DWARF.  But, we don't do that yet. FIXME */
-    else if (pst->language != language_unknown)
-       lang = pst->language;
-#endif
-    else if (pst->filename != NULL)
-      lang = deduce_language_from_filename (pst->filename);
-    if (lang == language_unknown) /* Make C the default language */
-       lang = language_c;
-    set_language (lang);
-  }
-
   if (corearg != NULL)
-    if (!setjmp (to_top_level))
+    if (!SET_TOP_LEVEL ())
       core_file_command (corearg, !batch);
-    else if (isdigit (corearg[0]) && !setjmp (to_top_level))
+    else if (isdigit (corearg[0]) && !SET_TOP_LEVEL ())
       attach_command (corearg, !batch);
   do_cleanups (ALL_CLEANUPS);
 
   if (ttyarg != NULL)
-    if (!setjmp (to_top_level))
+    if (!SET_TOP_LEVEL ())
       tty_command (ttyarg, !batch);
   do_cleanups (ALL_CLEANUPS);
 
@@ -737,63 +856,33 @@ GDB manual (available as on-line info or a printed manual).\n", stderr);
   error_pre_print = 0;
   warning_pre_print = "warning: ";
 
-  {
-    struct stat homebuf, cwdbuf;
-    char *homedir, *homeinit;
-
-    /* Read init file, if it exists in home directory  */
-    homedir = getenv ("HOME");
-    if (homedir)
+  /* Read the .gdbinit file in the current directory, *if* it isn't
+     the same as the $HOME/.gdbinit file (it should exist, also).  */
+  
+  if (!homedir
+      || memcmp ((char *) &homebuf, (char *) &cwdbuf, sizeof (struct stat)))
+    if (!inhibit_gdbinit && access (gdbinit, R_OK) == 0)
       {
-       homeinit = (char *) alloca (strlen (getenv ("HOME")) +
-                                   strlen (gdbinit) + 10);
-       strcpy (homeinit, getenv ("HOME"));
-       strcat (homeinit, "/");
-       strcat (homeinit, gdbinit);
-       if (!inhibit_gdbinit && access (homeinit, R_OK) == 0)
-         if (!setjmp (to_top_level))
-           source_command (homeinit, 0);
-       do_cleanups (ALL_CLEANUPS);
-
-       /* Do stats; no need to do them elsewhere since we'll only
-          need them if homedir is set.  Make sure that they are
-          zero in case one of them fails (this guarantees that they
-          won't match if either exists).  */
-       
-       memset (&homebuf, 0, sizeof (struct stat));
-       memset (&cwdbuf, 0, sizeof (struct stat));
-       
-       stat (homeinit, &homebuf);
-       stat (gdbinit, &cwdbuf); /* We'll only need this if
-                                        homedir was set.  */
-      }
-    
-    /* Read the input file in the current directory, *if* it isn't
-       the same file (it should exist, also).  */
-
-    if (!homedir
-       || bcmp ((char *) &homebuf,
-                (char *) &cwdbuf,
-                sizeof (struct stat)))
-      if (!inhibit_gdbinit && access (gdbinit, R_OK) == 0)
-       if (!setjmp (to_top_level))
+       if (!SET_TOP_LEVEL ())
          source_command (gdbinit, 0);
-       do_cleanups (ALL_CLEANUPS);
-  }
+      }
+  do_cleanups (ALL_CLEANUPS);
 
   for (i = 0; i < ncmd; i++)
-    if (!setjmp (to_top_level))
-      {
-       if (cmdarg[i][0] == '-' && cmdarg[i][1] == '\0')
-         read_command_file (stdin);
-       else
-         source_command (cmdarg[i], !batch);
-       do_cleanups (ALL_CLEANUPS);
-      }
-  free (cmdarg);
+    {
+      if (!SET_TOP_LEVEL ())
+       {
+         if (cmdarg[i][0] == '-' && cmdarg[i][1] == '\0')
+           read_command_file (stdin);
+         else
+           source_command (cmdarg[i], !batch);
+         do_cleanups (ALL_CLEANUPS);
+       }
+    }
+  free ((PTR)cmdarg);
 
   /* Read in the old history after all the command files have been read. */
-  initialize_history();
+  init_history();
 
   if (batch)
     {
@@ -812,7 +901,7 @@ GDB manual (available as on-line info or a printed manual).\n", stderr);
 
   while (1)
     {
-      if (!setjmp (to_top_level))
+      if (!SET_TOP_LEVEL ())
        {
          do_cleanups (ALL_CLEANUPS);           /* Do complete cleanup */
          command_loop ();
@@ -822,6 +911,34 @@ GDB manual (available as on-line info or a printed manual).\n", stderr);
   /* No exit -- exit is through quit_command.  */
 }
 
+void
+execute_user_command (c, args)
+     struct cmd_list_element *c;
+     char *args;
+{
+  register struct command_line *cmdlines;
+  struct cleanup *old_chain;
+  
+  if (args)
+    error ("User-defined commands cannot take arguments.");
+
+  cmdlines = c->user_commands;
+  if (cmdlines == 0)
+    /* Null command */
+    return;
+
+  /* Set the instream to 0, indicating execution of a
+     user-defined function.  */
+  old_chain = make_cleanup (source_cleanup, instream);
+  instream = (FILE *) 0;
+  while (cmdlines)
+    {
+      execute_command (cmdlines->line, 0);
+      cmdlines = cmdlines->next;
+    }
+  do_cleanups (old_chain);
+}
+
 /* Execute the line P as a command.
    Pass FROM_TTY as second argument to the defining function.  */
 
@@ -831,9 +948,7 @@ execute_command (p, from_tty)
      int from_tty;
 {
   register struct cmd_list_element *c;
-  register struct command_line *cmdlines;
   register enum language flang;
-  static const struct language_defn *saved_language = 0;
   static int warned = 0;
 
   free_all_values ();
@@ -850,28 +965,13 @@ execute_command (p, from_tty)
       c = lookup_cmd (&p, cmdlist, "", 0, 1);
       /* Pass null arg rather than an empty one.  */
       arg = *p ? p : 0;
+
+      /* If this command has been hooked, run the hook first. */
+      if (c->hook)
+       execute_user_command (c->hook, (char *)0);
+
       if (c->class == class_user)
-       {
-         struct cleanup *old_chain;
-         
-         if (*p)
-           error ("User-defined commands cannot take arguments.");
-         cmdlines = c->user_commands;
-         if (cmdlines == 0)
-           /* Null command */
-           return;
-
-         /* Set the instream to 0, indicating execution of a
-            user-defined function.  */
-         old_chain =  make_cleanup (source_cleanup, instream);
-         instream = (FILE *) 0;
-         while (cmdlines)
-           {
-             execute_command (cmdlines->line, 0);
-             cmdlines = cmdlines->next;
-           }
-         do_cleanups (old_chain);
-       }
+       execute_user_command (c, arg);
       else if (c->type == set_cmd || c->type == show_cmd)
        do_setshow_command (arg, from_tty & caution, c);
       else if (c->function.cfunc == NO_FUNCTION)
@@ -881,13 +981,11 @@ execute_command (p, from_tty)
    }
 
   /* Tell the user if the language has changed (except first time).  */
-  if (current_language != saved_language)
+  if (current_language != expected_language)
   {
     if (language_mode == language_mode_auto) {
-      if (saved_language)
-       language_info (1);      /* Print what changed.  */
+      language_info (1);       /* Print what changed.  */
     }
-    saved_language = current_language;
     warned = 0;
   }
 
@@ -975,7 +1073,10 @@ gdb_readline (prrompt)
 
   if (prrompt)
     {
-      printf (prrompt);
+      /* Don't use a _filtered function here.  It causes the assumed
+        character position to be off, since the newline we read from
+        the user is not accounted for.  */
+      fputs (prrompt, stdout);
       fflush (stdout);
     }
   
@@ -1019,7 +1120,21 @@ static char *history_filename;
 
 /* Variables which are necessary for fancy command line editing.  */
 char *gdb_completer_word_break_characters =
-  " \t\n!@#$%^&*()-+=|~`}{[]\"';:?/>.<,";
+  " \t\n!@#$%^&*()+=|~`}{[]\"';:?/>.<,-";
+
+/* When completing on command names, we remove '-' from the list of
+   word break characters, since we use it in command names.  If the
+   readline library sees one in any of the current completion strings,
+   it thinks that the string needs to be quoted and automatically supplies
+   a leading quote. */
+char *gdb_completer_command_word_break_characters =
+  " \t\n!@#$%^&*()+=|~`}{[]\"';:?/>.<,";
+
+/* Characters that can be used to quote completion strings.  Note that we
+   can't include '"' because the gdb C parser treats such quoted sequences
+   as strings. */
+char *gdb_completer_quote_characters =
+  "'";
 
 /* Functions that are used as part of the fancy command line editing.  */
 
@@ -1033,39 +1148,109 @@ noop_completer (text)
   return NULL;
 }
 
-/* Generate symbol names one by one for the completer.  If STATE is
-   zero, then we need to initialize, otherwise the initialization has
-   already taken place.  TEXT is what we expect the symbol to start
-   with.  RL_LINE_BUFFER is available to be looked at; it contains the
-   entire text of the line.  RL_POINT is the offset in that line of
-   the cursor.  You should pretend that the line ends at RL_POINT.
-   The result is NULL if there are no more completions, else a char
-   string which is a possible completion.  */
+/* Complete on filenames.  */
+/* FIXME: This would be a lot more useful if the word breaks got set
+   to not include '/'.  Probably best to make it up to each completer
+   to do its own word breaking.  */
+char **
+filename_completer (text)
+     char *text;
+{
+  /* From readline.  */
+  extern char *filename_completion_function ();
+  int subsequent_name;
+  char **return_val;
+  int return_val_used;
+  int return_val_alloced;
+
+  return_val_used = 0;
+  /* Small for testing.  */
+  return_val_alloced = 1;
+  return_val = (char **) xmalloc (return_val_alloced * sizeof (char *));
+
+  subsequent_name = 0;
+  while (1)
+    {
+      char *p;
+      p = filename_completion_function (text, subsequent_name);
+      if (return_val_used >= return_val_alloced)
+       {
+         return_val_alloced *= 2;
+         return_val =
+           (char **) xrealloc (return_val,
+                               return_val_alloced * sizeof (char *));
+       }
+      /* The string itself has already been stored in newly malloc'd space
+        for us by filename_completion_function.  */
+      return_val[return_val_used++] = p;
+      if (p == NULL)
+       break;
+      subsequent_name = 1;
+    }
+  return return_val;
+}
+
+/* Generate symbol names one by one for the completer.  Each time we are
+   called return another potential completion to the caller.
+
+   TEXT is what we expect the symbol to start with.
 
+   MATCHES is the number of matches that have currently been collected from
+   calling this completion function.  When zero, then we need to initialize,
+   otherwise the initialization has already taken place and we can just
+   return the next potential completion string.
+
+   Returns NULL if there are no more completions, else a pointer to a string
+   which is a possible completion.
+
+   RL_LINE_BUFFER is available to be looked at; it contains the entire text
+   of the line.  RL_POINT is the offset in that line of the cursor.  You
+   should pretend that the line ends at RL_POINT. */
+   
 static char *
-symbol_completion_function (text, state)
+symbol_completion_function (text, matches)
      char *text;
-     int state;
+     int matches;
 {
-  static char **list = (char **)NULL;
-  static int index;
-  char *output;
-  extern char *rl_line_buffer;
-  extern int rl_point;
+  static char **list = (char **)NULL;          /* Cache of completions */
+  static int index;                            /* Next cached completion */
+  char *output = NULL;
   char *tmp_command, *p;
   struct cmd_list_element *c, *result_list;
+  extern char *rl_line_buffer;
+  extern int rl_point;
 
-  if (!state)
+  if (matches == 0)
     {
-      /* Free the storage used by LIST, but not by the strings inside.  This is
-        because rl_complete_internal () frees the strings. */
+      /* The caller is beginning to accumulate a new set of completions, so
+        we need to find all of them now, and cache them for returning one at
+        a time on future calls. */
+
       if (list)
-       free (list);
+       {
+         /* Free the storage used by LIST, but not by the strings inside.
+            This is because rl_complete_internal () frees the strings. */
+         free ((PTR)list);
+       }
       list = 0;
       index = 0;
 
-      /* Decide whether to complete on a list of gdb commands or on
-        symbols.  */
+      /* Choose the default set of word break characters to break completions.
+        If we later find out that we are doing completions on command strings
+        (as opposed to strings supplied by the individual command completer
+        functions, which can be any string) then we will switch to the
+        special word break set for command strings, which leaves out the
+        '-' character used in some commands. */
+
+      /* FIXME: Using rl_completer_word_break_characters is the wrong
+        approach, because "show foo-bar<TAB>" won't know to use the
+        new set until too late.  Better approach is to do the word breaking
+        ourself.  */
+
+      rl_completer_word_break_characters =
+         gdb_completer_word_break_characters;
+
+      /* Decide whether to complete on a list of gdb commands or on symbols. */
       tmp_command = (char *) alloca (rl_point + 1);
       p = tmp_command;
       
@@ -1074,47 +1259,55 @@ symbol_completion_function (text, state)
 
       if (rl_point == 0)
        {
-         /* An empty line we want to consider ambiguous; that is,
-            it could be any command.  */
+         /* An empty line we want to consider ambiguous; that is, it
+            could be any command.  */
          c = (struct cmd_list_element *) -1;
          result_list = 0;
        }
       else
-       c = lookup_cmd_1 (&p, cmdlist, &result_list, 1);
+       {
+         c = lookup_cmd_1 (&p, cmdlist, &result_list, 1);
+       }
 
       /* Move p up to the next interesting thing.  */
       while (*p == ' ' || *p == '\t')
-       p++;
+       {
+         p++;
+       }
 
       if (!c)
-       /* He's typed something unrecognizable.  Sigh.  */
-       list = (char **) 0;
+       {
+         /* He's typed something unrecognizable.  Sigh.  */
+         list = NULL;
+       }
       else if (c == (struct cmd_list_element *) -1)
        {
          /* If we didn't recognize everything up to the thing that
             needs completing, and we don't know what command it is
-            yet, we are in trouble.  Part of the trouble might be
-            that the list of delimiters used by readline includes
-            '-', which we use in commands.  Check for this.  */
-         if (p + strlen(text) != tmp_command + rl_point) {
-           if (tmp_command[rl_point - strlen(text) - 1] == '-')
-             text = p;
-           else {
+            yet, we are in trouble. */
+
+         if (p + strlen(text) != tmp_command + rl_point)
+           {
              /* This really should not produce an error.  Better would
                 be to pretend to hit RETURN here; this would produce a
                 response like "Ambiguous command: foo, foobar, etc",
-                and leave the line available for re-entry with ^P.  Instead,
-                this error blows away the user's typed input without
-                any way to get it back.  */
+                and leave the line available for re-entry with ^P.
+                Instead, this error blows away the user's typed input
+                without any way to get it back.  */
              error ("  Unrecognized command.");
            }
-         }
          
          /* He's typed something ambiguous.  This is easier.  */
          if (result_list)
-           list = complete_on_cmdlist (*result_list->prefixlist, text);
+           {
+             list = complete_on_cmdlist (*result_list->prefixlist, text);
+           }
          else
-           list = complete_on_cmdlist (cmdlist, text);
+           {
+             list = complete_on_cmdlist (cmdlist, text);
+           }
+         rl_completer_word_break_characters =
+             gdb_completer_command_word_break_characters;
        }
       else
        {
@@ -1128,48 +1321,95 @@ symbol_completion_function (text, state)
             command.   */
 
          if (!*p && *text)
-           /* Always (might be longer versions of thie command).  */
-           list = complete_on_cmdlist (result_list, text);
+           {
+             /* Always (might be longer versions of thie command).  */
+             list = complete_on_cmdlist (result_list, text);
+             rl_completer_word_break_characters =
+                 gdb_completer_command_word_break_characters;
+           }
          else if (!*p && !*text)
            {
              if (c->prefixlist)
-               list = complete_on_cmdlist (*c->prefixlist, "");
+               {
+                 list = complete_on_cmdlist (*c->prefixlist, "");
+                 rl_completer_word_break_characters =
+                     gdb_completer_command_word_break_characters;
+               }
              else
-               list = (*c->completer) ("");
+               {
+                 list = (*c->completer) ("");
+               }
            }
          else
            {
              if (c->prefixlist && !c->allow_unknown)
                {
-#if 0
-                 /* Something like "info adsfkdj".  But error() is not
-                    the proper response; just return no completions
-                    instead.  */
-                 *p = '\0';
-                 error ("\"%s\" command requires a subcommand.",
-                        tmp_command);
-#else
+                 /* Something like "info adsfkdj".  But error() is not the
+                    proper response; just return no completions instead. */
                  list = NULL;
-#endif
                }
              else
-               list = (*c->completer) (text);
+               {
+                 list = (*c->completer) (text);
+               }
            }
        }
     }
 
-  /* If the debugged program wasn't compiled with symbols, or if we're
-     clearly completing on a command and no command matches, return
-     NULL.  */
-  if (!list)
-    return ((char *)NULL);
+  /* If we found a list of potential completions during initialization then
+     dole them out one at a time.  The vector of completions is NULL
+     terminated, so after returning the last one, return NULL (and continue
+     to do so) each time we are called after that, until a new list is
+     available. */
 
-  output = list[index];
-  if (output)
-    index++;
+  if (list)
+    {
+      output = list[index];
+      if (output)
+       {
+         index++;
+       }
+    }
 
   return (output);
 }
+
+/* Skip over a possibly quoted word (as defined by the quote characters
+   and word break characters the completer uses).  Returns pointer to the
+   location after the "word". */
+
+char *
+skip_quoted (str)
+     char *str;
+{
+  char quote_char = '\0';
+  char *scan;
+
+  for (scan = str; *scan != '\0'; scan++)
+    {
+      if (quote_char != '\0')
+       {
+         /* Ignore everything until the matching close quote char */
+         if (*scan == quote_char)
+           {
+             /* Found matching close quote. */
+             scan++;
+             break;
+           }
+       }
+      else if (strchr (gdb_completer_quote_characters, *scan))
+       {
+         /* Found start of a quoted string. */
+         quote_char = *scan;
+       }
+      else if (strchr (gdb_completer_word_break_characters, *scan))
+       {
+         break;
+       }
+    }
+  return (scan);
+}
+
 \f
 #ifdef STOP_SIGNAL
 static void
@@ -1216,6 +1456,10 @@ init_signals ()
   if (signal (SIGHUP, do_nothing) != SIG_IGN)
     signal (SIGHUP, disconnect);
   signal (SIGFPE, float_handler);
+
+#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER)
+  signal (SIGWINCH, SIGWINCH_HANDLER);
+#endif
 }
 \f
 /* Read one line from the command input stream `instream'
@@ -1307,7 +1551,7 @@ command_line_input (prrompt, repeat)
   }
 
 #ifdef STOP_SIGNAL
-  signal (SIGTSTP, SIG_DFL);
+  signal (STOP_SIGNAL, SIG_DFL);
 #endif
   immediate_quit--;
 
@@ -1488,7 +1732,7 @@ free_command_lines (lptr)
     {
       next = l->next;
       free (l->line);
-      free (l);
+      free ((PTR)l);
       l = next;
     }
 }
@@ -1591,28 +1835,19 @@ validate_comname (comname)
   p = comname;
   while (*p)
     {
-      if (!(*p >= 'A' && *p <= 'Z')
-         && !(*p >= 'a' && *p <= 'z')
-         && !(*p >= '0' && *p <= '9')
-         && *p != '-')
+      if (!isalnum(*p) && *p != '-')
        error ("Junk in argument list: \"%s\"", p);
       p++;
     }
 }
 
-#ifdef IBM6000
-
-lowercase (char *str)
+/* This is just a placeholder in the command data structures.  */
+static void
+user_defined_command (ignore, from_tty)
+     char *ignore;
+     int from_tty;
 {
-  while (*str) {
-    /* isupper(), tolower() are function calls in AIX. */
-    if ( *str >= 'A' && *str <= 'Z')
-      *str = *str + 'a' - 'A';
-    ++str;
-  }
 }
-#endif
 
 static void
 define_command (comname, from_tty)
@@ -1620,22 +1855,16 @@ define_command (comname, from_tty)
      int from_tty;
 {
   register struct command_line *cmds;
-  register struct cmd_list_element *c, *newc;
+  register struct cmd_list_element *c, *newc, *hookc = 0;
   char *tem = comname;
+#define        HOOK_STRING     "hook-"
+#define        HOOK_LEN 5
 
   validate_comname (comname);
 
-#ifdef IBM6000
-
-  /* If the rest of the commands will be case insensetive, this one 
-     should behave in the same manner. */
-
-  lowercase (comname);
-#endif
-
   /* Look it up, and verify that we got an exact match.  */
   c = lookup_cmd (&tem, cmdlist, "", -1, 1);
-  if (c && 0 != strcmp (comname, c->name))
+  if (c && !STREQ (comname, c->name))
     c = 0;
     
   if (c)
@@ -1644,27 +1873,61 @@ define_command (comname, from_tty)
        tem = "Redefine command \"%s\"? ";
       else
        tem = "Really redefine built-in command \"%s\"? ";
-      if (!query (tem, comname))
-       error ("Command \"%s\" not redefined.", comname);
+      if (!query (tem, c->name))
+       error ("Command \"%s\" not redefined.", c->name);
     }
 
+  /* If this new command is a hook, then mark the command which it
+     is hooking.  Note that we allow hooking `help' commands, so that
+     we can hook the `stop' pseudo-command.  */
+
+  if (!strncmp (comname, HOOK_STRING, HOOK_LEN))
+    {
+      /* Look up cmd it hooks, and verify that we got an exact match.  */
+      tem = comname+HOOK_LEN;
+      hookc = lookup_cmd (&tem, cmdlist, "", -1, 0);
+      if (hookc && !STREQ (comname+HOOK_LEN, hookc->name))
+       hookc = 0;
+      if (!hookc)
+       {
+         warning ("Your new `%s' command does not hook any existing command.",
+                  comname);
+         if (!query ("Proceed? ", (char *)0))
+           error ("Not confirmed.");
+       }
+    }
+
+  comname = savestring (comname, strlen (comname));
+
+  /* If the rest of the commands will be case insensitive, this one 
+     should behave in the same manner. */
+  for (tem = comname; *tem; tem++)
+    if (isupper(*tem)) *tem = tolower(*tem);
+
   if (from_tty)
     {
       printf ("Type commands for definition of \"%s\".\n\
 End with a line saying just \"end\".\n", comname);
       fflush (stdout);
     }
-  comname = savestring (comname, strlen (comname));
 
   cmds = read_command_lines ();
 
   if (c && c->class == class_user)
     free_command_lines (&c->user_commands);
 
-  newc = add_cmd (comname, class_user, not_just_help_class_command,
+  newc = add_cmd (comname, class_user, user_defined_command,
           (c && c->class == class_user)
           ? c->doc : savestring ("User-defined.", 13), &cmdlist);
   newc->user_commands = cmds;
+
+  /* If this new command is a hook, then mark both commands as being
+     tied.  */
+  if (hookc)
+    {
+      hookc->hook = newc;      /* Target gets hooked.  */
+      newc->hookee = hookc;    /* We are marked as hooking target cmd.  */
+    }
 }
 
 static void
@@ -1723,11 +1986,18 @@ There is absolutely no warranty for GDB; type \"show warranty\" for details.\n\
 }
 
 static void
-print_gdb_version ()
+print_gdb_version (stream)
+  FILE *stream;
 {
-  printf_filtered ("\
-GDB %s, Copyright 1992 Free Software Foundation, Inc.",
-         version);
+  fprintf_filtered (stream, "\
+GDB %s (%s", version, host_canonical);
+
+  if (strcmp(host_canonical, target_canonical))
+    fprintf_filtered (stream, " --target %s", target_canonical);
+
+  fprintf_filtered (stream, "), ");
+  wrap_here("");
+  fprintf_filtered (stream, "Copyright 1993 Free Software Foundation, Inc.");
 }
 
 /* ARGSUSED */
@@ -1738,7 +2008,7 @@ show_version (args, from_tty)
 {
   immediate_quit++;
   print_gnu_advertisement ();
-  print_gdb_version ();
+  print_gdb_version (stdout);
   printf_filtered ("\n");
   immediate_quit--;
 }
@@ -1759,12 +2029,20 @@ quit_command (args, from_tty)
 {
   if (inferior_pid != 0 && target_has_execution)
     {
-      if (query ("The program is running.  Quit anyway? "))
+      if (attach_flag)
        {
-         target_kill ();
+         if (query ("The program is running.  Quit anyway (and detach it)? "))
+           target_detach (args, from_tty);
+         else
+           error ("Not confirmed.");
        }
       else
-       error ("Not confirmed.");
+       {
+         if (query ("The program is running.  Quit anyway (and kill it)? "))
+           target_kill ();
+         else
+           error ("Not confirmed.");
+       }
     }
   /* Save the history information if it is appropriate to do so.  */
   if (write_history_p && history_filename)
@@ -1790,7 +2068,7 @@ pwd_command (args, from_tty)
   if (args) error ("The \"pwd\" command does not take an argument: %s", args);
   getcwd (dirbuf, sizeof (dirbuf));
 
-  if (strcmp (dirbuf, current_directory))
+  if (!STREQ (dirbuf, current_directory))
     printf ("Working directory %s\n (canonically %s).\n",
            current_directory, dirbuf);
   else
@@ -1873,14 +2151,15 @@ source_command (args, from_tty)
   struct cleanup *cleanups;
   char *file = args;
 
-  if (file == 0)
-    /* Let source without arguments read .gdbinit.  */
-    file = gdbinit;
+  if (file == NULL)
+    {
+      error ("source command requires pathname of file to source.");
+    }
 
   file = tilde_expand (file);
   make_cleanup (free, file);
 
-  stream = fopen (file, "r");
+  stream = fopen (file, FOPEN_RT);
   if (stream == 0)
     perror_with_name (file);
 
@@ -1901,7 +2180,7 @@ echo_command (text, from_tty)
   register int c;
 
   if (text)
-    while (c = *p++)
+    while ((c = *p++) != '\0')
       {
        if (c == '\\')
          {
@@ -1923,18 +2202,6 @@ echo_command (text, from_tty)
   fflush (stdout);
 }
 
-/* ARGSUSED */
-static void
-dump_me_command (args, from_tty)
-     char *args;
-     int from_tty;
-{
-  if (query ("Should GDB dump core? "))
-    {
-      signal (SIGQUIT, SIG_DFL);
-      kill (getpid (), SIGQUIT);
-    }
-}
 \f
 /* Functions to manipulate command line editing control variables.  */
 
@@ -2026,10 +2293,15 @@ set_history_size_command (args, from_tty, c)
      int from_tty;
      struct cmd_list_element *c;
 {
-  if (history_size == UINT_MAX)
+  if (history_size == INT_MAX)
     unstifle_history ();
-  else
+  else if (history_size >= 0)
     stifle_history (history_size);
+  else
+    {
+      history_size = INT_MAX;
+      error ("History size must be non-negative");
+    }
 }
 
 /* ARGSUSED */
@@ -2084,6 +2356,7 @@ int signo;
 {
   /* This message is based on ANSI C, section 4.7.  Note that integer
      divide by zero causes this, so "float" is a misnomer.  */
+  signal (SIGFPE, float_handler);
   error ("Erroneous arithmetic operation.");
 }
 
@@ -2096,19 +2369,29 @@ batch_mode ()
 
 \f
 static void
-initialize_cmd_lists ()
+init_cmd_lists ()
 {
-  cmdlist = (struct cmd_list_element *) 0;
-  infolist = (struct cmd_list_element *) 0;
-  enablelist = (struct cmd_list_element *) 0;
-  disablelist = (struct cmd_list_element *) 0;
-  deletelist = (struct cmd_list_element *) 0;
-  enablebreaklist = (struct cmd_list_element *) 0;
-  setlist = (struct cmd_list_element *) 0;
+  cmdlist = NULL;
+  infolist = NULL;
+  enablelist = NULL;
+  disablelist = NULL;
+  deletelist = NULL;
+  enablebreaklist = NULL;
+  setlist = NULL;
+  unsetlist = NULL;
   showlist = NULL;
-  sethistlist = (struct cmd_list_element *) 0;
+  sethistlist = NULL;
   showhistlist = NULL;
-  unsethistlist = (struct cmd_list_element *) 0;
+  unsethistlist = NULL;
+#if MAINTENANCE_CMDS
+  maintenancelist = NULL;
+  maintenanceinfolist = NULL;
+  maintenanceprintlist = NULL;
+#endif
+  setprintlist = NULL;
+  showprintlist = NULL;
+  setchecklist = NULL;
+  showchecklist = NULL;
 }
 
 /* Init the history buffer.  Note that we are called after the init file(s)
@@ -2118,7 +2401,7 @@ initialize_cmd_lists ()
  */
 
 static void
-initialize_history()
+init_history()
 {
   char *tmpenv;
 
@@ -2143,7 +2426,7 @@ initialize_history()
 }
 
 static void
-initialize_main ()
+init_main ()
 {
   struct cmd_list_element *c;
   
@@ -2161,11 +2444,18 @@ initialize_main ()
   /* Setup important stuff for command line editing.  */
   rl_completion_entry_function = (int (*)()) symbol_completion_function;
   rl_completer_word_break_characters = gdb_completer_word_break_characters;
+  rl_completer_quote_characters = gdb_completer_quote_characters;
   rl_readline_name = "gdb";
 
   /* Define the classes of commands.
      They will appear in the help list in the reverse of this order.  */
 
+  add_cmd ("internals", class_maintenance, NO_FUNCTION,
+          "Maintenance commands.\n\
+Some gdb commands are provided just for use by gdb maintainers.\n\
+These commands are subject to frequent change, and may not be as\n\
+well documented as user commands.",
+          &cmdlist);
   add_cmd ("obscure", class_obscure, NO_FUNCTION, "Obscure features.", &cmdlist);
   add_cmd ("aliases", class_alias, NO_FUNCTION, "Aliases of other commands.", &cmdlist);
   add_cmd ("user-defined", class_user, NO_FUNCTION, "User-defined commands.\n\
@@ -2188,10 +2478,11 @@ The commands below can be used to select other frames by number or address.",
 
   add_com ("pwd", class_files, pwd_command,
           "Print working directory.  This is used for your program as well.");
-  add_com ("cd", class_files, cd_command,
+  c = add_cmd ("cd", class_files, cd_command,
           "Set working directory to DIR for debugger and program being debugged.\n\
 The change does not take effect for the program being debugged\n\
-until the next time it is started.");
+until the next time it is started.", &cmdlist);
+  c->completer = filename_completer;
 
   add_show_from_set
     (add_set_cmd ("prompt", class_support, var_string, (char *)&prompt,
@@ -2219,17 +2510,18 @@ Use the \"document\" command to give documentation for the new command.\n\
 Commands defined in this way do not take arguments.");
 
 #ifdef __STDC__
-  add_com ("source", class_support, source_command,
+  c = add_cmd ("source", class_support, source_command,
           "Read commands from a file named FILE.\n\
 Note that the file \"" GDBINIT_FILENAME "\" is read automatically in this way\n\
-when gdb is started.");
+when gdb is started.", &cmdlist);
 #else
   /* Punt file name, we can't help it easily.  */
-  add_com ("source", class_support, source_command,
+  c = add_cmd ("source", class_support, source_command,
           "Read commands from a file named FILE.\n\
 Note that the file \".gdbinit\" is read automatically in this way\n\
-when gdb is started.");
+when gdb is started.", &cmdlist);
 #endif
+  c->completer = filename_completer;
 
   add_com ("quit", class_support, quit_command, "Exit gdb.");
   add_com ("help", class_support, help_command, "Print list of commands.");
@@ -2244,9 +2536,6 @@ when gdb is started.");
   c->function.sfunc = set_verbose;
   set_verbose (NULL, 0, c);
   
-  add_com ("dump-me", class_obscure, dump_me_command,
-          "Get fatal error; make debugger dump its core.");
-
   add_show_from_set
     (add_set_cmd ("editing", class_support, var_boolean, (char *)&command_editing_p,
           "Set editing of command lines as they are typed.\n\
@@ -2275,7 +2564,7 @@ Use \"on\" to enable to enable the saving, and \"off\" to disable it.\n\
 Without an argument, saving is enabled.", &sethistlist),
      &showhistlist);
 
-  c = add_set_cmd ("size", no_class, var_uinteger, (char *)&history_size,
+  c = add_set_cmd ("size", no_class, var_integer, (char *)&history_size,
                   "Set the size of the command history, \n\
 ie. the number of previous commands to keep a record of.", &sethistlist);
   add_show_from_set (c, &showhistlist);
This page took 0.039728 seconds and 4 git commands to generate.