Fix crash when exiting TUI with gdb -tui
[deliverable/binutils-gdb.git] / gdb / cli / cli-decode.c
index c37dfaffb5c1adcb2f3b4d8b526b2572dfd2df2f..a4ef93c62b056559c3f018ffca2d68cd126b06cc 100644 (file)
@@ -43,6 +43,11 @@ static struct cmd_list_element *find_cmd (const char *command,
                                          int ignore_help_classes,
                                          int *nfound);
 
+static void help_cmd_list (struct cmd_list_element *list,
+                          enum command_class theclass,
+                          bool recurse,
+                          struct ui_file *stream);
+
 static void help_all (struct ui_file *stream);
 
 /* Look up a command whose 'prefixlist' is KEY.  Return the command if found,
@@ -76,8 +81,8 @@ lookup_cmd_for_prefixlist (struct cmd_list_element **key,
 }
 
 static void
-print_help_for_command (struct cmd_list_element *c, const char *prefix,
-                       int recurse, struct ui_file *stream);
+print_help_for_command (struct cmd_list_element *c,
+                       bool recurse, struct ui_file *stream);
 
 \f
 /* Set the callback function for the specified command.  For each both
@@ -1001,7 +1006,10 @@ add_com (const char *name, enum command_class theclass,
   return add_cmd (name, theclass, fun, doc, &cmdlist);
 }
 
-/* Add an alias or abbreviation command to the list of commands.  */
+/* Add an alias or abbreviation command to the list of commands.
+   For aliases predefined by GDB (such as bt), THECLASS must be
+   different of class_alias, as class_alias is used to identify
+   user defined aliases.  */
 
 struct cmd_list_element *
 add_com_alias (const char *name, const char *oldname, enum command_class theclass,
@@ -1021,6 +1029,43 @@ add_com_suppress_notification (const char *name, enum command_class theclass,
                                        &cmdlist, suppress_notification);
 }
 
+/* Print the prefix of C followed by name of C in title style.  */
+
+static void
+fput_command_name_styled (struct cmd_list_element *c, struct ui_file *stream)
+{
+  const char *prefixname
+    = c->prefix == nullptr ? "" : c->prefix->prefixname;
+
+  fprintf_styled (stream, title_style.style (), "%s%s", prefixname, c->name);
+}
+
+/* If C has one or more aliases, style print the name of C and
+   the name of its aliases, separated by commas.
+   If ALWAYS_FPUT_C_NAME, print the name of C even if it has no aliases.
+   If one or more names are printed, POSTFIX is printed after the last name.
+*/
+
+static void
+fput_command_names_styled (struct cmd_list_element *c,
+                          bool always_fput_c_name, const char *postfix,
+                          struct ui_file *stream)
+{
+  if (always_fput_c_name ||  c->aliases != nullptr)
+    fput_command_name_styled (c, stream);
+  if (c->aliases != nullptr)
+    {
+      for (cmd_list_element *iter = c->aliases; iter; iter = iter->alias_chain)
+       {
+         fputs_filtered (", ", stream);
+         wrap_here ("   ");
+         fput_command_name_styled (iter, stream);
+       }
+    }
+  if (always_fput_c_name ||  c->aliases != nullptr)
+    fputs_filtered (postfix, stream);
+}
+
 /* If VERBOSE, print the full help for command C and highlight the
    documentation parts matching HIGHLIGHT,
    otherwise print only one-line help for command C.  */
