/*
* 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);
}
}
syntax highlighted by Code2HTML, v. 0.9.1