/
githubmirror
/
libmodulemd
Обзор
Документация
Войти
/
githubmirror
/
libmodulemd
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
modulemd/modulemd-translation-entry.c
667 строк
20 KB
Petr Písař
Initialize automaticly freed variables where the function could return before the first assignment
10 май 2023, 15:50
10 май 2023, 15:50
bfde7f2
Код
Авторство
О чём код?
/* * This file is part of libmodulemd * Copyright (C) 2018 Red Hat, Inc. * * Fedora-License-Identifier: MIT * SPDX-2.0-License-Identifier: MIT * SPDX-3.0-License-Identifier: MIT * * This program is free software. * For more information on the license, see COPYING. * For more information on free software, see <https://www.gnu.org/philosophy/free-sw.en.html>. */ #include <glib.h> #include <yaml.h> #include "modulemd-errors.h" #include "modulemd-translation-entry.h" #include "private/glib-extensions.h" #include "private/modulemd-translation-entry-private.h" #include "private/modulemd-util.h" #include "private/modulemd-yaml.h" #define TE_DEFAULT_STRING "__LOCALE_UNSET__" struct _ModulemdTranslationEntry { GObject parent_instance; gchar *locale; gchar *summary; gchar *description; GHashTable *profile_descriptions; }; G_DEFINE_TYPE (ModulemdTranslationEntry, modulemd_translation_entry, G_TYPE_OBJECT) enum { PROP_0, PROP_LOCALE, PROP_SUMMARY, PROP_DESCRIPTION, N_PROPS }; static GParamSpec *properties[N_PROPS]; ModulemdTranslationEntry * modulemd_translation_entry_new (const gchar *locale) { // clang-format off return g_object_new (MODULEMD_TYPE_TRANSLATION_ENTRY, "locale", locale, NULL); // clang-format on } ModulemdTranslationEntry * modulemd_translation_entry_copy (ModulemdTranslationEntry *self) { g_autoptr (ModulemdTranslationEntry) te = NULL; g_return_val_if_fail (MODULEMD_IS_TRANSLATION_ENTRY (self), NULL); te = modulemd_translation_entry_new ( modulemd_translation_entry_get_locale (self)); modulemd_translation_entry_set_summary ( te, modulemd_translation_entry_get_summary (self)); modulemd_translation_entry_set_description ( te, modulemd_translation_entry_get_description (self)); g_hash_table_unref (te->profile_descriptions); te->profile_descriptions = modulemd_hash_table_deep_str_copy (self->profile_descriptions); return g_object_ref (te); } static void modulemd_translation_entry_finalize (GObject *object) { ModulemdTranslationEntry *self = (ModulemdTranslationEntry *)object; g_clear_pointer (&self->locale, g_free); g_clear_pointer (&self->summary, g_free); g_clear_pointer (&self->description, g_free); g_clear_pointer (&self->profile_descriptions, g_hash_table_unref); G_OBJECT_CLASS (modulemd_translation_entry_parent_class)->finalize (object); } void modulemd_translation_entry_set_summary (ModulemdTranslationEntry *self, const gchar *summary) { g_return_if_fail (MODULEMD_IS_TRANSLATION_ENTRY (self)); g_clear_pointer (&self->summary, g_free); self->summary = g_strdup (summary); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SUMMARY]); } const gchar * modulemd_translation_entry_get_summary (ModulemdTranslationEntry *self) { g_return_val_if_fail (MODULEMD_IS_TRANSLATION_ENTRY (self), NULL); return self->summary; } void modulemd_translation_entry_set_description (ModulemdTranslationEntry *self, const gchar *description) { g_return_if_fail (MODULEMD_IS_TRANSLATION_ENTRY (self)); g_clear_pointer (&self->description, g_free); self->description = g_strdup (description); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DESCRIPTION]); } const gchar * modulemd_translation_entry_get_description (ModulemdTranslationEntry *self) { g_return_val_if_fail (MODULEMD_IS_TRANSLATION_ENTRY (self), NULL); return self->description; } static void modulemd_translation_entry_set_locale (ModulemdTranslationEntry *self, const gchar *locale) { g_return_if_fail (MODULEMD_IS_TRANSLATION_ENTRY (self)); /* It is a coding error if we ever get a NULL name here */ g_return_if_fail (locale); /* It is a coding error if we ever get the default string here */ g_return_if_fail (g_strcmp0 (locale, TE_DEFAULT_STRING)); g_clear_pointer (&self->locale, g_free); self->locale = g_strdup (locale); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LOCALE]); } const gchar * modulemd_translation_entry_get_locale (ModulemdTranslationEntry *self) { g_return_val_if_fail (MODULEMD_IS_TRANSLATION_ENTRY (self), NULL); return self->locale; } GStrv modulemd_translation_entry_get_profiles_as_strv ( ModulemdTranslationEntry *self) { return modulemd_ordered_str_keys_as_strv (self->profile_descriptions); } void modulemd_translation_entry_set_profile_description ( ModulemdTranslationEntry *self, const gchar *profile_name, const gchar *profile_description) { g_hash_table_replace (self->profile_descriptions, g_strdup (profile_name), g_strdup (profile_description)); } const gchar * modulemd_translation_entry_get_profile_description ( ModulemdTranslationEntry *self, const gchar *profile_name) { return (const gchar *)g_hash_table_lookup (self->profile_descriptions, profile_name); } static void modulemd_translation_entry_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { ModulemdTranslationEntry *self = MODULEMD_TRANSLATION_ENTRY (object); switch (prop_id) { case PROP_LOCALE: g_value_set_string (value, modulemd_translation_entry_get_locale (self)); break; case PROP_SUMMARY: g_value_set_string (value, modulemd_translation_entry_get_summary (self)); break; case PROP_DESCRIPTION: g_value_set_string (value, modulemd_translation_entry_get_description (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void modulemd_translation_entry_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ModulemdTranslationEntry *self = MODULEMD_TRANSLATION_ENTRY (object); switch (prop_id) { case PROP_LOCALE: modulemd_translation_entry_set_locale (self, g_value_get_string (value)); break; case PROP_SUMMARY: modulemd_translation_entry_set_summary (self, g_value_get_string (value)); break; case PROP_DESCRIPTION: modulemd_translation_entry_set_description (self, g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void modulemd_translation_entry_class_init (ModulemdTranslationEntryClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = modulemd_translation_entry_finalize; object_class->get_property = modulemd_translation_entry_get_property; object_class->set_property = modulemd_translation_entry_set_property; properties[PROP_LOCALE] = g_param_spec_string ( "locale", "Locale", "The locale for this translation entry. It must correspond to the format " "specified by libc locale names. This field may only be set on object " "construction and is immutable afterwards.", TE_DEFAULT_STRING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY); properties[PROP_SUMMARY] = g_param_spec_string ("summary", "Summary", "The summary of this module stream translated into " "the language specified by locale.", TE_DEFAULT_STRING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); properties[PROP_DESCRIPTION] = g_param_spec_string ("description", "Description", "The description of this module stream translated " "into the language specified by locale.", TE_DEFAULT_STRING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, N_PROPS, properties); } static void modulemd_translation_entry_init (ModulemdTranslationEntry *self) { self->profile_descriptions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); } /* === YAML Functions === */ static GHashTable * modulemd_translation_entry_parse_yaml_profiles (yaml_parser_t *parser, GError **error) { MODULEMD_INIT_TRACE (); MMD_INIT_YAML_EVENT (event); gboolean done = FALSE; gboolean in_map = FALSE; g_autofree gchar *profile_name = NULL; g_autofree gchar *value = NULL; g_autoptr (GHashTable) profiles = NULL; g_autoptr (GError) nested_error = NULL; g_return_val_if_fail (error == NULL || *error == NULL, FALSE); profiles = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); /* Parse the profiles */ while (!done) { YAML_PARSER_PARSE_WITH_EXIT (parser, &event, error); switch (event.type) { case YAML_MAPPING_START_EVENT: in_map = TRUE; break; case YAML_MAPPING_END_EVENT: in_map = FALSE; done = TRUE; break; case YAML_SCALAR_EVENT: if (!in_map) { MMD_YAML_ERROR_EVENT_EXIT ( error, event, "Missing mapping in translation entry profiles"); break; } profile_name = g_strdup ((const gchar *)event.data.scalar.value); value = modulemd_yaml_parse_string (parser, &nested_error); if (!value) { MMD_YAML_ERROR_EVENT_EXIT (error, event, "Error parsing profile value: %s", nested_error->message); } g_hash_table_replace (profiles, g_steal_pointer (&profile_name), g_steal_pointer (&value)); break; default: /* We received a YAML event we shouldn't expect at this level */ MMD_YAML_ERROR_EVENT_EXIT ( error, event, "Unexpected YAML event in translation entry profile"); break; } yaml_event_delete (&event); } /* Work around false-positive in clang static analysis which thinks it's * possible for this function to return NULL and not set error. */ if (G_UNLIKELY (profiles == NULL)) { g_set_error (error, MODULEMD_YAML_ERROR, MMD_YAML_ERROR_EMIT, "Somehow got a NULL hash table here."); } return g_steal_pointer (&profiles); } ModulemdTranslationEntry * modulemd_translation_entry_parse_yaml (yaml_parser_t *parser, const gchar *locale, gboolean strict, GError **error) { MODULEMD_INIT_TRACE (); MMD_INIT_YAML_EVENT (event); gboolean done = FALSE; gboolean in_map = FALSE; g_autofree gchar *value = NULL; GHashTable *profiles = NULL; g_autoptr (ModulemdTranslationEntry) te = NULL; g_autoptr (GError) nested_error = NULL; g_return_val_if_fail (error == NULL || *error == NULL, FALSE); te = modulemd_translation_entry_new (locale); /* Read in any supplementary attributes of the translation entry */ while (!done) { YAML_PARSER_PARSE_WITH_EXIT (parser, &event, error); switch (event.type) { case YAML_MAPPING_START_EVENT: in_map = TRUE; break; case YAML_MAPPING_END_EVENT: in_map = FALSE; done = TRUE; break; case YAML_SCALAR_EVENT: if (!in_map) { MMD_YAML_ERROR_EVENT_EXIT ( error, event, "Missing mapping in translation entry"); break; } if (!g_strcmp0 ((const gchar *)event.data.scalar.value, "summary")) { value = modulemd_yaml_parse_string (parser, &nested_error); if (!value) { MMD_YAML_ERROR_EVENT_EXIT ( error, event, "Failed to parse summary in translation entry: %s", nested_error->message); } modulemd_translation_entry_set_summary (te, value); g_clear_pointer (&value, g_free); } else if (!g_strcmp0 ((const gchar *)event.data.scalar.value, "description")) { value = modulemd_yaml_parse_string (parser, &nested_error); if (!value) { MMD_YAML_ERROR_EVENT_EXIT ( error, event, "Failed to parse description in translation entry: %s", nested_error->message); } modulemd_translation_entry_set_description (te, value); g_clear_pointer (&value, g_free); } else if (!g_strcmp0 ((const gchar *)event.data.scalar.value, "profiles")) { profiles = modulemd_translation_entry_parse_yaml_profiles ( parser, &nested_error); if (profiles == NULL) { MMD_YAML_ERROR_EVENT_EXIT (error, event, "Failed to parse profiles: %s", nested_error->message); } g_hash_table_unref (te->profile_descriptions); te->profile_descriptions = profiles; } else { SKIP_UNKNOWN (parser, NULL, "Unexpected key in translation entry body: %s", (const gchar *)event.data.scalar.value); } break; default: /* We received a YAML event we shouldn't expect at this level */ MMD_YAML_ERROR_EVENT_EXIT ( error, event, "Unexpected YAML event in translation entry"); break; } yaml_event_delete (&event); } return g_steal_pointer (&te); } static gboolean modulemd_translation_entry_emit_yaml_profiles (ModulemdTranslationEntry *self, yaml_emitter_t *emitter, GError **error) { MODULEMD_INIT_TRACE (); int ret; g_autoptr (GError) nested_error = NULL; GHashTableIter iter; gpointer key; gpointer value; MMD_INIT_YAML_EVENT (event); ret = mmd_emitter_scalar ( emitter, "profiles", YAML_PLAIN_SCALAR_STYLE, &nested_error); if (!ret) { g_propagate_prefixed_error (error, g_steal_pointer (&nested_error), "Failed to emit profiles key: "); return FALSE; } ret = mmd_emitter_start_mapping ( emitter, YAML_BLOCK_MAPPING_STYLE, &nested_error); if (!ret) { g_propagate_prefixed_error (error, g_steal_pointer (&nested_error), "Failed to emit profiles start: "); return FALSE; } g_hash_table_iter_init (&iter, self->profile_descriptions); while (g_hash_table_iter_next (&iter, &key, &value)) { ret = mmd_emitter_scalar_string (emitter, (const gchar *)key, &nested_error); if (!ret) { g_propagate_prefixed_error (error, g_steal_pointer (&nested_error), "Failed to emit profile key: "); return FALSE; } ret = mmd_emitter_scalar_string ( emitter, (const gchar *)value, &nested_error); if (!ret) { g_propagate_prefixed_error (error, g_steal_pointer (&nested_error), "Failed to emit profile value: "); return FALSE; } } ret = mmd_emitter_end_mapping (emitter, &nested_error); if (!ret) { g_propagate_prefixed_error (error, g_steal_pointer (&nested_error), "Failed to emit profiles end: "); return FALSE; } return TRUE; } gboolean modulemd_translation_entry_emit_yaml (ModulemdTranslationEntry *self, yaml_emitter_t *emitter, GError **error) { MODULEMD_INIT_TRACE (); int ret; g_autoptr (GError) nested_error = NULL; MMD_INIT_YAML_EVENT (event); /* Emit the Translation Entry Locale */ ret = mmd_emitter_scalar_string ( emitter, modulemd_translation_entry_get_locale (self), &nested_error); if (!ret) { g_propagate_prefixed_error (error, g_steal_pointer (&nested_error), "Failed to emit translation entry locale: "); return FALSE; } /* Start the mapping for additional attributes of this translation entry */ ret = mmd_emitter_start_mapping ( emitter, YAML_BLOCK_MAPPING_STYLE, &nested_error); if (!ret) { g_propagate_prefixed_error ( error, g_steal_pointer (&nested_error), "Failed to start translation entry mapping: "); return FALSE; } /* Add translation entry attributes if available */ if (modulemd_translation_entry_get_summary (self) != NULL) { ret = mmd_emitter_scalar ( emitter, "summary", YAML_PLAIN_SCALAR_STYLE, &nested_error); if (!ret) { g_propagate_prefixed_error (error, g_steal_pointer (&nested_error), "Failed to emit summary key: "); return FALSE; } ret = mmd_emitter_scalar_string ( emitter, modulemd_translation_entry_get_summary (self), &nested_error); if (!ret) { g_propagate_prefixed_error ( error, g_steal_pointer (&nested_error), "Failed to emit translation entry summary: "); return FALSE; } } if (modulemd_translation_entry_get_description (self) != NULL) { ret = mmd_emitter_scalar ( emitter, "description", YAML_PLAIN_SCALAR_STYLE, &nested_error); if (!ret) { g_propagate_prefixed_error (error, g_steal_pointer (&nested_error), "Failed to emit description key: "); return FALSE; } ret = mmd_emitter_scalar_string ( emitter, modulemd_translation_entry_get_description (self), &nested_error); if (!ret) { g_propagate_prefixed_error ( error, g_steal_pointer (&nested_error), "Failed to emit translation entry description: "); return FALSE; } } if (g_hash_table_size (self->profile_descriptions) != 0) { ret = modulemd_translation_entry_emit_yaml_profiles ( self, emitter, &nested_error); if (!ret) { g_propagate_prefixed_error (error, g_steal_pointer (&nested_error), "Failed to emit profiles: "); return FALSE; } } /* End the mapping */ ret = mmd_emitter_end_mapping (emitter, &nested_error); if (!ret) { g_propagate_prefixed_error (error, g_steal_pointer (&nested_error), "Failed to end translation entry mapping: "); return FALSE; } return TRUE; }