aboutsummaryrefslogtreecommitdiff
path: root/gdb/cli/cli-option.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/cli/cli-option.c')
-rw-r--r--gdb/cli/cli-option.c86
1 files changed, 86 insertions, 0 deletions
diff --git a/gdb/cli/cli-option.c b/gdb/cli/cli-option.c
index 8f28446..07d552b 100644
--- a/gdb/cli/cli-option.c
+++ b/gdb/cli/cli-option.c
@@ -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"));
}