Commit f53218ed authored by Thomas Haller's avatar Thomas Haller

cli: add property type for enum and showcase for ipv6.addr-gen-mode

parent 6ca30a61
......@@ -62,6 +62,37 @@ static char *secret_flags_to_string (guint32 flags, NMMetaAccessorGetType get_ty
/*****************************************************************************/
static GType
_gobject_property_get_gtype (GObject *gobject, const char *property_name)
{
GParamSpec *param_spec;
param_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (gobject), property_name);
if (param_spec)
return param_spec->value_type;
g_return_val_if_reached (G_TYPE_INVALID);
}
static GType
_gtype_property_get_gtype (GType gtype, const char *property_name)
{
/* given @gtype, a type for a GObject, lookup the property @property_name
* and return its value_type. */
if (G_TYPE_IS_CLASSED (gtype)) {
GParamSpec *param_spec;
nm_auto_unref_gtypeclass GTypeClass *gtypeclass = g_type_class_ref (gtype);
if (G_IS_OBJECT_CLASS (gtypeclass)) {
param_spec = g_object_class_find_property (G_OBJECT_CLASS (gtypeclass), property_name);
if (param_spec)
return param_spec->value_type;
}
}
g_return_val_if_reached (G_TYPE_INVALID);
}
/*****************************************************************************/
/*
* Parse IP address from string to NMIPAddress stucture.
* ip_str is the IP address in the form address/prefix
......@@ -575,6 +606,132 @@ _get_fcn_gobject_secret_flags (ARGS_GET_FCN)
return secret_flags_to_string (v, get_type);
}
static char *
_get_fcn_gobject_enum (ARGS_GET_FCN)
{
GType gtype = 0;
GType gtype_prop;
nm_auto_unref_gtypeclass GTypeClass *gtype_class = NULL;
nm_auto_unref_gtypeclass GTypeClass *gtype_prop_class = NULL;
gboolean has_gtype = FALSE;
nm_auto_unset_gvalue GValue gval = G_VALUE_INIT;
gint64 v;
gboolean format_numeric = FALSE;
gboolean format_numeric_hex = FALSE;
gboolean format_numeric_hex_unknown = FALSE;
gboolean format_text = FALSE;
gboolean format_text_l10n = FALSE;
gs_free char *s = NULL;
char s_numeric[64];
if (property_info->property_typ_data) {
if (property_info->property_typ_data->subtype.gobject_enum.get_gtype) {
gtype = property_info->property_typ_data->subtype.gobject_enum.get_gtype ();
has_gtype = TRUE;
}
}
if ( property_info->property_typ_data
&& get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY
&& NM_FLAGS_ANY (property_info->property_typ_data->typ_flags, NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PRETTY_NUMERIC
| NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PRETTY_NUMERIC_HEX
| NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PRETTY_TEXT
| NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PRETTY_TEXT_L10N)) {
format_numeric_hex = NM_FLAGS_HAS (property_info->property_typ_data->typ_flags, NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PRETTY_NUMERIC_HEX);
format_numeric = format_numeric_hex || NM_FLAGS_HAS (property_info->property_typ_data->typ_flags, NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PRETTY_NUMERIC);
format_text_l10n = NM_FLAGS_HAS (property_info->property_typ_data->typ_flags, NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PRETTY_TEXT_L10N);
format_text = format_text_l10n || NM_FLAGS_HAS (property_info->property_typ_data->typ_flags, NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PRETTY_TEXT);
} else if ( property_info->property_typ_data
&& get_type == NM_META_ACCESSOR_GET_TYPE_PARSABLE
&& NM_FLAGS_ANY (property_info->property_typ_data->typ_flags, NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PARSABLE_NUMERIC
| NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PARSABLE_NUMERIC_HEX
| NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PARSABLE_TEXT)) {
format_numeric_hex = NM_FLAGS_HAS (property_info->property_typ_data->typ_flags, NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PARSABLE_NUMERIC_HEX);
format_numeric = format_numeric && NM_FLAGS_HAS (property_info->property_typ_data->typ_flags, NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PARSABLE_NUMERIC);
format_text = NM_FLAGS_HAS (property_info->property_typ_data->typ_flags, NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PARSABLE_TEXT);
} else if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY) {
/* by default, output in format "%u (%s)" (with hex for flags and l10n). */
format_numeric = TRUE;
format_numeric_hex_unknown = TRUE;
format_text = TRUE;
format_text_l10n = TRUE;
} else {
/* by default, output only numeric (with hex for flags). */
format_numeric = TRUE;
format_numeric_hex_unknown = TRUE;
}
nm_assert (format_text || format_numeric);
gtype_prop = _gobject_property_get_gtype (G_OBJECT (setting), property_info->property_name);
g_value_init (&gval, gtype_prop);
g_object_get_property (G_OBJECT (setting), property_info->property_name, &gval);
if ( gtype_prop == G_TYPE_INT
|| ( G_TYPE_IS_CLASSED (gtype_prop)
&& G_IS_ENUM_CLASS ((gtype_prop_class ?: (gtype_prop_class = g_type_class_ref (gtype_prop)))))) {
if (gtype_prop == G_TYPE_INT) {
if (!has_gtype)
g_return_val_if_reached (NULL);
v = g_value_get_int (&gval);
} else
v = g_value_get_enum (&gval);
} else if ( gtype_prop == G_TYPE_UINT
|| ( G_TYPE_IS_CLASSED (gtype_prop)
&& G_IS_FLAGS_CLASS ((gtype_prop_class ?: (gtype_prop_class = g_type_class_ref (gtype_prop)))))) {
if (gtype_prop == G_TYPE_UINT) {
if (!has_gtype)
g_return_val_if_reached (NULL);
v = g_value_get_uint (&gval);
} else
v = g_value_get_flags (&gval);
} else
g_return_val_if_reached (NULL);
if (!has_gtype) {
gtype = gtype_prop;
gtype_class = g_steal_pointer (&gtype_prop_class);
}
nm_assert (({
nm_auto_unref_gtypeclass GTypeClass *t = NULL;
( G_TYPE_IS_CLASSED (gtype)
&& (t = g_type_class_ref (gtype))
&& (G_IS_ENUM_CLASS (t) || G_IS_FLAGS_CLASS (t)));
}));
if (format_numeric && !format_text) {
return format_numeric_hex
|| ( format_numeric_hex_unknown
&& !G_IS_ENUM_CLASS (gtype_class ?: (gtype_class = g_type_class_ref (gtype))))
? g_strdup_printf ("0x%"G_GINT64_FORMAT, v)
: g_strdup_printf ("%"G_GINT64_FORMAT, v);
}
s = nm_utils_enum_to_str (gtype, (int) v);
if (!format_numeric)
return g_steal_pointer (&s);
if ( format_numeric_hex
|| ( format_numeric_hex_unknown
&& !G_IS_ENUM_CLASS (gtype_class ?: (gtype_class = g_type_class_ref (gtype)))))
nm_sprintf_buf (s_numeric, "0x%"G_GINT64_FORMAT, v);
else
nm_sprintf_buf (s_numeric, "%"G_GINT64_FORMAT, v);
if (nm_streq0 (s, s_numeric))
return g_steal_pointer (&s);
if (format_text_l10n)
return g_strdup_printf (_("%s (%s)"), s_numeric, s);
else
return g_strdup_printf ("%s (%s)", s_numeric, s);
}
/*****************************************************************************/
static gboolean
......@@ -745,20 +902,122 @@ _set_fcn_gobject_secret_flags (ARGS_SET_FCN)
return TRUE;
}
static gboolean
_set_fcn_gobject_enum (ARGS_SET_FCN)
{
GType gtype = 0;
GType gtype_prop;
gboolean has_gtype = FALSE;
nm_auto_unset_gvalue GValue gval = G_VALUE_INIT;
int v;
if (property_info->property_typ_data) {
if (property_info->property_typ_data->subtype.gobject_enum.get_gtype) {
gtype = property_info->property_typ_data->subtype.gobject_enum.get_gtype ();
has_gtype = TRUE;
}
}
gtype_prop = _gobject_property_get_gtype (G_OBJECT (setting), property_info->property_name);
if ( gtype_prop == G_TYPE_INT
|| G_IS_ENUM_CLASS (gtype_prop)) {
if (gtype_prop == G_TYPE_INT) {
if (!has_gtype)
g_return_val_if_reached (FALSE);
}
} else if ( gtype_prop == G_TYPE_UINT
|| G_IS_FLAGS_CLASS (gtype_prop)) {
if (gtype_prop == G_TYPE_UINT) {
if (!has_gtype)
g_return_val_if_reached (FALSE);
}
} else
g_return_val_if_reached (FALSE);
if (!has_gtype)
gtype = gtype_prop;
if (!nm_utils_enum_from_str (gtype, value, &v, NULL))
goto fail;
g_value_init (&gval, gtype_prop);
if ( gtype_prop == G_TYPE_INT
|| G_IS_ENUM_CLASS (gtype_prop)) {
if (gtype_prop == G_TYPE_INT)
g_value_set_int (&gval, v);
else
g_value_set_enum (&gval, v);
} else if ( gtype_prop == G_TYPE_UINT
|| G_IS_FLAGS_CLASS (gtype_prop)) {
if (gtype_prop == G_TYPE_UINT)
g_value_set_uint (&gval, v);
else
g_value_set_flags (&gval, v);
}
if (!nm_g_object_set_property (G_OBJECT (setting), property_info->property_name, &gval, NULL))
goto fail;
return TRUE;
fail:
if (error) {
gs_free const char **valid_all = NULL;
gs_free const char *valid_str = NULL;
int min = G_MININT;
int max = G_MAXINT;
if (property_info->property_typ_data) {
if ( property_info->property_typ_data->subtype.gobject_enum.min
|| property_info->property_typ_data->subtype.gobject_enum.max) {
min = property_info->property_typ_data->subtype.gobject_enum.min;
max = property_info->property_typ_data->subtype.gobject_enum.max;
}
}
valid_all = nm_utils_enum_get_values (gtype, min, max);
valid_str = g_strjoinv (",", (char **) valid_all);
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT,
_("invalid option '%s', use one of [%s]"),
value,
valid_str);
}
return FALSE;
}
/*****************************************************************************/
static const char *const*
_values_fcn_gobject_enum (ARGS_VALUES_FCN)
{
GType gtype = 0;
gboolean has_gtype = FALSE;
int min = G_MININT;
int max = G_MAXINT;
char **v, **w;
bool has_minmax = property_info->property_typ_data->subtype.gobject_enum.min
|| property_info->property_typ_data->subtype.gobject_enum.max;
v = (char **) nm_utils_enum_get_values ( property_info->property_typ_data->subtype.gobject_enum.get_gtype (),
has_minmax ? property_info->property_typ_data->subtype.gobject_enum.min : G_MININT,
has_minmax ? property_info->property_typ_data->subtype.gobject_enum.max : G_MAXINT);
for (w = v; w && *w; w++)
if (property_info->property_typ_data) {
if ( property_info->property_typ_data->subtype.gobject_enum.min
|| property_info->property_typ_data->subtype.gobject_enum.max) {
min = property_info->property_typ_data->subtype.gobject_enum.min;
max = property_info->property_typ_data->subtype.gobject_enum.max;
}
if (property_info->property_typ_data->subtype.gobject_enum.get_gtype) {
gtype = property_info->property_typ_data->subtype.gobject_enum.get_gtype ();
has_gtype = TRUE;
}
}
if (!has_gtype) {
gtype = _gtype_property_get_gtype (setting_info->general->get_setting_gtype (),
property_info->property_name);
}
v = (char **) nm_utils_enum_get_values (gtype, min, max);
if (v) {
for (w = v; *w; w++)
*w = g_strdup (*w);
}
return (const char *const*) (*out_to_free = v);
}
......@@ -3300,33 +3559,6 @@ _set_fcn_ip6_config_ip6_privacy (ARGS_SET_FCN)
return TRUE;
}
static char *
_get_fcn_ip6_config_addr_gen_mode (ARGS_GET_FCN)
{
NMSettingIP6Config *s_ip6 = NM_SETTING_IP6_CONFIG (setting);
NMSettingIP6ConfigAddrGenMode addr_gen_mode;
addr_gen_mode = nm_setting_ip6_config_get_addr_gen_mode (s_ip6);
return nm_utils_enum_to_str (nm_setting_ip6_config_addr_gen_mode_get_type (), addr_gen_mode);
}
static gboolean
_set_fcn_ip6_config_addr_gen_mode (ARGS_SET_FCN)
{
NMSettingIP6ConfigAddrGenMode addr_gen_mode;
if (!nm_utils_enum_from_str (nm_setting_ip6_config_addr_gen_mode_get_type (), value,
(int *) &addr_gen_mode, NULL)) {
g_set_error (error, 1, 0, _("invalid option '%s', use one of [%s]"),
value, "eui64,stable-privacy");
return FALSE;
}
g_object_set (setting, property_info->property_name, addr_gen_mode, NULL);
return TRUE;
}
static char *
_get_fcn_macsec_mode (ARGS_GET_FCN)
{
......@@ -4388,9 +4620,14 @@ register_nmcli_value_transforms (void)
#define DEFINE_PROPERTY_TYP_DATA(...) \
(&((NMMetaPropertyTypData) { __VA_ARGS__ } ))
#define DEFINE_PROPERTY_TYP_DATA_SUBTYPE(type, ...) \
#define PROPERTY_TYP_DATA_SUBTYPE(stype, ...) \
.subtype = { \
.stype = { __VA_ARGS__ }, \
}
#define DEFINE_PROPERTY_TYP_DATA_SUBTYPE(stype, ...) \
DEFINE_PROPERTY_TYP_DATA ( \
.subtype = { .type = { __VA_ARGS__ } } , \
PROPERTY_TYP_DATA_SUBTYPE (stype, __VA_ARGS__), \
)
static const NMMetaPropertyType _pt_name = {
......@@ -4441,6 +4678,12 @@ static const NMMetaPropertyType _pt_gobject_secret_flags = {
.set_fcn = _set_fcn_gobject_secret_flags,
};
static const NMMetaPropertyType _pt_gobject_enum = {
.get_fcn = _get_fcn_gobject_enum,
.set_fcn = _set_fcn_gobject_enum,
.values_fcn = _values_fcn_gobject_enum,
};
/*****************************************************************************/
/* FIXME: it is wrong to have a property-type "name". The name is a regular
......@@ -5511,14 +5754,14 @@ static const NMMetaPropertyInfo property_infos_ip6_config[] = {
},
{
.property_name = N_ (NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE),
.property_type = DEFINE_PROPERTY_TYPE (
.get_fcn = _get_fcn_ip6_config_addr_gen_mode,
.set_fcn = _set_fcn_ip6_config_addr_gen_mode,
.values_fcn = _values_fcn_gobject_enum,
),
.property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_enum,
.property_type = &_pt_gobject_enum,
.property_typ_data = DEFINE_PROPERTY_TYP_DATA (
PROPERTY_TYP_DATA_SUBTYPE (gobject_enum,
.get_gtype = nm_setting_ip6_config_addr_gen_mode_get_type,
),
.typ_flags = NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PARSABLE_TEXT
| NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PRETTY_TEXT,
),
},
{
.property_name = N_ (NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME),
......
......@@ -29,6 +29,16 @@ typedef enum {
NM_META_ACCESSOR_GET_TYPE_PARSABLE,
} NMMetaAccessorGetType;
typedef enum {
NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PRETTY_NUMERIC = (1LL << 0),
NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PRETTY_NUMERIC_HEX = (1LL << 1),
NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PRETTY_TEXT = (1LL << 2),
NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PRETTY_TEXT_L10N = (1LL << 3),
NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PARSABLE_NUMERIC = (1LL << 4),
NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PARSABLE_NUMERIC_HEX = (1LL << 5),
NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PARSABLE_TEXT = (1LL << 6),
} NMMetaPropertyTypFlags;
typedef enum {
NM_META_PROPERTY_TYPE_MAC_MODE_DEFAULT,
NM_META_PROPERTY_TYPE_MAC_MODE_CLONED,
......@@ -86,6 +96,7 @@ struct _NMMetaPropertyTypData {
} mac;
} subtype;
const char *const*values_static;
NMMetaPropertyTypFlags typ_flags;
};
struct _NMMetaPropertyInfo {
......
......@@ -55,6 +55,14 @@ _nm_auto_unset_gvalue_impl (GValue *v)
}
#define nm_auto_unset_gvalue nm_auto(_nm_auto_unset_gvalue_impl)
static inline void
_nm_auto_unref_gtypeclass (GTypeClass **v)
{
if (v && *v)
g_type_class_unref (*v);
}
#define nm_auto_unref_gtypeclass nm_auto(_nm_auto_unref_gtypeclass)
static inline void
_nm_auto_free_gstring_impl (GString **str)
{
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment