--- trunk/src/settings.c 2007/10/08 16:20:26 28 +++ trunk/src/settings.c 2007/10/08 16:20:58 32 @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * - * $Id: settings.c,v 1.7 2006/07/15 10:06:11 debug Exp $ + * $Id: settings.c,v 1.14 2006/09/21 11:53:26 debug Exp $ * * A generic settings object. (This module should be 100% indepedent of GXemul * and hence easily reusable.) It is basically a tree structure of nodes, @@ -34,7 +34,7 @@ * or to a variable in memory. * * Appart from the pointer, the other properties are a definition of the - * type being pointed to (int, int32_t, int64_t, etc), how it should be + * type being pointed to (int, int32_t, int64_t, char*, etc), how it should be * presented (e.g. it may be an int value in memory, but it should be * presented as a boolean "true/false" value), and a flag which tells us * whether the setting is directly writable or not. @@ -43,11 +43,6 @@ * settings_destroy() is called if individual settings have not yet been * deleted. (This is to help making sure that code which uses the settings * subsystem correctly un-initializes stuff.) - * - * - * TODO: - * Remove a setting - * Read/write settings */ #include @@ -62,6 +57,9 @@ struct settings { + struct settings *parent; + char *name_in_parent; + int n_settings; /* @@ -108,7 +106,8 @@ /* * settings_destroy(): * - * Frees all resources occupied by a settings object. + * Frees all resources occupied by a settings object. Also, if this settings + * object has a parent, then remove it from the parent. */ void settings_destroy(struct settings *settings) { @@ -157,11 +156,113 @@ if (settings->ptr != NULL) free(settings->ptr); + if (settings->parent != NULL) { + settings_remove(settings->parent, settings->name_in_parent); + free(settings->name_in_parent); + } + free(settings); } /* + * settings_read(): + * + * Used internally by settings_access() and settings_debugdump(). + */ +static int settings_read(struct settings *settings, int i, uint64_t *valuep) +{ + *valuep = 0; + + switch (settings->storage_type[i]) { + case SETTINGS_TYPE_INT: + *valuep = *((int *) settings->ptr[i]); + break; + case SETTINGS_TYPE_INT8: + *valuep = *((int8_t *) settings->ptr[i]); + break; + case SETTINGS_TYPE_INT16: + *valuep = *((int16_t *) settings->ptr[i]); + break; + case SETTINGS_TYPE_INT32: + *valuep = *((int32_t *) settings->ptr[i]); + break; + case SETTINGS_TYPE_INT64: + *valuep = *((int64_t *) settings->ptr[i]); + break; + case SETTINGS_TYPE_UINT: + *valuep = *((uint *) settings->ptr[i]); + break; + case SETTINGS_TYPE_UINT8: + *valuep = *((uint8_t *) settings->ptr[i]); + break; + case SETTINGS_TYPE_UINT16: + *valuep = *((uint16_t *) settings->ptr[i]); + break; + case SETTINGS_TYPE_UINT32: + *valuep = *((uint32_t *) settings->ptr[i]); + break; + case SETTINGS_TYPE_UINT64: + *valuep = *((uint64_t *) settings->ptr[i]); + break; + case SETTINGS_TYPE_STRING: + /* Note: Strings cannot be read like this. */ + break; + default:printf("settings_read(): FATAL ERROR! Unknown storage type" + ": %i\n", settings->storage_type[i]); + exit(1); + } + + return SETTINGS_OK; +} + + +/* + * settings_write(): + * + * Used internally by settings_access(). + */ +static int settings_write(struct settings *settings, int i, uint64_t *valuep) +{ + if (!settings->writable[i]) + return SETTINGS_READONLY; + + switch (settings->storage_type[i]) { + case SETTINGS_TYPE_INT: + case SETTINGS_TYPE_UINT: + *((int *) settings->ptr[i]) = *valuep; + break; + case SETTINGS_TYPE_INT8: + case SETTINGS_TYPE_UINT8: + *((int8_t *) settings->ptr[i]) = *valuep; + break; + case SETTINGS_TYPE_INT16: + case SETTINGS_TYPE_UINT16: + *((int16_t *) settings->ptr[i]) = *valuep; + break; + case SETTINGS_TYPE_INT32: + case SETTINGS_TYPE_UINT32: + *((int32_t *) settings->ptr[i]) = *valuep; + break; + case SETTINGS_TYPE_INT64: + case SETTINGS_TYPE_UINT64: + *((int64_t *) settings->ptr[i]) = *valuep; + break; + case SETTINGS_TYPE_STRING: + /* Note: Strings cannot be read like this. */ + printf("settings_write(): ERROR! Strings cannot be " + "written like this.\n"); + break; + default:printf("settings_read(): FATAL ERROR! Unknown storage type" + ": %i\n", settings->storage_type[i]); + exit(1); + } + + return SETTINGS_OK; +} + + +/* * settings_debugdump(): * * Dump settings in a settings object to stdout. @@ -173,7 +274,7 @@ size_t name_buflen = strlen(prefix) + 100; char *name = malloc(name_buflen); int i; - uint64_t value; + uint64_t value = 0; for (i=0; in_settings; i++) { snprintf(name, name_buflen, "%s.%s", prefix, settings->name[i]); @@ -186,27 +287,23 @@ /* Normal value: */ printf("%s = ", name); - switch (settings->storage_type[i]) { - case SETTINGS_TYPE_INT: - value = *((int *) settings->ptr[i]); - break; - case SETTINGS_TYPE_INT32: - value = *((int32_t *) settings->ptr[i]); - break; - case SETTINGS_TYPE_INT64: - value = *((int64_t *) settings->ptr[i]); - break; - default:printf("FATAL ERROR! Unknown storage type" - ": %i\n", settings->storage_type[i]); - exit(1); - } + settings_read(settings, i, &value); switch (settings->presentation_format[i]) { case SETTINGS_FORMAT_DECIMAL: printf("%"PRIi64, value); break; - case SETTINGS_FORMAT_HEX: - printf("0x%"PRIx64, value); + case SETTINGS_FORMAT_HEX8: + printf("0x%02"PRIx8, (int8_t) value); + break; + case SETTINGS_FORMAT_HEX16: + printf("0x%04"PRIx16, (int16_t) value); + break; + case SETTINGS_FORMAT_HEX32: + printf("0x%08"PRIx32, (int32_t) value); + break; + case SETTINGS_FORMAT_HEX64: + printf("0x%016"PRIx64, (int64_t) value); break; case SETTINGS_FORMAT_BOOL: printf(value? "true" : "false"); @@ -214,6 +311,9 @@ case SETTINGS_FORMAT_YESNO: printf(value? "yes" : "no"); break; + case SETTINGS_FORMAT_STRING: + printf("\"%s\"", *((char **)settings->ptr[i])); + break; default:printf("FATAL ERROR! Unknown presentation " "format: %i\n", settings->presentation_format[i]); @@ -221,7 +321,7 @@ } if (!settings->writable[i]) - printf(" (Read-only)"); + printf(" (R/O)"); printf("\n"); } @@ -239,6 +339,19 @@ void settings_add(struct settings *settings, const char *name, int writable, int type, int format, void *ptr) { + int i; + + for (i=0; in_settings; i++) { + if (strcmp(settings->name[i], name) == 0) + break; + } + + if (i < settings->n_settings) { + fprintf(stderr, "settings_add(): name '%s' is already" + " in use\n", name); + exit(1); + } + settings->n_settings ++; if ((settings->name = realloc(settings->name, settings->n_settings @@ -258,11 +371,20 @@ goto out_of_mem; settings->name[settings->n_settings - 1] = strdup(name); + if (settings->name[settings->n_settings - 1] == NULL) + goto out_of_mem; settings->writable[settings->n_settings - 1] = writable; settings->storage_type[settings->n_settings - 1] = type; settings->presentation_format[settings->n_settings - 1] = format; settings->ptr[settings->n_settings - 1] = ptr; + if (type == SETTINGS_TYPE_SUBSETTINGS) { + ((struct settings *)ptr)->parent = settings; + ((struct settings *)ptr)->name_in_parent = strdup(name); + if (((struct settings *)ptr)->name_in_parent == NULL) + goto out_of_mem; + } + return; out_of_mem: @@ -271,3 +393,132 @@ } +/* + * settings_remove(): + * + * Remove a setting from a settings object. + */ +void settings_remove(struct settings *settings, const char *name) +{ + int i, m; + + for (i=0; in_settings; i++) { + if (strcmp(settings->name[i], name) == 0) + break; + } + + if (i >= settings->n_settings) { +#ifdef UNSTABLE_DEVEL + fprintf(stderr, "settings_remove(): attempting to remove" + " non-existant setting '%s'\n", name); +#endif + return; + } + + /* Check subsettings specifically: */ + if (settings->storage_type[i] == SETTINGS_TYPE_SUBSETTINGS && + settings->ptr[i] != NULL) { + struct settings *subsettings = settings->ptr[i]; + if (subsettings->n_settings != 0) { + fprintf(stderr, "settings_remove(): attempting to " + "remove non-emtpy setting '%s'\n", name); + fprintf(stderr, "Remaining settings are:\n"); + for (i=0; in_settings; i++) + fprintf(stderr, "\t%s\n", subsettings->name[i]); + exit(1); + } + } + + settings->n_settings --; + free(settings->name[i]); + + m = settings->n_settings - i; + if (m == 0) + return; + + memmove(&settings->name[i], &settings->name[i+1], + m * sizeof(settings->name[0])); + memmove(&settings->writable[i], &settings->writable[i+1], + m * sizeof(settings->writable[0])); + memmove(&settings->storage_type[i], &settings->storage_type[i+1], + m * sizeof(settings->storage_type[0])); + memmove(&settings->presentation_format[i], + &settings->presentation_format[i+1], + m * sizeof(settings->presentation_format[0])); + memmove(&settings->ptr[i], &settings->ptr[i+1], + m * sizeof(settings->ptr[0])); +} + + +/* + * settings_remove_all(): + * + * Remove all (level-1) settings from a settings object. By level-1, I mean + * all settings that do not contain subsettings. + */ +void settings_remove_all(struct settings *settings) +{ + while (settings->n_settings > 0) + settings_remove(settings, settings->name[0]); +} + + +/* + * settings_access(): + * + * Read or write a setting. fullname may be something like "settings.x.y". + * When writing a value, valuebuf should point to a uint64_t containing the + * new value (note: always a uint64_t). When reading a value, valuebuf should + * point to a uint64_t where the value will be stored. + * + * The return value is one of the following: + * + * SETTINGS_OK + * The value was read or written. + * + * SETTINGS_NAME_NOT_FOUND + * The name was not found in the settings object. + * + * SETTINGS_READONLY + * The name was found, but it was marked as read-only, and + * an attempt was made to write to it. + */ +int settings_access(struct settings *settings, const char *fullname, + int writeflag, uint64_t *valuep) +{ + int i; + + /* printf("settings_access(fullname='%s')\n", fullname); */ + + if (strncmp(fullname, GLOBAL_SETTINGS_NAME".", + strlen(GLOBAL_SETTINGS_NAME) + 1) == 0) + fullname += strlen(GLOBAL_SETTINGS_NAME) + 1; + + for (i=0; in_settings; i++) { + size_t settings_name_len = strlen(settings->name[i]); + + if (strncmp(fullname, settings->name[i], + settings_name_len) != 0) + continue; + + /* Found the correct setting? */ + if (fullname[settings_name_len] == '\0') { + if (writeflag) + return settings_write(settings, i, valuep); + else + return settings_read(settings, i, valuep); + } + + /* Found a setting which has sub-settings? */ + if (fullname[settings_name_len] == '.') { + /* Recursive search: */ + return settings_access( + (struct settings *)settings->ptr[i], + fullname + settings_name_len + 1, + writeflag, valuep); + } + } + + return SETTINGS_NAME_NOT_FOUND; +} +