Teach gdb::option about string options
[deliverable/binutils-gdb.git] / gdb / cli / cli-option.c
index 8f2844610b56d55ae95be5d08beb2cd0910a59c2..07d552b7f5bbdaff7bc6f11a4e5c0ba999879ef6 100644 (file)
@@ -43,6 +43,9 @@ union option_value
 
   /* For var_enum options.  */
   const char *enumeration;
+
+  /* For var_string options.  This is malloc-allocated.  */
+  char *string;
 };
 
 /* Holds an options definition and its value.  */
@@ -56,6 +59,54 @@ struct option_def_and_value
 
   /* The option's value, if any.  */
   gdb::optional<option_value> value;
+
+  /* Constructor.  */
+  option_def_and_value (const option_def &option_, void *ctx_,
+                       gdb::optional<option_value> &&value_ = {})
+    : option (option_),
+      ctx (ctx_),
+      value (std::move (value_))
+  {
+    clear_value (option_, value_);
+  }
+
+  /* Move constructor.  Need this because for some types the values
+     are allocated on the heap.  */
+  option_def_and_value (option_def_and_value &&rval)
+    : option (rval.option),
+      ctx (rval.ctx),
+      value (std::move (rval.value))
+  {
+    clear_value (rval.option, rval.value);
+  }
+
+  DISABLE_COPY_AND_ASSIGN (option_def_and_value);
+
+  ~option_def_and_value ()
+  {
+    if (value.has_value ())
+      {
+       if (option.type == var_string)
+         xfree (value->string);
+      }
+  }
+
+private:
+
+  /* Clear the option_value, without releasing it.  This is used after
+     the value has been moved to some other option_def_and_value
+     instance.  This is needed because for some types the value is
+     allocated on the heap, so we must clear the pointer in the
+     source, to avoid a double free.  */
+  static void clear_value (const option_def &option,
+                          gdb::optional<option_value> &value)
+  {
+    if (value.has_value ())
+      {
+       if (option.type == var_string)
+         value->string = nullptr;
+      }
+  }
 };
 
 static void save_option_value_in_ctx (gdb::optional<option_def_and_value> &ov);
@@ -373,6 +424,25 @@ parse_option (gdb::array_view<const option_def_group> options_group,
        val.enumeration = parse_cli_var_enum (args, match->enums);
        return option_def_and_value {*match, match_ctx, val};
       }
+    case var_string:
+      {
+       if (check_for_argument (args, "--"))
+         {
+           /* Treat e.g., "maint test-options -string --" as if there
+              was no argument after "-string".  */
+           error (_("-%s requires an argument"), match->name);
+         }
+
+       const char *arg_start = *args;
+       *args = skip_to_space (*args);
+
+       if (*args == arg_start)
+         error (_("-%s requires an argument"), match->name);
+
+       option_value val;
+       val.string = savestring (arg_start, *args - arg_start);
+       return option_def_and_value {*match, match_ctx, val};
+      }
 
     default:
       /* Not yet.  */
@@ -532,6 +602,11 @@ save_option_value_in_ctx (gdb::optional<option_def_and_value> &ov)
       *ov->option.var_address.enumeration (ov->option, ov->ctx)
        = ov->value->enumeration;
       break;
+    case var_string:
+      *ov->option.var_address.string (ov->option, ov->ctx)
+       = ov->value->string;
+      ov->value->string = nullptr;
+      break;
     default:
       gdb_assert_not_reached ("unhandled option type");
     }
@@ -604,6 +679,8 @@ get_val_type_str (const option_def &opt, std::string &buffer)
          }
        return buffer.c_str ();
       }
+    case var_string:
+      return "STRING";
     default:
       return nullptr;
     }
@@ -731,6 +808,15 @@ add_setshow_cmds_for_options (command_class cmd_class,
                                nullptr, option.show_cmd_cb,
                                set_list, show_list);
        }
+      else if (option.type == var_string)
+       {
+         add_setshow_string_cmd (option.name, cmd_class,
+                                 option.var_address.string (option, data),
+                                 option.set_doc, option.show_doc,
+                                 option.help_doc,
+                                 nullptr, option.show_cmd_cb,
+                                 set_list, show_list);
+       }
       else
        gdb_assert_not_reached (_("option type not handled"));
     }
This page took 0.024803 seconds and 4 git commands to generate.