@@ -1036,9 +1081,7 @@ print_doc_of_command (struct cmd_list_element *c, const char *prefix,
   if (verbose)
     fputs_filtered ("\n", stream);
 
-  fprintf_styled (stream, title_style.style (),
-                 "%s%s", prefix, c->name);
-  fputs_filtered (" -- ", stream);
+  fput_command_names_styled (c, true, " -- ", stream);
   if (verbose)
     fputs_highlighted (c->doc, highlight, stream);
   else
@@ -1064,6 +1107,14 @@ apropos_cmd (struct ui_file *stream,
   /* Walk through the commands.  */
   for (c=commandlist;c;c=c->next)
     {
+      if (c->cmd_pointer != nullptr)
+       {
+         /* Command aliases/abbreviations are skipped to ensure we print the
+            doc of a command only once, when encountering the aliased
+            command.  */
+         continue;
+       }
+
       returnvalue = -1; /* Needed to avoid double printing.  */
       if (c->name != NULL)
        {
@@ -1073,6 +1124,17 @@ apropos_cmd (struct ui_file *stream,
          returnvalue = regex.search (c->name, name_len, 0, name_len, NULL);
          if (returnvalue >= 0)
            print_doc_of_command (c, prefix, verbose, regex, stream);
+
+         /* Try to match against the name of the aliases.  */
+         for (cmd_list_element *iter = c->aliases;
+              returnvalue < 0 && iter;
+              iter = iter->alias_chain)
+           {
+             name_len = strlen (iter->name);
+             returnvalue = regex.search (iter->name, name_len, 0, name_len, NULL);
+             if (returnvalue >= 0)
+               print_doc_of_command (c, prefix, verbose, regex, stream);
+           }
        }
       if (c->doc != NULL && returnvalue < 0)
        {
@@ -1082,10 +1144,8 @@ apropos_cmd (struct ui_file *stream,
          if (regex.search (c->doc, doc_len, 0, doc_len, NULL) >= 0)
            print_doc_of_command (c, prefix, verbose, regex, stream);
        }
-      /* Check if this command has subcommands and is not an
-        abbreviation.  We skip listing subcommands of abbreviations
-        in order to avoid duplicates in the output.  */
-      if (c->prefixlist != NULL && !c->abbrev_flag)
+      /* Check if this command has subcommands.  */
+      if (c->prefixlist != NULL)
        {
          /* Recursively call ourselves on the subcommand list,
             passing the right prefix in.  */
@@ -1108,7 +1168,7 @@ apropos_cmd (struct ui_file *stream,
 void
 help_cmd (const char *command, struct ui_file *stream)
 {
-  struct cmd_list_element *c;
+  struct cmd_list_element *c, *alias, *prefix_cmd, *c_cmd;
 
   if (!command)
     {
@@ -1122,11 +1182,14 @@ help_cmd (const char *command, struct ui_file *stream)
       return;
     }
 
+  const char *orig_command = command;
   c = lookup_cmd (&command, cmdlist, "", 0, 0);
 
   if (c == 0)
     return;
 
+  lookup_cmd_composition (orig_command, &alias, &prefix_cmd, &c_cmd);
+
   /* There are three cases here.
      If c->prefixlist is nonzero, we have a prefix command.
      Print its documentation, then list its subcommands.
@@ -1139,6 +1202,9 @@ help_cmd (const char *command, struct ui_file *stream)
      number of this class so that the commands in the class will be
      listed.  */
 
+  /* If the user asked 'help somecommand' and there is no alias,
+     the false indicates to not output the (single) command name.  */
+  fput_command_names_styled (c, false, "\n", stream);
   fputs_filtered (c->doc, stream);
   fputs_filtered ("\n", stream);
 
@@ -1208,7 +1274,7 @@ help_list (struct cmd_list_element *list, const char *cmdtype,
   else
     fprintf_filtered (stream, "List of %scommands:\n\n", cmdtype2);
 
-  help_cmd_list (list, theclass, cmdtype, (int) theclass >= 0, stream);
+  help_cmd_list (list, theclass, theclass >= 0, stream);
 
   if (theclass == all_classes)
     {
@@ -1255,7 +1321,7 @@ help_all (struct ui_file *stream)
       if (c->func == NULL)
        {
          fprintf_filtered (stream, "\nCommand class: %s\n\n", c->name);
-         help_cmd_list (cmdlist, c->theclass, "", 1, stream);
+         help_cmd_list (cmdlist, c->theclass, true, stream);
        }
     }
 
@@ -1275,7 +1341,7 @@ help_all (struct ui_file *stream)
              fprintf_filtered (stream, "\nUnclassified commands\n\n");
              seen_unclassified = 1;
            }
-         print_help_for_command (c, "", 1, stream);
+         print_help_for_command (c, 1, stream);
        }
     }
 
@@ -1327,12 +1393,10 @@ print_doc_line (struct ui_file *stream, const char *str,
    If RECURSE is non-zero, also print one-line descriptions
    of all prefixed subcommands.  */
 static void
-print_help_for_command (struct cmd_list_element *c, const char *prefix,
-                       int recurse, struct ui_file *stream)
+print_help_for_command (struct cmd_list_element *c,
+                       bool recurse, struct ui_file *stream)
 {
-  fprintf_styled (stream, title_style.style (),
-                 "%s%s", prefix, c->name);
-  fputs_filtered (" -- ", stream);
+  fput_command_names_styled (c, true, " -- ", stream);
   print_doc_line (stream, c->doc, false);
   fputs_filtered ("\n", stream);
 
@@ -1342,48 +1406,80 @@ print_help_for_command (struct cmd_list_element *c, const char *prefix,
     /* Subcommands of a prefix command typically have 'all_commands'
        as class.  If we pass CLASS to recursive invocation,
        most often we won't see anything.  */
-    help_cmd_list (*c->prefixlist, all_commands, c->prefixname, 1, stream);
+    help_cmd_list (*c->prefixlist, all_commands, true, stream);
 }
 
 /*
  * Implement a help command on command list LIST.
  * RECURSE should be non-zero if this should be done recursively on
  * all sublists of LIST.
- * PREFIX is the prefix to print before each command name.
  * STREAM is the stream upon which the output should be written.
  * THECLASS should be:
  *      A non-negative class number to list only commands in that
- * class.
  *      ALL_COMMANDS to list all commands in list.
  *      ALL_CLASSES  to list all classes in list.
  *
+ *   Note that aliases are only shown when THECLASS is class_alias.
+ *   In the other cases, the aliases will be shown together with their
+ *   aliased command.
+ *
  *   Note that RECURSE will be active on *all* sublists, not just the
  * ones selected by the criteria above (ie. the selection mechanism
  * is at the low level, not the high-level).
  */
-void
+
+static void
 help_cmd_list (struct cmd_list_element *list, enum command_class theclass,
-              const char *prefix, int recurse, struct ui_file *stream)
+              bool recurse, struct ui_file *stream)
 {
   struct cmd_list_element *c;
 
   for (c = list; c; c = c->next)
     {
-      if (c->abbrev_flag == 0
-         && !c->cmd_deprecated
-         && (theclass == all_commands
-             || (theclass == all_classes && c->func == NULL)
-             || (theclass == c->theclass && c->func != NULL)))
+      if (c->abbrev_flag == 1 || c->cmd_deprecated)
        {
-         print_help_for_command (c, prefix, recurse, stream);
+         /* Do not show abbreviations or deprecated commands.  */
+         continue;
        }
-      else if (c->abbrev_flag == 0
-              && recurse
-              && !c->cmd_deprecated
-              && theclass == class_user && c->prefixlist != NULL)
-       /* User-defined commands may be subcommands.  */
-       help_cmd_list (*c->prefixlist, theclass, c->prefixname,
-                      recurse, stream);
+
+      if (c->cmd_pointer != nullptr && theclass != class_alias)
+       {
+         /* Do not show an alias, unless specifically showing the
+            list of aliases:  for all other classes, an alias is
+            shown (if needed) together with its aliased command.  */
+         continue;
+       }
+
+      if (theclass == all_commands
+         || (theclass == all_classes && c->func == NULL)
+         || (theclass == c->theclass && c->func != NULL))
+       {
+         /* show C when
+             - showing all commands
+            - showing all classes and C is a help class
+            - showing commands of THECLASS and C is not the help class  */
+
+         /* If we show the class_alias and C is an alias, do not recurse,
+            as this would show the (possibly very long) not very useful
+            list of sub-commands of the aliased command.  */
+         print_help_for_command
+           (c,
+            recurse && (theclass != class_alias || c->cmd_pointer == nullptr),
+            stream);
+         continue;
+       }
+
+      if (recurse
+         && (theclass == class_user || theclass == class_alias)
+         && c->prefixlist != NULL)
+       {
+         /* User-defined commands or aliases may be subcommands.  */
+         help_cmd_list (*c->prefixlist, theclass, recurse, stream);
+         continue;
+       }
+
+      /* Do not show C or recurse on C, e.g. because C does not belong to
+        THECLASS or because C is a help class.  */
     }
 }
 \f
This page took 0.028091 seconds and 4 git commands to generate.