diff options
Diffstat (limited to 'clients/common/nm-meta-setting-access.c')
-rw-r--r-- | clients/common/nm-meta-setting-access.c | 296 |
1 files changed, 270 insertions, 26 deletions
diff --git a/clients/common/nm-meta-setting-access.c b/clients/common/nm-meta-setting-access.c index 7a0cefde9d..ebaf6e7ebc 100644 --- a/clients/common/nm-meta-setting-access.c +++ b/clients/common/nm-meta-setting-access.c @@ -21,36 +21,67 @@ #include "nm-meta-setting-access.h" +#include <NetworkManager.h> + /*****************************************************************************/ const NMMetaSettingInfoEditor * -nm_meta_setting_info_editor_find_by_name (const char *setting_name, gboolean use_alias) +nm_meta_setting_info_editor_find_by_fuzzyname (const char *setting_name, gboolean use_alias, + gboolean fuzzy_match, gboolean *out_unique) { - const NMMetaSettingInfo *meta_setting_info; - const NMMetaSettingInfoEditor *setting_info; + const NMMetaSettingInfoEditor *best_match = NULL; + guint found = 0; + gsize l; guint i; g_return_val_if_fail (setting_name, NULL); - meta_setting_info = nm_meta_setting_infos_by_name (setting_name); - setting_info = NULL; - if (meta_setting_info) { - nm_assert (nm_streq0 (meta_setting_info->setting_name, setting_name)); - if (meta_setting_info->meta_type < G_N_ELEMENTS (nm_meta_setting_infos_editor)) { - setting_info = &nm_meta_setting_infos_editor[meta_setting_info->meta_type]; - nm_assert (setting_info->general == meta_setting_info); + if (!*setting_name) + goto out; + + l = strlen (setting_name); + + for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) { + const NMMetaSettingInfoEditor *si = &nm_meta_setting_infos_editor[i]; + + if (nm_streq (si->general->setting_name, setting_name)) { + NM_SET_OUT (out_unique, TRUE); + return si; } - } - if (!setting_info && use_alias) { - for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) { - if (nm_streq0 (nm_meta_setting_infos_editor[i].alias, setting_name)) { - setting_info = &nm_meta_setting_infos_editor[i]; - break; - } + if ( fuzzy_match + && g_ascii_strncasecmp (si->general->setting_name, setting_name, l)) + goto found_fuzzy; + + if (use_alias) { + if (nm_streq0 (si->alias, setting_name)) + goto found_fuzzy; + if ( fuzzy_match + && g_ascii_strncasecmp (si->alias, setting_name, l)) + goto found_fuzzy; } + + continue; +found_fuzzy: + if (!best_match) + best_match = si; + found++; + if (found >= 2) + break; } - return setting_info; +out: + /* a non-unique match may not seem interesting at first. It is however + * because we need to distinguish between no setting-for-the-name + * (and search the property-aliases), or have-a-non-unique-match (and + * don't check proerty-aliases). */ + NM_SET_OUT (out_unique, found <= 1); + return best_match; +} + +const NMMetaSettingInfoEditor * +nm_meta_setting_info_editor_find_by_name (const char *setting_name, gboolean use_alias) +{ + return nm_meta_setting_info_editor_find_by_fuzzyname (setting_name, use_alias, FALSE, NULL); } const NMMetaSettingInfoEditor * @@ -93,21 +124,46 @@ nm_meta_setting_info_editor_find_by_setting (NMSetting *setting) } const NMMetaPropertyInfo * -nm_meta_setting_info_editor_get_property_info (const NMMetaSettingInfoEditor *setting_info, const char *property_name) +nm_meta_setting_info_editor_get_property_info (const NMMetaSettingInfoEditor *setting_info, + const char *property_name, + gboolean fuzzy_match) { + const NMMetaPropertyInfo *best_match = NULL; + gsize l; guint i; g_return_val_if_fail (setting_info, NULL); g_return_val_if_fail (property_name, NULL); + if (!property_name) + return NULL; + + if (setting_info->get_property_info) { + return setting_info->get_property_info (setting_info, + property_name, + fuzzy_match); + } + + l = strlen (property_name); + for (i = 0; i < setting_info->properties_num; i++) { - nm_assert (setting_info->properties[i]->property_name); - nm_assert (setting_info->properties[i]->setting_info == setting_info); - if (nm_streq (setting_info->properties[i]->property_name, property_name)) - return setting_info->properties[i]; + const NMMetaPropertyInfo *si = setting_info->properties[i]; + + nm_assert (si->property_name); + nm_assert (si->setting_info == setting_info); + + if (nm_streq (si->property_name, property_name)) + return si; + + if ( fuzzy_match + && g_ascii_strncasecmp (si->property_name, property_name, l)) { + if (best_match) + return NULL; + best_match = si; + } } - return NULL; + return best_match; } const NMMetaPropertyInfo * @@ -120,7 +176,7 @@ nm_meta_property_info_find_by_name (const char *setting_name, const char *proper if (!setting_info) return NULL; - property_info = nm_meta_setting_info_editor_get_property_info (setting_info, property_name); + property_info = nm_meta_setting_info_editor_get_property_info (setting_info, property_name, FALSE); if (!property_info) return NULL; @@ -138,7 +194,7 @@ nm_meta_property_info_find_by_setting (NMSetting *setting, const char *property_ setting_info = nm_meta_setting_info_editor_find_by_setting (setting); if (!setting_info) return NULL; - property_info = nm_meta_setting_info_editor_get_property_info (setting_info, property_name); + property_info = nm_meta_setting_info_editor_get_property_info (setting_info, property_name, FALSE); if (!property_info) return NULL; @@ -325,6 +381,73 @@ nm_meta_abstract_info_complete (const NMMetaAbstractInfo *abstract_info, } } +/** + * nm_meta_abstract_info_get_property_names: + * @abstract_info: the meta data + * @target: (allow none): an optional target instance. The result + * of property names may or may not depend on the target. + * If present, @target must be valid for @abstract_info. + * @get_property_names_flags: flags argument to control the result. + * + * Returns: (transfer full): the list of valid property names for target. + * For most setting types, this is just the static list of GObject property + * names. + * For some types this may be a type dependent list of properties (bond.options). + * For other types, it may even be a list of properties that are generated based + * on the current @setting (user.data). */ +char ** +nm_meta_abstract_info_get_property_names (const NMMetaAbstractInfo *abstract_info, + gpointer target, + NMMetaAccessorGetPropertyNamesFlags get_property_names_flags) +{ + GPtrArray *result; + + g_return_val_if_fail (abstract_info, NULL); + + if (!abstract_info->meta_type->get_property_names) + return NULL; + + if (!NM_FLAGS_ANY (get_property_names_flags, + NM_META_ACCESSOR_GET_PROPERTY_NAMES_FLAGS_WITH_THIS_LEVEL + | NM_META_ACCESSOR_GET_PROPERTY_NAMES_FLAGS_WITH_TOPLEVEL_LEVEL)) + get_property_names_flags |= NM_META_ACCESSOR_GET_PROPERTY_NAMES_FLAGS_WITH_THIS_LEVEL; + + result = g_ptr_array_new (); + abstract_info->meta_type->get_property_names (abstract_info, + target, + get_property_names_flags, + result); + if (!result->len) { + g_ptr_array_free (result, TRUE); + return NULL; + } + + g_ptr_array_sort (result, nm_strcmp_p); + g_ptr_array_add (result, NULL); + return _nm_utils_strv_cleanup ((char **) g_ptr_array_free (result, FALSE), + FALSE, FALSE, TRUE); +} + +gboolean +nm_meta_abstract_info_set_property (const NMMetaAbstractInfo *abstract_info, + gpointer target, + const char *property_name, + const char *value, + GError **error) +{ + g_return_val_if_fail (target, FALSE); + g_return_val_if_fail (property_name, FALSE); + g_return_val_if_fail (!error || !*error, FALSE); + g_return_val_if_fail (abstract_info, FALSE); + g_return_val_if_fail (abstract_info->meta_type->set_property, FALSE); + + return abstract_info->meta_type->set_property (abstract_info, + target, + property_name, + value, + error); +} + /*****************************************************************************/ char * @@ -373,6 +496,45 @@ nm_meta_abstract_infos_get_names_str (const NMMetaAbstractInfo *const*fields_arr /*****************************************************************************/ +static void +_parse_name (const char *name, + const char **out_toplevel, + const char **out_nested, + NMMetaPropertyNameModifier *out_modifier, + char **out_to_free) +{ + const char *toplevel = NULL; + const char *nested = NULL; + NMMetaPropertyNameModifier modifier = NM_META_PROPERTY_NAME_MODIFIER_NONE; + const char *s; + char *t; + + if (name) { + if (NM_IN_SET (name[0], '+', '-')) { + modifier = name[0] == '+' + ? NM_META_PROPERTY_NAME_MODIFIER_PLUS + : NM_META_PROPERTY_NAME_MODIFIER_MINUS; + name++; + } + + s = strchr (name, '.'); + if (!s) + toplevel = name; + else { + t = g_strdup (name); + *out_to_free = t; + toplevel = t; + t = &t[s - name]; + *t = '\0'; + nested = t+1; + } + } + + *out_toplevel = toplevel; + *out_nested = nested; + *out_modifier = modifier; +} + typedef struct { guint idx; gsize self_offset_plus_1; @@ -619,3 +781,85 @@ nm_meta_selection_create_parse_list (const NMMetaAbstractInfo *const* fields_arr return _output_selection_pack (fields_array, array, str); } + +NMMetaSelectionResultList * +nm_meta_selection_parse_connection_property_name (NMConnection *connection, + const char *property_name, + GError **error) +{ + const char *const property_name_orig = property_name; + gs_free char *parsed_name_tmp = NULL; + const char *nested_name; + NMMetaPropertyNameModifier modifier; + const NMMetaSettingInfoEditor *setting_info = NULL; + const NMMetaPropertyInfo *property_info = NULL; + + g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + + _parse_name (property_name, + &property_name, + &nested_name, + &modifier, + &parsed_name_tmp); + + if (property_name || !property_name[0]) + goto out_invalid_toplevel_name; + + { + gboolean unique_match; + + setting_info = nm_meta_setting_info_editor_find_by_fuzzyname (property_name, TRUE, TRUE, &unique_match); + if (!unique_match) + goto out_invalid_toplevel_name; + } + + if (setting_info) { + if (!nested_name) { + gs_strfreev char **v = NULL; + gs_free char *t = NULL; + + v = nm_meta_abstract_info_get_property_names ((const NMMetaAbstractInfo *) setting_info, + nm_connection_get_setting_by_name (connection, setting_info->general->setting_name), + NM_META_ACCESSOR_GET_PROPERTY_NAMES_FLAGS_WITH_THIS_LEVEL); + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT, + _("invalid property name \"%s\". Requires a property name like [%s]"), + property_name_orig, (t = g_strjoinv (",", v))); + return FALSE; + } + + property_info = nm_meta_setting_info_editor_get_property_info (setting_info, + nested_name, + TRUE); + if (!property_info) { + gs_strfreev char **v = NULL; + gs_free char *t = NULL; + + v = nm_meta_abstract_info_get_property_names ((const NMMetaAbstractInfo *) setting_info, + nm_connection_get_setting_by_name (connection, setting_info->general->setting_name), + NM_META_ACCESSOR_GET_PROPERTY_NAMES_FLAGS_WITH_THIS_LEVEL); + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT, + _("invalid property name \"%s\". \"%s\" requires a property name like [%s]"), + property_name_orig, setting_info->general->setting_name, + (t = g_strjoinv (",", v))); + return FALSE; + } + + } else { + if (nested_name) + goto out_invalid_toplevel_name; + + /* lookup the property name by toplevel alias. */ + } + +out_invalid_toplevel_name: + { + gs_free char *t = NULL; + + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT, + _("invalid property name \"%s\". Valid names are [%s]"), + property_name_orig, (t = g_strjoinv (",", nm_meta_abstract_info_get_property_names (&nm_meta_connection_info, connection, 0)))); + } + return FALSE; +} + + |