mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-03 19:50:14 +01:00
It was missing before.
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1970
Fixes: af5c1c8019 ('man nm-settings-nmcli: autogenerate the "Format" field')
591 lines
22 KiB
C
591 lines
22 KiB
C
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
|
|
|
#include "libnm-client-aux-extern/nm-default-client.h"
|
|
|
|
#include "libnmc-setting/nm-meta-setting-desc.h"
|
|
#include "libnmc-setting/nm-meta-setting-base.h"
|
|
#include "libnm-glib-aux/nm-enum-utils.h"
|
|
#include "libnm-core-aux-intern/nm-common-macros.h"
|
|
#include "nm-core-enum-types.h"
|
|
#include <stdarg.h>
|
|
#include <stdlib.h>
|
|
|
|
#define INDENT 4
|
|
|
|
#define prop_assert(cond, ...) \
|
|
G_STMT_START \
|
|
if (!(cond)) \
|
|
_prop_log(TRUE, __VA_ARGS__); \
|
|
G_STMT_END
|
|
#define prop_abort(...) _prop_log(TRUE, __VA_ARGS__)
|
|
#define prop_warn(...) _prop_log(FALSE, __VA_ARGS__)
|
|
|
|
static void G_GNUC_PRINTF(3, 4)
|
|
_prop_log(gboolean fatal, const NMMetaPropertyInfo *prop_info, const char *fmt, ...)
|
|
{
|
|
va_list vaargs;
|
|
gs_free char *msg = NULL;
|
|
gs_free char *msg_full = NULL;
|
|
|
|
va_start(vaargs, fmt);
|
|
msg = g_strdup_vprintf(fmt, vaargs);
|
|
msg_full = g_strdup_printf("gen-metadata-nm-settings-nmcli: %s.%s (type %d): %s\n",
|
|
prop_info->setting_info->general->setting_name,
|
|
prop_info->property_name,
|
|
(int) prop_info->property_type->doc_format,
|
|
msg);
|
|
va_end(vaargs);
|
|
|
|
if (fatal)
|
|
g_error("%s", msg_full);
|
|
else
|
|
g_warning("%s", msg_full);
|
|
}
|
|
|
|
static char *
|
|
_xml_escape_attribute(const char *value)
|
|
{
|
|
gs_free char *s = NULL;
|
|
|
|
s = g_markup_escape_text(value, -1);
|
|
return g_strdup_printf("\"%s\"", s);
|
|
}
|
|
|
|
static const char *
|
|
_indent_level(guint num_spaces)
|
|
{
|
|
static const char spaces[] = " ";
|
|
|
|
nm_assert(num_spaces < G_N_ELEMENTS(spaces));
|
|
return &spaces[G_N_ELEMENTS(spaces) - num_spaces - 1];
|
|
}
|
|
|
|
static GType
|
|
_property_get_gtype(const NMMetaPropertyInfo *prop_info)
|
|
{
|
|
nm_auto_unref_gtypeclass NMSettingClass *setting_class =
|
|
g_type_class_ref(prop_info->setting_info->general->get_setting_gtype());
|
|
GParamSpec *param_spec =
|
|
g_object_class_find_property(G_OBJECT_CLASS(setting_class), prop_info->property_name);
|
|
|
|
if (param_spec)
|
|
return param_spec->value_type;
|
|
g_return_val_if_reached(G_TYPE_INVALID);
|
|
}
|
|
|
|
static char *
|
|
get_enum_format(GType g_type)
|
|
{
|
|
if (G_TYPE_IS_FLAGS(g_type))
|
|
return g_strdup_printf("flags (%s)", g_type_name(g_type));
|
|
else
|
|
return g_strdup_printf("choice (%s)", g_type_name(g_type));
|
|
}
|
|
|
|
static char *
|
|
get_mac_format(const NMMetaPropertyInfo *prop_info)
|
|
{
|
|
const NMMetaPropertyTypData *prop_typ_data = prop_info->property_typ_data;
|
|
|
|
if (prop_typ_data) {
|
|
switch (prop_typ_data->subtype.mac.mode) {
|
|
case NM_META_PROPERTY_TYPE_MAC_MODE_DEFAULT:
|
|
case NM_META_PROPERTY_TYPE_MAC_MODE_CLONED_ETHERNET:
|
|
case NM_META_PROPERTY_TYPE_MAC_MODE_CLONED_WIFI:
|
|
break;
|
|
case NM_META_PROPERTY_TYPE_MAC_MODE_INFINIBAND:
|
|
return g_strdup("Infiniband MAC address");
|
|
case NM_META_PROPERTY_TYPE_MAC_MODE_WPAN:
|
|
return g_strdup("WPAN MAC address");
|
|
default:
|
|
prop_abort(prop_info, "unknown mode (%d)", prop_typ_data->subtype.mac.mode);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return g_strdup("MAC address");
|
|
}
|
|
|
|
static char *
|
|
get_ethtool_format(const NMMetaPropertyInfo *prop_info)
|
|
{
|
|
NMEthtoolID ethtool_id;
|
|
|
|
prop_assert(prop_info->property_typ_data, prop_info, "missing .property_typ_data");
|
|
|
|
ethtool_id = prop_info->property_typ_data->subtype.ethtool.ethtool_id;
|
|
|
|
switch (nm_ethtool_id_to_type(ethtool_id)) {
|
|
case NM_ETHTOOL_TYPE_CHANNELS:
|
|
case NM_ETHTOOL_TYPE_COALESCE:
|
|
case NM_ETHTOOL_TYPE_RING:
|
|
return g_strdup("integer");
|
|
case NM_ETHTOOL_TYPE_FEATURE:
|
|
case NM_ETHTOOL_TYPE_PAUSE:
|
|
case NM_ETHTOOL_TYPE_EEE:
|
|
return g_strdup("ternary");
|
|
case NM_ETHTOOL_TYPE_UNKNOWN:
|
|
nm_assert_not_reached();
|
|
};
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static char *
|
|
get_multilist_format(const NMMetaPropertyInfo *prop_info)
|
|
{
|
|
NMMetaPropertyTypeFormat item_fmt;
|
|
|
|
if (prop_info->property_typ_data) {
|
|
item_fmt = prop_info->property_typ_data->list_items_doc_format;
|
|
|
|
switch (item_fmt) {
|
|
case NM_META_PROPERTY_TYPE_FORMAT_UNDEF:
|
|
prop_abort(prop_info, "undefined item format for multilist");
|
|
break;
|
|
case NM_META_PROPERTY_TYPE_FORMAT_INT:
|
|
case NM_META_PROPERTY_TYPE_FORMAT_MTU:
|
|
return g_strdup("list of integers");
|
|
case NM_META_PROPERTY_TYPE_FORMAT_STRING:
|
|
return g_strdup("list of strings");
|
|
case NM_META_PROPERTY_TYPE_FORMAT_BOOL:
|
|
return g_strdup("list of booleans");
|
|
case NM_META_PROPERTY_TYPE_FORMAT_TERNARY:
|
|
return g_strdup("list of ternaries");
|
|
case NM_META_PROPERTY_TYPE_FORMAT_MAC:
|
|
return g_strdup("list of MAC addresses");
|
|
case NM_META_PROPERTY_TYPE_FORMAT_IPV4:
|
|
return g_strdup("list of IPv4 addresses");
|
|
case NM_META_PROPERTY_TYPE_FORMAT_IPV6:
|
|
return g_strdup("list of IPv6 addresses");
|
|
default:
|
|
prop_abort(prop_info, "unsupported item format (%d)", item_fmt);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static char *
|
|
get_property_format(const NMMetaPropertyInfo *prop_info)
|
|
{
|
|
const NMMetaPropertyType *prop_type = prop_info->property_type;
|
|
NMMetaPropertyTypeFormat fmt = prop_type->doc_format;
|
|
|
|
if (!prop_type->set_fcn)
|
|
return g_strdup("read only");
|
|
|
|
switch (fmt) {
|
|
case NM_META_PROPERTY_TYPE_FORMAT_INT:
|
|
case NM_META_PROPERTY_TYPE_FORMAT_MTU:
|
|
return g_strdup("integer");
|
|
case NM_META_PROPERTY_TYPE_FORMAT_STRING:
|
|
return g_strdup("string");
|
|
case NM_META_PROPERTY_TYPE_FORMAT_ENUM:
|
|
return get_enum_format(nm_meta_property_enum_get_type(prop_info));
|
|
case NM_META_PROPERTY_TYPE_FORMAT_SECRET_FLAGS:
|
|
return get_enum_format(NM_TYPE_SETTING_SECRET_FLAGS);
|
|
case NM_META_PROPERTY_TYPE_FORMAT_DCB_FLAGS:
|
|
return get_enum_format(NM_TYPE_SETTING_DCB_FLAGS);
|
|
case NM_META_PROPERTY_TYPE_FORMAT_BOOL:
|
|
return g_strdup("boolean");
|
|
case NM_META_PROPERTY_TYPE_FORMAT_TERNARY:
|
|
return g_strdup("ternary");
|
|
case NM_META_PROPERTY_TYPE_FORMAT_MAC:
|
|
return get_mac_format(prop_info);
|
|
case NM_META_PROPERTY_TYPE_FORMAT_IPV4:
|
|
return g_strdup("IPv4 address");
|
|
case NM_META_PROPERTY_TYPE_FORMAT_IPV6:
|
|
return g_strdup("IPv6 address");
|
|
case NM_META_PROPERTY_TYPE_FORMAT_BYTES:
|
|
return g_strdup("bytes");
|
|
case NM_META_PROPERTY_TYPE_FORMAT_PATH:
|
|
return g_strdup("filesystem path");
|
|
case NM_META_PROPERTY_TYPE_FORMAT_ETHTOOL:
|
|
return get_ethtool_format(prop_info);
|
|
case NM_META_PROPERTY_TYPE_FORMAT_MULTILIST:
|
|
return get_multilist_format(prop_info);
|
|
case NM_META_PROPERTY_TYPE_FORMAT_OBJLIST:
|
|
return g_strdup_printf("list of %s.%s objects",
|
|
prop_info->setting_info->general->setting_name,
|
|
prop_info->property_name);
|
|
case NM_META_PROPERTY_TYPE_FORMAT_OPTIONLIST:
|
|
return g_strdup("list of key/value options");
|
|
case NM_META_PROPERTY_TYPE_FORMAT_DCB:
|
|
return g_strdup("list of integers");
|
|
case NM_META_PROPERTY_TYPE_FORMAT_DCB_BOOL:
|
|
return g_strdup("list of booleans");
|
|
default:
|
|
prop_abort(prop_info, "missing .format");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
#define append_vals(to, ...) \
|
|
G_STMT_START \
|
|
{ \
|
|
size_t i; \
|
|
const char *from[] = {__VA_ARGS__}; \
|
|
for (i = 0; i < NM_N_ELEMENTS(from); i++) \
|
|
g_ptr_array_add((to), g_strdup(from[i])); \
|
|
} \
|
|
G_STMT_END
|
|
|
|
static void
|
|
append_connection_types(GPtrArray *valid_values)
|
|
{
|
|
size_t i;
|
|
for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) {
|
|
/* If the setting has a priority of a base-type, it's a valid value for connection.type */
|
|
NMSettingPriority pri =
|
|
_nm_setting_type_get_base_type_priority(nm_meta_setting_infos[i].get_setting_gtype());
|
|
if (pri != NM_SETTING_PRIORITY_INVALID)
|
|
g_ptr_array_add(valid_values, g_strdup(nm_meta_setting_infos[i].setting_name));
|
|
}
|
|
}
|
|
|
|
static void
|
|
append_int_valid_range(const NMMetaPropertyInfo *prop_info, GPtrArray *valid_values)
|
|
{
|
|
NMMetaSignUnsignInt64 min;
|
|
NMMetaSignUnsignInt64 max;
|
|
|
|
nm_meta_property_int_get_range(prop_info, &min, &max);
|
|
if (NM_IN_SET(_property_get_gtype(prop_info), G_TYPE_UINT, G_TYPE_UINT64)) {
|
|
g_ptr_array_add(
|
|
valid_values,
|
|
g_strdup_printf("%" G_GUINT64_FORMAT " - %" G_GUINT64_FORMAT, min.u64, max.u64));
|
|
} else {
|
|
g_ptr_array_add(
|
|
valid_values,
|
|
g_strdup_printf("%" G_GINT64_FORMAT " - %" G_GINT64_FORMAT, min.i64, max.i64));
|
|
}
|
|
}
|
|
|
|
static void
|
|
_append_enum_valid_values(GType g_type,
|
|
int min,
|
|
int max,
|
|
const NMUtilsEnumValueInfo *value_infos,
|
|
GPtrArray *valid_values)
|
|
{
|
|
size_t i;
|
|
const char **alias;
|
|
GString *names = g_string_sized_new(64);
|
|
GArray *values = _nm_utils_enum_get_values_full(g_type, min, max, value_infos);
|
|
|
|
for (i = 0; i < values->len; i++) {
|
|
NMUtilsEnumValueInfoFull *val = &nm_g_array_index(values, NMUtilsEnumValueInfoFull, i);
|
|
|
|
g_string_assign(names, val->nick);
|
|
|
|
if (val->aliases) {
|
|
for (alias = val->aliases; *alias; alias++) {
|
|
g_string_append_c(names, '/');
|
|
g_string_append(names, *alias);
|
|
}
|
|
}
|
|
|
|
g_ptr_array_add(valid_values, g_strdup_printf("%s (%s)", names->str, val->value_str));
|
|
}
|
|
|
|
g_string_free(names, TRUE);
|
|
g_array_unref(values);
|
|
}
|
|
|
|
static void
|
|
append_enum_valid_values(const NMMetaPropertyInfo *prop_info, GPtrArray *valid_values)
|
|
{
|
|
const NMMetaPropertyTypData *prop_typ_data = prop_info->property_typ_data;
|
|
const NMUtilsEnumValueInfo *value_infos;
|
|
GType gtype;
|
|
int min;
|
|
int max;
|
|
|
|
gtype = nm_meta_property_enum_get_type(prop_info);
|
|
nm_meta_property_enum_get_range(prop_info, &min, &max);
|
|
value_infos = prop_typ_data ? prop_typ_data->subtype.gobject_enum.value_infos : NULL;
|
|
|
|
_append_enum_valid_values(gtype, min, max, value_infos, valid_values);
|
|
}
|
|
|
|
static void
|
|
append_ethtool_valid_values(const NMMetaPropertyInfo *prop_info, GPtrArray *valid_values)
|
|
{
|
|
NMEthtoolID ethtool_id;
|
|
|
|
prop_assert(prop_info->property_typ_data, prop_info, "missing .property_typ_data");
|
|
|
|
ethtool_id = prop_info->property_typ_data->subtype.ethtool.ethtool_id;
|
|
|
|
switch (nm_ethtool_id_to_type(ethtool_id)) {
|
|
case NM_ETHTOOL_TYPE_CHANNELS:
|
|
case NM_ETHTOOL_TYPE_COALESCE:
|
|
case NM_ETHTOOL_TYPE_RING:
|
|
g_ptr_array_add(valid_values, g_strdup_printf("0 - %u", G_MAXUINT32));
|
|
break;
|
|
case NM_ETHTOOL_TYPE_FEATURE:
|
|
case NM_ETHTOOL_TYPE_PAUSE:
|
|
case NM_ETHTOOL_TYPE_EEE:
|
|
append_vals(valid_values, "on", "off", "ignore");
|
|
break;
|
|
case NM_ETHTOOL_TYPE_UNKNOWN:
|
|
nm_assert_not_reached();
|
|
}
|
|
}
|
|
|
|
static void
|
|
append_dcb_valid_values(const NMMetaPropertyInfo *prop_info, GPtrArray *valid_values)
|
|
{
|
|
guint max;
|
|
guint other;
|
|
|
|
prop_assert(prop_info->property_typ_data, prop_info, "missing .property_typ_data");
|
|
|
|
max = prop_info->property_typ_data->subtype.dcb.max;
|
|
other = prop_info->property_typ_data->subtype.dcb.other;
|
|
|
|
if (max != 0)
|
|
g_ptr_array_add(valid_values, g_strdup_printf("0 - %u", max));
|
|
if (other != 0 && (!max || other > max))
|
|
g_ptr_array_add(valid_values, g_strdup_printf("%u", other));
|
|
}
|
|
|
|
static GPtrArray *
|
|
get_property_valid_values(const NMMetaPropertyInfo *prop_info)
|
|
{
|
|
const NMMetaPropertyType *prop_type = prop_info->property_type;
|
|
const NMMetaPropertyTypData *prop_typ_data = prop_info->property_typ_data;
|
|
NMMetaPropertyTypeFormat fmt = prop_type->doc_format;
|
|
GPtrArray *valid_values = g_ptr_array_new_full(16, g_free);
|
|
|
|
/* connection.type is generated differently */
|
|
if (prop_info->setting_info->general->meta_type == NM_META_SETTING_TYPE_CONNECTION
|
|
&& !nm_strcmp0(prop_info->property_name, "type")) {
|
|
append_connection_types(valid_values);
|
|
return valid_values;
|
|
}
|
|
|
|
/* If it's a list, get the format of the items, but only if we can process it
|
|
* (prop_typ_data->subtype is of type multilist, so we can't process ints or enums) */
|
|
if (fmt == NM_META_PROPERTY_TYPE_FORMAT_MULTILIST && prop_typ_data) {
|
|
switch (prop_typ_data->list_items_doc_format) {
|
|
case NM_META_PROPERTY_TYPE_FORMAT_SECRET_FLAGS:
|
|
case NM_META_PROPERTY_TYPE_FORMAT_DCB_FLAGS:
|
|
case NM_META_PROPERTY_TYPE_FORMAT_BOOL:
|
|
case NM_META_PROPERTY_TYPE_FORMAT_DCB_BOOL:
|
|
case NM_META_PROPERTY_TYPE_FORMAT_TERNARY:
|
|
case NM_META_PROPERTY_TYPE_FORMAT_ETHTOOL:
|
|
fmt = prop_typ_data->list_items_doc_format;
|
|
break;
|
|
case NM_META_PROPERTY_TYPE_FORMAT_ENUM:
|
|
prop_warn(prop_info, "unknown enum type, can't get valid values");
|
|
break;
|
|
case NM_META_PROPERTY_TYPE_FORMAT_INT:
|
|
prop_warn(prop_info, "can't check for valid range in multilists");
|
|
break;
|
|
default:
|
|
/* Other types probably don't need to show "Valid values" */
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch (fmt) {
|
|
case NM_META_PROPERTY_TYPE_FORMAT_INT:
|
|
append_int_valid_range(prop_info, valid_values);
|
|
break;
|
|
case NM_META_PROPERTY_TYPE_FORMAT_ENUM:
|
|
append_enum_valid_values(prop_info, valid_values);
|
|
break;
|
|
case NM_META_PROPERTY_TYPE_FORMAT_SECRET_FLAGS:
|
|
_append_enum_valid_values(NM_TYPE_SETTING_SECRET_FLAGS, 0, G_MAXUINT, NULL, valid_values);
|
|
break;
|
|
case NM_META_PROPERTY_TYPE_FORMAT_DCB_FLAGS:
|
|
_append_enum_valid_values(NM_TYPE_SETTING_DCB_FLAGS, 0, G_MAXUINT, NULL, valid_values);
|
|
break;
|
|
case NM_META_PROPERTY_TYPE_FORMAT_BOOL:
|
|
case NM_META_PROPERTY_TYPE_FORMAT_DCB_BOOL:
|
|
append_vals(valid_values, "true/yes/on", "false/no/off");
|
|
break;
|
|
case NM_META_PROPERTY_TYPE_FORMAT_TERNARY:
|
|
append_vals(valid_values, "true/yes/on", "false/no/off", "default/unknown");
|
|
break;
|
|
case NM_META_PROPERTY_TYPE_FORMAT_ETHTOOL:
|
|
append_ethtool_valid_values(prop_info, valid_values);
|
|
break;
|
|
case NM_META_PROPERTY_TYPE_FORMAT_DCB:
|
|
append_dcb_valid_values(prop_info, valid_values);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (prop_typ_data && prop_typ_data->values_static) {
|
|
const char *const *v;
|
|
for (v = prop_typ_data->values_static; *v; v++)
|
|
g_ptr_array_add(valid_values, g_strdup(*v));
|
|
}
|
|
|
|
return valid_values;
|
|
}
|
|
|
|
static void
|
|
append_int_special_values(const NMMetaPropertyInfo *prop_info, GPtrArray *special_values)
|
|
{
|
|
const NMMetaPropertyTypData *prop_typ_data = prop_info->property_typ_data;
|
|
|
|
if (prop_typ_data && prop_typ_data->subtype.gobject_int.value_infos) {
|
|
GType gtype = _property_get_gtype(prop_info);
|
|
bool is_uint = NM_IN_SET(gtype, G_TYPE_UINT, G_TYPE_UINT64);
|
|
guint base = prop_typ_data->subtype.gobject_int.base;
|
|
const NMMetaUtilsIntValueInfo *v = prop_typ_data->subtype.gobject_int.value_infos;
|
|
|
|
if (!(base == 0 || base == 10 || (is_uint && base == 16))) {
|
|
if (is_uint)
|
|
prop_abort(prop_info, "only base 10 supported for signed int");
|
|
else
|
|
prop_abort(prop_info, "only base 10 or 16 supported for uint");
|
|
}
|
|
|
|
for (; v->nick != NULL; v++) {
|
|
char *v_str;
|
|
if (base == 16)
|
|
v_str = g_strdup_printf("%s (0x%" G_GINT64_MODIFIER "x)", v->nick, v->value.u64);
|
|
else if (is_uint)
|
|
v_str = g_strdup_printf("%s (%" G_GUINT64_FORMAT ")", v->nick, v->value.u64);
|
|
else
|
|
v_str = g_strdup_printf("%s (%" G_GINT64_FORMAT ")", v->nick, v->value.i64);
|
|
|
|
g_ptr_array_add(special_values, v_str);
|
|
}
|
|
}
|
|
}
|
|
|
|
static GPtrArray *
|
|
get_property_special_values(const NMMetaPropertyInfo *prop_info)
|
|
{
|
|
const NMMetaPropertyType *prop_type = prop_info->property_type;
|
|
const NMMetaPropertyTypData *prop_typ_data = prop_info->property_typ_data;
|
|
NMMetaPropertyTypeFormat fmt = prop_type->doc_format;
|
|
GPtrArray *special_values = g_ptr_array_new_full(16, g_free);
|
|
|
|
switch (fmt) {
|
|
case NM_META_PROPERTY_TYPE_FORMAT_INT:
|
|
append_int_special_values(prop_info, special_values);
|
|
break;
|
|
case NM_META_PROPERTY_TYPE_FORMAT_MAC:
|
|
if (prop_typ_data) {
|
|
switch (prop_typ_data->subtype.mac.mode) {
|
|
case NM_META_PROPERTY_TYPE_MAC_MODE_CLONED_ETHERNET:
|
|
case NM_META_PROPERTY_TYPE_MAC_MODE_CLONED_WIFI:
|
|
append_vals(special_values,
|
|
NM_CLONED_MAC_PRESERVE,
|
|
NM_CLONED_MAC_PERMANENT,
|
|
NM_CLONED_MAC_RANDOM,
|
|
NM_CLONED_MAC_STABLE);
|
|
if (prop_typ_data->subtype.mac.mode == NM_META_PROPERTY_TYPE_MAC_MODE_CLONED_WIFI)
|
|
append_vals(special_values, NM_CLONED_MAC_STABLE_SSID);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case NM_META_PROPERTY_TYPE_FORMAT_MTU:
|
|
g_ptr_array_add(special_values, g_strdup("auto"));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return special_values;
|
|
}
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
int i_sett_infos;
|
|
int i_property;
|
|
|
|
g_print("<nm-setting-docs>\n");
|
|
for (i_sett_infos = 0; i_sett_infos < G_N_ELEMENTS(nm_meta_setting_infos_editor);
|
|
i_sett_infos++) {
|
|
const NMMetaSettingInfoEditor *sett_info = &nm_meta_setting_infos_editor[i_sett_infos];
|
|
gs_free char *tmp_s1 = NULL;
|
|
gs_free char *tmp_s2 = NULL;
|
|
|
|
g_print("%s<setting", _indent_level(INDENT));
|
|
g_print(" name=%s", tmp_s1 = _xml_escape_attribute(sett_info->general->setting_name));
|
|
if (sett_info->alias)
|
|
g_print("\n%salias=%s",
|
|
_indent_level(INDENT + 9),
|
|
tmp_s2 = _xml_escape_attribute(sett_info->alias));
|
|
g_print(" >\n");
|
|
|
|
for (i_property = 0; i_property < sett_info->properties_num; i_property++) {
|
|
const NMMetaPropertyInfo *prop_info = sett_info->properties[i_property];
|
|
gs_free char *name = NULL;
|
|
gs_free char *alias = NULL;
|
|
gs_free char *descr = NULL;
|
|
gs_free char *fmt = NULL;
|
|
gs_unref_ptrarray GPtrArray *vals_arr = NULL;
|
|
gs_free char *vals_str = NULL;
|
|
gs_unref_ptrarray GPtrArray *specials_arr = NULL;
|
|
gs_free char *specials_str = NULL;
|
|
|
|
g_print("%s<property", _indent_level(2 * INDENT));
|
|
g_print(" name=%s", name = _xml_escape_attribute(prop_info->property_name));
|
|
if (prop_info->property_alias)
|
|
g_print("\n%salias=%s",
|
|
_indent_level(2 * INDENT + 10),
|
|
alias = _xml_escape_attribute(prop_info->property_alias));
|
|
if (prop_info->describe_doc) {
|
|
/* These descriptions are used by interactive nmcli modes. For the most part,
|
|
* they are themselves generated (see "settings-docs.h"). Some of them are instead
|
|
* explicitly (manually) set.
|
|
*
|
|
* In any case, they serve little purpose outside of nmcli's interactive mode,
|
|
* because their formatting/wording would not be suitable.
|
|
*
|
|
* We generate this XML mainly to generate `man nm-settings-nmcli`, but the
|
|
* descriptions in "describe_doc" field are not suitable there.
|
|
*
|
|
* Name them something else ("<nmcli-description>") which isn't actually used. */
|
|
g_print("\n%snmcli-description=%s",
|
|
_indent_level(2 * INDENT + 10),
|
|
descr = _xml_escape_attribute(prop_info->describe_doc));
|
|
}
|
|
|
|
fmt = get_property_format(prop_info);
|
|
if (fmt)
|
|
g_print("\n%sformat=%s",
|
|
_indent_level(2 * INDENT + 10),
|
|
_xml_escape_attribute(fmt));
|
|
|
|
vals_arr = get_property_valid_values(prop_info);
|
|
if (vals_arr->len) {
|
|
g_ptr_array_add(vals_arr, NULL);
|
|
vals_str = g_strjoinv(", ", (char **) vals_arr->pdata);
|
|
g_print("\n%svalues=%s",
|
|
_indent_level(2 * INDENT + 10),
|
|
_xml_escape_attribute(vals_str));
|
|
}
|
|
|
|
specials_arr = get_property_special_values(prop_info);
|
|
if (specials_arr->len) {
|
|
g_ptr_array_add(specials_arr, NULL);
|
|
specials_str = g_strjoinv(", ", (char **) specials_arr->pdata);
|
|
g_print("\n%sspecial-values=%s",
|
|
_indent_level(2 * INDENT + 10),
|
|
_xml_escape_attribute(specials_str));
|
|
}
|
|
|
|
g_print(" />\n");
|
|
}
|
|
|
|
g_print("%s</setting>\n", _indent_level(INDENT));
|
|
}
|
|
g_print("</nm-setting-docs>\n");
|
|
return 0;
|
|
}
|