/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU 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 General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "option.h" static struct chain * G_options = NULL; option * option_new(const char *name, option_type type, const void *value) { /* ----------------------------------------------------------------------------- * Create an option * if option_type OPTION_CHAIN is passed, value will not be copied * so it must pointed to a dynamically allocated memory and it must not be freed * just after !! * * @param const char *, name * @param option_type * @param const void *, the value * @return option * * -------------------------------------------------------------------------- */ option *new_option = NULL; char *new_name = NULL; void *new_value = NULL; new_option = (option *)malloc(sizeof(option)); if (new_option == NULL) return NULL; new_name = (char *)strdup(name); if (new_name == NULL) { free(new_option); return NULL; } switch(type) { case OPTION_STRING: new_value = (char *)strdup(value); if (new_value == NULL) { free(new_name); free(new_option); return NULL; } break; case OPTION_INT: new_value = (int *)malloc(sizeof(value)); if (new_value == NULL) { free(new_name); free(new_option); return NULL; } memcpy(new_value, value, sizeof(value)); break; case OPTION_CHAIN: new_value = (struct chain *)value; break; } new_option->name = new_name; new_option->type = type; new_option->value = new_value; return new_option; } void option_destroy(option *option_to_destroy) { /* ----------------------------------------------------------------------------- * Destroy an option * * -------------------------------------------------------------------------- */ struct chain* chain_option = NULL; option *option_tmp = NULL; switch((option_to_destroy)->type) { case OPTION_CHAIN: for (chain_option = (struct chain *)option_to_destroy->value; chain_option != NULL; chain_option = chain_option->next) { option_tmp = (option *)chain_option->value; option_destroy(option_tmp); } free(option_to_destroy->name); drop_all_chain((struct chain *)option_to_destroy->value); free(option_to_destroy); break; case OPTION_INT: case OPTION_STRING: free(option_to_destroy->name); free(option_to_destroy->value); free(option_to_destroy); break; } } option * option_copy(const option *option_to_copy) { /* ----------------------------------------------------------------------------- * Copy an option * * @param option *, the option to copy * @return option * * -------------------------------------------------------------------------- */ return option_new(option_to_copy->name, option_to_copy->type, option_to_copy->value); } void drop_all_option() { /* ----------------------------------------------------------------------------- * Destroy *ALL* option * * -------------------------------------------------------------------------- */ struct chain *chain_option = NULL; option *option_tmp = NULL; for (chain_option = G_options; chain_option != NULL; chain_option = chain_option->next) { option_tmp = chain_option->value; option_destroy(option_tmp); } drop_all_chain(G_options); G_options = NULL; } struct chain * get_root_option() { /* ----------------------------------------------------------------------------- * Get pointer to the first element * * @return struct chain * * -------------------------------------------------------------------------- */ return G_options; } void set_root_option(void *mem) { /* ----------------------------------------------------------------------------- * Set a new pointer to the first element * * @param void * * -------------------------------------------------------------------------- */ G_options = mem; } void *get_option(const char *name, option_type *type) { /* ----------------------------------------------------------------------------- * Get the value from an option by name * * @param const char *, name * @param option_type *, option type retrieved * @return void * * if option_type is OPTION_STRING, value is a char * * if option_type is OPTION_INT, value is an int * * if option_type is OPTION_CHAIN, value is a struct chain * * -------------------------------------------------------------------------- */ struct chain *chain_option = NULL; option *option_tmp = NULL; for (chain_option = G_options; chain_option != NULL; chain_option = chain_option->next) { option_tmp = chain_option->value; if (strcmp(option_tmp->name, name) == 0) { /* We have found the option */ if (type != NULL) *type = option_tmp->type; return option_tmp->value; } } return NULL; } int set_option(const char *name, option_type type, const void *value) { /* ----------------------------------------------------------------------------- * Set the value from an option by name * * @param const char *, name * @param option_type, option type * @param const void *, new value * @return int * -------------------------------------------------------------------------- */ option *option_tmp = NULL; struct chain *chain_option = NULL; if (G_options == NULL) { /* It is the first option */ option_tmp = option_new(name, type, value); if (option_tmp == NULL) return 0; G_options = new_chain(option_tmp, NO_FREE); return 1; } /* Verify if this option exists */ chain_option = find_option_byname(name); if (chain_option == NULL) { /* We add a new option */ option_tmp = option_new(name, type, value); if (option_tmp == NULL) return 0; append_chain(new_chain(option_tmp, NO_FREE), G_options); } else { /* We replace an existing option */ option_tmp = (option *)chain_option->value; option_destroy(option_tmp); option_tmp = option_new(name, type, value); if (option_tmp == NULL) return 0; chain_option->value = option_tmp; } return 1; } int add_option(const char *name, option_type type, const void *value) { /* ----------------------------------------------------------------------------- * Add an option by name * * @param const char *, name * @param option_type, option type * @param const void *, new value * @return int * -------------------------------------------------------------------------- */ option *option_tmp = NULL, *option_chain = NULL; struct chain *chain_option = NULL, *chain_option_chain = NULL; if (G_options == NULL) { /* It is the first option */ option_tmp = option_new(name, type, value); if (option_tmp == NULL) return 0; chain_option = new_chain(option_tmp, NO_FREE); if (chain_option == NULL) return 0; option_chain = option_new(name, OPTION_CHAIN, chain_option); if (option_chain == NULL) return 0; G_options = new_chain(option_chain, NO_FREE); return 1; } /* Verify it this option exists */ chain_option = find_option_byname(name); if (chain_option == NULL) { /* We add a new option */ option_tmp = option_new(name, type, value); if (option_tmp == NULL) return 0; chain_option = new_chain(option_tmp, NO_FREE); if (chain_option == NULL) return 0; option_chain = option_new(name, OPTION_CHAIN, chain_option); if (option_chain == NULL) return 0; append_chain(new_chain(option_chain, NO_FREE), G_options); } else { /* We add a new value to an existing option */ option_tmp = (option *)chain_option->value; switch(option_tmp->type) { case OPTION_CHAIN: /* We add a new option to the chain */ chain_option_chain = (struct chain *)option_tmp->value; option_tmp = option_new(name, type, value); if (option_tmp == NULL) return 0; append_chain(new_chain(option_tmp, NO_FREE), chain_option_chain); break; case OPTION_INT: case OPTION_STRING: /* We have an option with simple values so we add it */ chain_option_chain = new_chain(option_tmp, NO_FREE); if (chain_option_chain == NULL) return 0; /* We create a new option */ option_tmp = option_new(name, type, value); if (option_tmp == NULL) return 0; append_chain(new_chain(option_tmp, NO_FREE), chain_option_chain); option_chain = option_new(name, OPTION_CHAIN, chain_option_chain); if (option_chain == NULL) return 0; chain_option->value = option_chain; break; } } return 1; } struct chain *find_option_byname(const char *name) { /* ----------------------------------------------------------------------------- * Get the chain pointer to an option found by name * * @param const char *, name * @return struct chain * or NULL if option is not found * -------------------------------------------------------------------------- */ struct chain *chain_option = NULL; option *option_tmp = NULL; for (chain_option = G_options; chain_option != NULL; chain_option = chain_option->next) { /* Verify if this option exists */ option_tmp = (option *)chain_option->value; if (strcmp(option_tmp->name, name) == 0) /* An option already exists */ break; } if (chain_option == NULL) return NULL; return chain_option; } void dump_option(int fd, option *option_dump) { /* ----------------------------------------------------------------------------- * Print an option information to a file descriptor * * @param int, the file descriptor to write on * @param option *, the option to dump * -------------------------------------------------------------------------- */ struct chain *chain_option_chain = NULL; option *option_tmp = option_dump; FILE * stream = NULL; stream = fdopen(fd, "w"); if (stream == NULL) return; switch(option_tmp->type) { case OPTION_INT: fprintf(stream, "%s = %d\n", option_tmp->name, *(int *)option_tmp->value); fflush(stream); break; case OPTION_STRING: fprintf(stream, "%s = %s\n", option_tmp->name, (char *)option_tmp->value); fflush(stream); break; case OPTION_CHAIN: fprintf(stream, "%s = ", option_tmp->name); for (chain_option_chain = (struct chain *)option_tmp->value; chain_option_chain != NULL; chain_option_chain = chain_option_chain->next) { option_tmp = (option *)chain_option_chain->value; switch(option_tmp->type) { case OPTION_INT: fprintf(stream, "%d", *(int *)option_tmp->value); break; case OPTION_STRING: fprintf(stream, "%s", (char *)option_tmp->value); break; default: break; } if (chain_option_chain->next != NULL) fprintf(stream, ", "); } fprintf(stream, "\n"); fflush(stream); break; } } void dump_all_option(int fd) { /* ----------------------------------------------------------------------------- * Print *ALL* option informations to a file descriptor * * @param int, the file descriptor to write on * -------------------------------------------------------------------------- */ struct chain *chain_option = NULL; option *option_tmp = NULL; for (chain_option = G_options; chain_option != NULL; chain_option = chain_option->next) { option_tmp = (option *)chain_option->value; dump_option(fd, option_tmp); } }