/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- eel-enumeration.c: Enumeration data structure. Copyright (C) 2000 Eazel, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. Author: Ramiro Estrugo */ #include #include "eel-enumeration.h" #include "eel-debug.h" #include "eel-glib-extensions.h" #include "eel-lib-self-check-functions.h" #include "eel-string.h" #include "eel-i18n.h" static gboolean suppress_duplicate_registration_warning; struct EelEnumeration { char *id; GPtrArray *entries; /* array of EelEnumerationEntry */ }; static EelEnumeration * eel_enumeration_new (const char *id) { EelEnumeration *enumeration; g_assert (id != NULL); g_assert (id[0] != '\0'); enumeration = g_new0 (EelEnumeration, 1); enumeration->id = g_strdup (id); enumeration->entries = g_ptr_array_new (); return enumeration; } static void free_entry (EelEnumerationEntry *entry) { g_free (entry->name); g_free (entry->description); g_free (entry); } static void eel_enumeration_free (EelEnumeration *enumeration) { if (enumeration == NULL) { return; } g_free (enumeration->id); g_ptr_array_foreach (enumeration->entries, (GFunc) free_entry, NULL); g_ptr_array_free (enumeration->entries, TRUE); g_free (enumeration); } char * eel_enumeration_get_id (const EelEnumeration *enumeration) { g_return_val_if_fail (enumeration != NULL, NULL); return g_strdup (enumeration->id); } guint eel_enumeration_get_length (const EelEnumeration *enumeration) { g_return_val_if_fail (enumeration != NULL, 0); return enumeration->entries->len; } const EelEnumerationEntry * eel_enumeration_get_nth_entry (const EelEnumeration *enumeration, guint n) { g_return_val_if_fail (enumeration != NULL, NULL); g_return_val_if_fail (n < enumeration->entries->len, NULL); return (EelEnumerationEntry *) g_ptr_array_index (enumeration->entries, n); } int eel_enumeration_get_name_position (const EelEnumeration *enumeration, const char *name) { int i; g_return_val_if_fail (enumeration != NULL, -1); g_return_val_if_fail (name != NULL, -1); for (i = 0; i < enumeration->entries->len; ++i) { EelEnumerationEntry *entry = enumeration->entries->pdata[i]; if (strcmp (name, entry->name) == 0) { return i; } } return -1; } gboolean eel_enumeration_contains_name (const EelEnumeration *enumeration, const char *name) { g_return_val_if_fail (enumeration != NULL, FALSE); g_return_val_if_fail (name != NULL, FALSE); return eel_enumeration_get_name_position (enumeration, name) != -1; } guint eel_enumeration_get_value_for_name (const EelEnumeration *enumeration, const char *name) { int i; g_return_val_if_fail (enumeration != NULL, 0); g_return_val_if_fail (name != NULL, 0); for (i = 0; i < enumeration->entries->len; ++i) { EelEnumerationEntry *entry = enumeration->entries->pdata[i]; if (strcmp (name, entry->name) == 0) { return entry->value; } } g_warning ("No name '%s' in enumeration '%s'", name, enumeration->id); return 0; } const char * eel_enumeration_get_name_for_value (const EelEnumeration *enumeration, int value) { int i; g_return_val_if_fail (enumeration != NULL, 0); for (i = 0; i < enumeration->entries->len; ++i) { EelEnumerationEntry *entry = enumeration->entries->pdata[i]; if (value == entry->value) { return entry->name; } } g_warning ("No value '%d' in enumeration '%s'", value, enumeration->id); return NULL; } char ** eel_enumeration_get_names (const EelEnumeration *enumeration) { GPtrArray *names; int i; g_return_val_if_fail (enumeration != NULL, NULL); if (enumeration->entries->len == 0) { return NULL; } names = g_ptr_array_sized_new (enumeration->entries->len + 1); for (i = 0; i < enumeration->entries->len; ++i) { EelEnumerationEntry *entry = enumeration->entries->pdata[i]; g_ptr_array_add (names, g_strdup (entry->name)); } g_ptr_array_add (names, NULL); return (char **) g_ptr_array_free (names, FALSE); } static EelEnumeration * eel_enumeration_new_from_tokens (const char *id, const char *names, const char *descriptions, const char *values, const char *delimiter) { EelEnumeration *enumeration; char **namev; char **descriptionv; char **valuev; int length; guint i; g_return_val_if_fail (id != NULL, NULL); g_return_val_if_fail (id[0] != '\0', NULL); g_return_val_if_fail (names != NULL, NULL); g_return_val_if_fail (names[0] != '\0', NULL); g_return_val_if_fail (values != NULL, NULL); g_return_val_if_fail (values[0] != '\0', NULL); g_return_val_if_fail (delimiter != NULL, NULL); g_return_val_if_fail (delimiter[0] != '\0', NULL); enumeration = eel_enumeration_new (id); namev = g_strsplit (names, delimiter, -1); valuev = g_strsplit (values, delimiter, -1); length = g_strv_length (namev); if (g_strv_length (valuev) != length) { g_warning ("names and values have different lengths."); g_strfreev (namev); g_strfreev (valuev); return NULL; } descriptionv = descriptions != NULL ? g_strsplit (descriptions, delimiter, -1) : NULL; if (descriptionv != NULL) { if (g_strv_length (descriptionv) != length) { g_warning ("names and descriptions have different lengths."); g_strfreev (namev); g_strfreev (descriptionv); g_strfreev (valuev); return NULL; } } for (i = 0; i < length; i++) { EelEnumerationEntry *entry; int value; if (!eel_str_to_int (valuev[i], &value)) { g_warning ("Could not convert value '%d' to an integer. Using 0.", i); value = 0; } entry = g_new0 (EelEnumerationEntry, 1); entry->name = namev[i]; entry->description = descriptionv ? descriptionv[i] : NULL; entry->value = value; g_ptr_array_add (enumeration->entries, entry); } return enumeration; } static EelEnumerationEntry * dup_entry (const EelEnumerationEntry *entry) { EelEnumerationEntry *res; res = g_new0 (EelEnumerationEntry, 1); res->name = g_strdup (entry->name); res->description = g_strdup (entry->description); res->value = entry->value; return res; } static EelEnumeration * eel_enumeration_new_from_entries (const char *id, const EelEnumerationEntry entries[], guint n_entries) { EelEnumeration *enumeration; guint i; g_assert (id != NULL); g_assert (id[0] != '\0'); g_assert (entries != NULL); enumeration = eel_enumeration_new (id); for (i = 0; i < n_entries; i++) { g_ptr_array_add (enumeration->entries, dup_entry (&entries[i])); } return enumeration; } static GHashTable *enumeration_table = NULL; static void enumeration_table_free (void) { if (enumeration_table != NULL) { g_hash_table_destroy (enumeration_table); enumeration_table = NULL; } } static GHashTable * enumeration_table_get (void) { if (enumeration_table != NULL) { return enumeration_table; } enumeration_table = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) eel_enumeration_free); eel_debug_call_at_shutdown (enumeration_table_free); return enumeration_table; } const EelEnumeration * eel_enumeration_lookup (const char *id) { GHashTable *table; g_return_val_if_fail (id != NULL, NULL); g_return_val_if_fail (id[0] != '\0', NULL); table = enumeration_table_get (); g_return_val_if_fail (table != NULL, NULL); return g_hash_table_lookup (table, id); } void eel_enumeration_register (const char *id, const EelEnumerationEntry entries[], guint n_entries) { GHashTable *table; EelEnumeration *enumeration; g_return_if_fail (id != NULL); g_return_if_fail (id[0] != '\0'); g_return_if_fail (entries != NULL); table = enumeration_table_get (); g_return_if_fail (table != NULL); if (eel_enumeration_lookup (id) != NULL) { if (!suppress_duplicate_registration_warning) { g_warning ("Trying to register duplicate enumeration '%s'.", id); } return; } enumeration = eel_enumeration_new_from_entries (id, entries, n_entries); g_hash_table_insert (table, g_strdup (id), enumeration); } #if !defined (EEL_OMIT_SELF_CHECK) #define CHECK_ENUMERATION_ENTRY(enumeration, i, name, description, value) \ EEL_CHECK_INTEGER_RESULT (eel_enumeration_get_name_position (enumeration, name), i); \ EEL_CHECK_INTEGER_RESULT (eel_enumeration_get_value_for_name (enumeration, name), value); \ EEL_CHECK_STRING_RESULT (g_strdup (eel_enumeration_get_name_for_value (enumeration, value)), name); static EelEnumerationEntry speed_tradeoff_enum_entries[] = { { "always", "Always", 10 }, { "local_only", "Local Files Only", 20 }, { "never", "Never", 30 } }; static EelEnumerationEntry standard_zoom_levels_enum_entries[] = { { "smallest", "25%", 25 }, { "smaller", "50%", 50 }, { "small", "75%", 75 }, { "standard", "100%", 100 }, { "large", "150%", 150 }, { "larger", "200%", 200 }, { "largest", "400%", 400 } }; static EelEnumerationEntry file_size_enum_entries[] = { { "102400", "100 K", 102400 }, { "512000", "500 K", 512000 }, { "1048576", "1 MB", 1048576 }, { "3145728", "3 MB", 3145728 }, { "5242880", "5 MB", 5242880 }, { "10485760", "10 MB", 10485760 }, { "104857600", "100 MB", 104857600 } }; #define CHECK_REGISTERED_ENUMERATION(enumname) \ G_STMT_START { \ const EelEnumeration *e; \ int i; \ e = eel_enumeration_lookup (#enumname); \ g_return_if_fail (e != NULL); \ for (i = 0; i < G_N_ELEMENTS (enumname##_enum_entries); i++) { \ CHECK_ENUMERATION_ENTRY (e, \ i, \ enumname##_enum_entries[i].name, \ enumname##_enum_entries[i].description, \ enumname##_enum_entries[i].value); \ } \ EEL_CHECK_INTEGER_RESULT (eel_enumeration_get_length (e), i); \ } G_STMT_END void eel_self_check_enumeration (void) { EelEnumeration *e; char **names; /***/ e = eel_enumeration_new_from_tokens ("id", "single", NULL, "1", ","); CHECK_ENUMERATION_ENTRY (e, 0, "single", "", 1); EEL_CHECK_STRING_RESULT (eel_enumeration_get_id (e), "id"); EEL_CHECK_INTEGER_RESULT (eel_enumeration_get_length (e), 1); eel_enumeration_free (e); /***/ e = eel_enumeration_new_from_tokens ("id", "apple,orange,banana", NULL, "1,2,3", ","); CHECK_ENUMERATION_ENTRY (e, 0, "apple", "", 1); CHECK_ENUMERATION_ENTRY (e, 1, "orange", "", 2); CHECK_ENUMERATION_ENTRY (e, 2, "banana", "", 3); EEL_CHECK_STRING_RESULT (eel_enumeration_get_id (e), "id"); EEL_CHECK_INTEGER_RESULT (eel_enumeration_get_length (e), 3); eel_enumeration_free (e); /***/ e = eel_enumeration_new_from_tokens ("id", "foo", NULL, "666", ","); CHECK_ENUMERATION_ENTRY (e, 0, "foo", "", 666); EEL_CHECK_STRING_RESULT (eel_enumeration_get_id (e), "id"); EEL_CHECK_INTEGER_RESULT (eel_enumeration_get_length (e), 1); eel_enumeration_free (e); /***/ e = eel_enumeration_new_from_tokens ("id", "one,two,---,three", "One,Two,---,Three", "1,2,0,3", ","); CHECK_ENUMERATION_ENTRY (e, 0, "one", "One", 1); CHECK_ENUMERATION_ENTRY (e, 1, "two", "Two", 2); CHECK_ENUMERATION_ENTRY (e, 2, "---", "---", 0); CHECK_ENUMERATION_ENTRY (e, 3, "three", "Three", 3); EEL_CHECK_INTEGER_RESULT (eel_enumeration_get_length (e), 4); eel_enumeration_free (e); /***/ e = eel_enumeration_new_from_tokens ("id", "red,green,blue", "Red Desc,Green Desc,Blue Desc", "10,20,30", ","); CHECK_ENUMERATION_ENTRY (e, 0, "red", "Red Desc", 10); CHECK_ENUMERATION_ENTRY (e, 1, "green", "Green Desc", 20); CHECK_ENUMERATION_ENTRY (e, 2, "blue", "Blue Desc", 30); EEL_CHECK_STRING_RESULT (eel_enumeration_get_id (e), "id"); EEL_CHECK_INTEGER_RESULT (eel_enumeration_get_length (e), 3); EEL_CHECK_BOOLEAN_RESULT (eel_enumeration_contains_name (e, "red"), TRUE); EEL_CHECK_BOOLEAN_RESULT (eel_enumeration_contains_name (e, "green"), TRUE); EEL_CHECK_BOOLEAN_RESULT (eel_enumeration_contains_name (e, "blue"), TRUE); EEL_CHECK_BOOLEAN_RESULT (eel_enumeration_contains_name (e, "pink"), FALSE); eel_enumeration_free (e); /***/ e = eel_enumeration_new_from_tokens ("id", "red,foo:green,bar:blue,baz", "Red,Desc:Green,Desc:Blue,Desc", "10:20:30", ":"); CHECK_ENUMERATION_ENTRY (e, 0, "red,foo", "Red,Desc", 10); CHECK_ENUMERATION_ENTRY (e, 1, "green,bar", "Green,Desc", 20); CHECK_ENUMERATION_ENTRY (e, 2, "blue,baz", "Blue,Desc", 30); EEL_CHECK_STRING_RESULT (eel_enumeration_get_id (e), "id"); EEL_CHECK_INTEGER_RESULT (eel_enumeration_get_length (e), 3); EEL_CHECK_BOOLEAN_RESULT (eel_enumeration_contains_name (e, "black"), FALSE); names = eel_enumeration_get_names (e); EEL_CHECK_INTEGER_RESULT (strcmp(names[2], "blue,baz"), 0); g_strfreev (names); eel_enumeration_free (e); /***/ suppress_duplicate_registration_warning = TRUE; eel_enumeration_register ("speed_tradeoff", speed_tradeoff_enum_entries, G_N_ELEMENTS (speed_tradeoff_enum_entries)); eel_enumeration_register ("standard_zoom_levels", standard_zoom_levels_enum_entries, G_N_ELEMENTS (standard_zoom_levels_enum_entries)); eel_enumeration_register ("file_size", file_size_enum_entries, G_N_ELEMENTS (file_size_enum_entries)); suppress_duplicate_registration_warning = FALSE; CHECK_REGISTERED_ENUMERATION(speed_tradeoff); CHECK_REGISTERED_ENUMERATION(standard_zoom_levels); CHECK_REGISTERED_ENUMERATION(file_size); } #endif /* !EEL_OMIT_SELF_CHECK */