File:  [ELWIX - Embedded LightWeight unIX -] / gpl / axl / knife / exarg.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Fri Feb 17 12:50:02 2012 UTC (12 years, 4 months ago) by misho
Branches: axl, MAIN
CVS tags: HEAD, AXL0_6_7
version 0.6.7

/** 
 *  LibExploreArguments: a library to parse command line options
 *  Copyright (C) 2005 Advanced Software Production Line, S.L.
 * 
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public License
 *  as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser 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
 *  
 *  You may find a copy of the license under this software is released
 *  at COPYING file. This is LGPL software: you are wellcome to
 *  develop propietary applications using this library withtout any
 *  royalty or fee but returning back any change, improvement or
 *  addition in the form of source code, project image, documentation
 *  patches, etc. 
 *
 *  Contact us at:
 *          
 *      Postal address:
 *         Advanced Software Production Line, S.L.
 *         C/ Dr. Michavila NÂș 14
 *         Coslada 28820 Madrid
 *         Spain
 *
 *      Email address:
 *         info@aspl.es - http://fact.aspl.es
 *
 */
#include <exarg.h>

#if defined(__GNUC__)
#  ifndef _GNU_SOURCE
#  define _GNU_SOURCE
#  endif
#endif

/* local includes */
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>

#define LOG_DOMAIN "exarg"

typedef struct _ExArgNodeOption ExArgNodeOption;

/** 
 * @internal Definition for the void *.
 */
typedef void * epointer;

/** 
 * @brief First argument option supported (this is the head of the
 * list of arguments supported).
 */
ExArgNodeOption * argument_options          = NULL;
ExArgument      * params                    = NULL;
const char      * exarg_exec_name           = NULL;
char            * __exarg_usage_header      = NULL;
char            * __exarg_help_header       = NULL;
char            * __exarg_post_usage_header = NULL;
char            * __exarg_post_help_header  = NULL;
int               __exarg_disable_free_args = 0;

typedef enum { 
	/** 
	 * @internal Parse mode not defined.
	 */
	PARSE_MODE_NOT_DEF,
	/** 
	 * @internal Parse mode unix defined.
	 */
	PARSE_MODE_UNIX,
	/** 
	 * @internal Parse module windows defined.
	 */
	PARSE_MODE_WINDOWS
} ExArgParseMode;

/** 
 * @internal This allows to know the parse mode used by exarg. Parse
 * mode allows to differenciate arguments that are file path under
 * unix by options under windows. This option is automatic, being the
 * first option parse to configure the parse mode. This means that the
 * user can't mix options provided using the windows and unix mode at
 * the same time.
 */
ExArgParseMode   parse_mode = PARSE_MODE_NOT_DEF;

/** 
 * @internal Function used by the exarg library to drop a message.
 * 
 * @param format The message to print using a printf format.
 */
void exarg_msg (char * format, ...)
{
	va_list args;

	/* print the message */
	va_start (args, format);
	vprintf (format, args);
	va_end (args);

	/* flush */
	fflush (stdout);

	/* exit from the library */
	exit (-1);

	return;
}

/** 
 * @brief Allows to check current parse mode, return ok if the parse
 * mode isn't defined or the current parse mode is the one provided.
 * 
 * @param mode The parse mode to check.
 * 
 * @return 1 if the parse mode is ok or 0 if current parse mode is
 * incompatible.
 */
#define CHECK_PARSE_MODE(mode) ((parse_mode == PARSE_MODE_NOT_DEF) || (parse_mode == mode))

/** 
 * @brief Allows to update current parse mode.
 * 
 * @param mode The parse mode to configure.
 * 
 */
#define UPDATE_PARSE_MODE(mode)\
if (parse_mode == PARSE_MODE_NOT_DEF)\
   parse_mode = mode;

/**
 * \mainpage LibExArg (Explore Arguments Library)  Manual
 * \section Introduction
 *
 *  LibExArg library is a small, easy to use with a consistent API
 *  which allows you to parse command line argument for your program.
 *
 *  It doesn't require any external dependency for its function, it
 *  really portable and at this point is running on <b>GNU/Linux</b>
 *  platforms and <b>Microsoft Windows</b> platforms.
 *
 *  For details on how to starting to use LibExarg, you can find the
 *  \ref exarg "module documentation for LibExArg here". You can find
 *  \ref exarg_example "here an example about using LibExArg".
 *
 * \section licence Library License
 *
 *  The library is released under the terms of the GNU LGPL (The GNU
 *  Lesser General Public License) licence. You can get a copy of the
 *  license http://www.gnu.org/licenses/licenses.html#LGPL.
 *
 *  This license allows you to write applications using LibExArg which
 *  are using some GPL compatible license or commercial applications.
 *
 */

/**
 * \page exarg_example A simple example on using LibExarg
 *
 * \section Introduction
 *
 *  You may find interesting the following example which makes use of
 *  LibExArg. This example install 3 arguments to be accepted as valid
 *  command line options and the write down to the terminal the result
 *  of those command used by the user.
 * 
 *  Once the arguments are installed, the user can execute 
 *
 *
 *  \include "test-exarg.c"
 * 
 */

/** \defgroup exarg ExArg module: functions to parse command line argument in your program
 *
 */

/** 
 * @brief Argument dependency (a list of nodes that each argument has
 * to define for its dependencies and its mutual exclusions).
 */
typedef struct _ExArgDependency ExArgDependency;

struct _ExArgDependency {
	ExArgNodeOption * node;
	ExArgDependency  * next;
};


/**
 * \addtogroup exarg
 * @{ 
 */

struct _ExArgNodeOption {
	/** 
	 * @brief Holds the argument name (long value recognized by
	 * --long-option and /long-option).
	 */
	const char      * arg_name;
	/** 
	 * @brief Holds the optional short argument option.
	 */
	const char      * arg_short_name;
	/** 
	 * @brief Argument type.
	 */
	ExArgType         type;
	/** 
	 * @brief Argument description.
	 */
	const char      * description;
	/** 
	 * @brief If the argument is \ref EXARG_STRING, this holds the
	 * string value associated if defined.
	 */
	char            * string_value;
	/** 
	 * @brief If the argument is \ref EXARG_INT, this holds the
	 * int value associated if defined.
	 */
	int               int_value;
	/** 
	 * @brief Boolean value that allows to know if the argument
	 * option was defined
	 */
	int               is_defined;

	/** 
	 * @brief Allows to configure if the provided argument is
	 * optional.
	 */
	int               is_optional;

	/** 
	 * @brief Pointer to the next argument option stored.
	 */
	ExArgNodeOption * next;

	/* a reference to the first dependecy argument */
	ExArgDependency * depends;

	ExArgDependency * excludes;
};

struct _ExArgument {
	/** 
	 * @brief The string value that is encapsulated by the
	 * argument.
	 */
	char       * string;

	/** 
	 * @brief A reference to the next argument in the list.
	 */
	ExArgument * next;
};


/** 
 * @internal Definition to allocate memory.
 * 
 * @param type The type to allocate
 * @param count The amount of memory to allocate.
 * 
 * @return Returns a newly allocated memory.
 */
#define exarg_new(type, count) (type *) calloc (count, sizeof (type))

/** 
 * @internal Definition to dealloc an object.
 * 
 * @param ref The reference to dealloc.
 */
void exarg_free (epointer ref)
{
	if (ref == NULL)
		return;
	free (ref);
	
	return;
}

/** 
 * @internal Allows to get the basename for the file path provided.
 * 
 * @param file_path The file path that is requested to return the
 * basename value.
 * 
 * @return A reference to the basename (the return must not be
 * dealloc).
 */
const char * exarg_basename (char * file_path) 
{
	int iterator = strlen (file_path);

	while ((iterator != 0) && 
	       (file_path [iterator - 1]  != '/') && 
	       (file_path [iterator - 1]  != '\\')) {
		/* decrease iterator */
		iterator--;
	}

	/* return the base name */
	return file_path + iterator;
}

/** 
 * @internal Allows to split the provided string using the provided
 * separators.
 * 
 * @param chunk The chunk to split.
 * @param separator_num The number of separators.
 * 
 * @return A newly allocated set of strings.
 */
char     ** exarg_split           (const char * chunk, int separator_num, ...)
{
	va_list      args;
	char      ** separators;
	char      ** result;
	int          iterator;
	int          index;
	int          previous_index;
	int          count      = 0;
	int          length     = 0;

	/* check received values */
	if (chunk == NULL)
		return NULL;
	if (separator_num < 1)
		return NULL;

	separators = exarg_new (char *, separator_num + 1);
	iterator   = 0;
	va_start (args, separator_num);

	/* get all separators to be used */
	while (iterator < separator_num) {
		separators[iterator] = va_arg (args, char *);
		iterator++;
	}
	
	va_end (args);

	/* now, count the number of strings that we will get by
	 * separating the string into several pieces */
	index    = 0;
	while (*(chunk + index) != 0) {

		/* reset the iterator */
		iterator = 0;
		while (iterator < separator_num) { 

			/* compare the current index with the current
			 * separator */
			length = strlen (separators[iterator]);
			if (! memcmp (chunk + index, separators[iterator], length)) {

				/* update items found */
				count++;

				/* update index to skip the item found */
				index += length - 1; /* make the last index to be captured the the -1 */

				/* break the loop */
				break;
			}
			iterator++;
		}

		/* update the index to the next item */
		index++;
	}
	
	/* create the result that will hold items separated */
	result = exarg_new (char *, count + 2);

	/* now copy items found */
	count          = 0;
	index          = 0;

	/* remember previous_index */
	previous_index = index;
	while (*(chunk + index) != 0) {

		/* reset the iterator */
		iterator = 0;
		while (iterator < separator_num) { 

			/* compare the current index with the current
			 * separator */
			length = strlen (separators[iterator]);
			if (! memcmp (chunk + index, separators[iterator], length)) {

				/* copy the chunk found */
				result[count] = exarg_new (char, index - previous_index + 1);
				memcpy (result[count], chunk + previous_index, index - previous_index);

				/* update items found */
				count++;

				/* update index to skip the item found */
				if (*(chunk + index + length) == 0) {
					/* in the case no more elements to read will be found */
					/* put an empty space at the end */
					result [count]    = exarg_new (char, 1);
					
					exarg_free (separators);
					return result;
				}

				/* remember previous_index */
				index += length; 
				previous_index = index;
				index--; /* make the last index to be captured the the -1 */
				break;
			}
			iterator++;
		}

		/* update the index to the next item */
		index++;
	}

	/* check for a last chunk */
	if (index != previous_index) {
		/* copy the chunk found */
		result[count] = exarg_new (char, index - previous_index + 1);
		memcpy (result[count], chunk + previous_index, index - previous_index);
	}

	
	/* release memory */
	exarg_free (separators);
	
	return result;
}

/** 
 * @internal Allows to calculate the amount of memory required to
 * store the string that will representing the construction provided
 * by the printf-like format received and its arguments.
 * 
 * @param format The printf-like format to be printed.
 *
 * @param args The set of arguments that the printf applies to.
 *
 * <i><b>NOTE:</b> not all printf specification is supported. Generally, the
 * following is supported: %s, %d, %f, %g, %ld, %lg and all
 * combinations that provides precision, number of items inside the
 * integer part, etc: %6.2f, %+2d, etc. An especial case not supported
 * is %lld, %llu and %llg.</i>
 *
 * @return Return the number of bytes that must be allocated to hold
 * the string (including the string terminator \0). If the format is
 * not correct or it is not properly formated according to the value
 * found at the argument set, the function will return -1.
 */
int exarg_vprintf_len (const char * format, va_list args)
{
	/** IMPLEMENTATION NOTE: in the case this code is update,
	 * update axl_stream_vprintf_len **/

# if defined (OS_WIN32) && ! defined (__GNUC__)
#   if HAVE_VSCPRINTF
	if (format == NULL)
		return 0;
	return _vscprintf (format, args) + 1;
#   else
	char buffer[8192];
	if (format == NULL)
		return 0;
	return _vsnprintf (buffer, 8191, format, args) + 1;
#   endif
#else
	/* gnu gcc case */
	if (format == NULL)
		return 0;
	return vsnprintf (NULL, 0, format, args) + 1;

#endif
}



/** 
 * @internal Allows to produce an string representing the message hold by
 * chunk with the parameters provided.
 * 
 * @param chunk The message chunk to print.
 * @param args The arguments for the chunk.
 * 
 * @return A newly allocated string.
 */
char  * exarg_strdup_printfv    (char * chunk, va_list args)
{
	/** IMPLEMENTATION NOTE: place update axl_stream_strdup_printfv
	 * code in the case this code is updated **/

#ifndef HAVE_VASPRINTF
	int       size;
#endif
	char    * result   = NULL;

	if (chunk == NULL)
		return NULL;

#ifdef HAVE_VASPRINTF
	/* do the operation using the GNU extension */
	if (vasprintf (&result, chunk, args) == -1)
		return NULL;
#else
	/* get the amount of memory to be allocated */
	size = exarg_vprintf_len (chunk, args);

	/* check result */
	if (size == -1) {
		printf ("error: unable to calculate the amount of memory for the strdup_printf operation");
		return NULL;
	} /* end if */

	/* allocate memory */
	result   = exarg_new (char, size + 2);
	
	/* copy current size */
#  if defined(OS_WIN32) && ! defined (__GNUC__)
	_vsnprintf_s (result, size + 1, size, chunk, args);
#  else
	vsnprintf (result, size + 1, chunk, args);
#  endif
#endif
	/* return the result */
	return result;
}

/** 
 * @internal Implementation that allows to produce dinamically
 * allocated strings using printf-like format.
 * 
 * @param chunk The chunk representing the format.
 * 
 * @return An dynamically allocated string.
 */
char      * exarg_strdup_printf   (char * chunk, ...)
{
	char    * result   = NULL;
	va_list   args;

	/* return a null value if null chunk is received */
	if (chunk == NULL)
		return NULL;

	/* open std args */
	va_start (args, chunk);

	/* get the string */
	result = exarg_strdup_printfv (chunk, args);
	
	/* close std args */
	va_end (args);
	
	return result;
}

/** 
 * @internal Allows to copy the given chunk, supposing that is a
 * properly format C string that ends with a '\\0' value.
 *
 * This function allows to perform a copy for the given string. If a
 * copy limited by a size is required, use \ref axl_stream_strdup_n.
 * 
 * @param chunk The chunk to copy
 * 
 * @return A newly allocated string or NULL if fails.
 */
char      * exarg_strdup          (char * chunk)
{
	char * result;
	int    length;

	/* do not copy if null reference is received */
	if (chunk == NULL)
		return NULL;

	length = strlen (chunk);
	result = exarg_new (char, length + 1);
	
	memcpy (result, chunk, length);

	return result;
}

/** 
 * @internal Internal function that allows to dealloc the provided array of chunks.
 * 
 * @param chunks An array containing pointers to chunks.
 */
void        exarg_freev           (char ** chunks)
{
	int iterator = 0;

	/* return if the received reference is null */
	if (chunks == NULL)
		return;
	 
	/* release memory used by all elements inside the chunk */
	while (chunks[iterator] != 0) {
		exarg_free (chunks[iterator]);
		iterator++;
	}
	
	/* now release the chunk inside */
	exarg_free (chunks);
	
	/* nothing more to do */
	return;
}


/** 
 * @internal Adds the argument to the current argument list.
 * 
 * @param argument The argument to add.
 */
void __exarg_add_argument (char * argument)
{
	ExArgument * arg;
	ExArgument * arg2;

	/* creates the node */
	arg         = exarg_new (ExArgument, 1);
	arg->string = argument;

	if (params == NULL) {
		/* basic case, only one argument */
		params = arg;
		
		return;
	} /* end if */

	/* complex case, lookup for the last node */
	arg2 = params;
	while (arg2->next != NULL)
		arg2 = arg2->next;

	/* set the argument on the last position */
	arg2->next = arg;

	return;
}

/**
 * @internal
 * @brief Perfom a look up inside the argument option installed.
 *
 * This function tries to return the ExArgNodeOption using the given
 * value as index key. 
 *
 * The given value can represent the long key option or the short
 * form.
 * 
 * @param arg_name the key to use on lookup process
 *
 * @return the function retuns the argument option if found or NULL if
 * not.
 */
ExArgNodeOption * exarg_lookup_node (const char * arg_name)
{
	ExArgNodeOption * result      = NULL;
	int               arg_name_len;

	/* check for null value */
	if (arg_name == NULL)
		return NULL;

	/* get length */
	arg_name_len = strlen (arg_name);

	/* look up the item on the current argument option */
	result = argument_options;
	while (result != NULL) {

		/* check value with long argument form */
		if (arg_name_len == strlen (result->arg_name) &&
		    !memcmp (arg_name, result->arg_name, strlen (arg_name))) {

			/* return found node */
			return result;
		}
		
		/* check value with short argument form */
		if ((result->arg_short_name != NULL) && 
		    (arg_name_len == strlen (result->arg_short_name)) &&
		    !memcmp (arg_name, result->arg_short_name, strlen (arg_name))) {

			/* return node found */
			return result;
		}
		
		/* update to the next item */
		result = result->next;

	} /* end while */

	/* return that we didn't found an item */
	return result;
	
} /* end exarg_lookup_node */




int exarg_is_argument (char * argument) 
{

	int iterator = 1;

	/* support standard unix format definition */
	if (CHECK_PARSE_MODE (PARSE_MODE_UNIX) && !memcmp (argument, "--", 2)) {

		/* update parse mode */
		UPDATE_PARSE_MODE (PARSE_MODE_UNIX);
		return 1;
	}

	/* support sort argument format definition */
	if (CHECK_PARSE_MODE (PARSE_MODE_UNIX) && (strlen (argument) == 2) && (argument[0] == '-')) {

		/* update parse mode */
		UPDATE_PARSE_MODE (PARSE_MODE_UNIX);

		return 1;
	}
	
	/* support windows argument format */
	if (CHECK_PARSE_MODE (PARSE_MODE_WINDOWS) && (strlen (argument) > 2) && (argument[0] == '/')) {

		/* now check if the argument doesn't have more bars */
		while (argument[iterator] != 0) {
			/* check value */
			if (argument[iterator] == '/')
				return 0;

			/* update iterator */
			iterator++;
			
		} /* end while */

		/* update parse mode */
		UPDATE_PARSE_MODE (PARSE_MODE_WINDOWS);
		
		return 1;
	}

	return 0;
}

char * exarg_get_argument (char * argument)
{
	/* support getting the argument value for unix standard
	 * argument */
	if (!memcmp (argument, "--", 2))
		return &(argument[2]);
	
	/* support getting the argument value for short def */
	if ((strlen (argument) == 2) && (argument[0] == '-'))
		return &(argument[1]);

	/* support getting the argument value for windows def */
	if ((strlen (argument) > 2) && (argument[0] == '/'))
		return &(argument[1]);

	return NULL;
}

int exarg_check_help_argument (char * argument)
{
	if (!memcmp (argument, "help", 4) || !memcmp (argument, "?", 1))
		return 1;
	return 0;
}

void     exarg_wrap_and_print (const char * text, int size_to_wrap, const char * fill_text)
{
	char    ** stringv      = NULL;
	int        i            = 0;
	int        sum          = 0;
	char     * working_line = NULL;
	char     * aux_string   = NULL;
	int        first_line   = 1;

	/* do not print anything if a null value is received */
	if (text == NULL)
		return;

	if (strlen (text) <= size_to_wrap) {
		printf ("%s\n", text);
		return;
	}

	stringv = exarg_split (text, 1, " ");
	for (i = 0; stringv[i]; i++) {
		if (working_line) {
			aux_string   = working_line;
			working_line = exarg_strdup_printf ("%s %s", working_line, stringv[i]);
			exarg_free (aux_string);
		}else
			working_line = exarg_strdup (stringv[i]);
		sum = sum + strlen (stringv[i]) + 1;

		if (sum >= size_to_wrap) {
			sum = 0;
			if (first_line) {
				first_line = 0;
				printf ("%s\n", working_line);
			}else
				printf ("%s%s\n", fill_text, working_line);
			exarg_free (working_line);
			working_line = NULL;
		}

	}
	if (sum) {
		printf ("%s%s\n", fill_text, working_line);
		exarg_free (working_line);
	}
	exarg_freev (stringv);
	
	
	return;
}

void __exarg_show_usage_foreach (epointer key, epointer value, epointer user_data)
{
	char            ** string_aux = (char **) user_data;
	char             * str        = (* string_aux);
	char             * aux        = NULL;
	ExArgNodeOption  * node       = (ExArgNodeOption  *) value;

	switch (node->type) {
	case EXARG_NONE:
		if (node->arg_short_name)
			(*string_aux) = exarg_strdup_printf (" [-%s|--%s]", node->arg_short_name, node->arg_name);
		else
			(*string_aux) = exarg_strdup_printf (" [--%s]", node->arg_name);
		break;
	case EXARG_INT:
		if (node->arg_short_name)
			(*string_aux) = exarg_strdup_printf (" [-%s <number>|--%s <number>]", node->arg_short_name, node->arg_name);
		else
			(*string_aux) = exarg_strdup_printf (" [--%s <number>]", node->arg_name);
		break;
	case EXARG_STRING:
		if (node->arg_short_name)
			(*string_aux) = exarg_strdup_printf (" [-%s <string>|--%s <string>]", node->arg_short_name, node->arg_name);
		else
			(*string_aux) = exarg_strdup_printf (" [--%s <string>]", node->arg_name);
		break;
	} /* end switch */

	if (str != NULL) {
		/* get a reference to previous content */
		aux           = (* string_aux);
		(*string_aux) = exarg_strdup_printf ("%s%s", str, (*string_aux));
		
		/* dealloc both pieces that joined are the result */
		exarg_free (str);
		exarg_free (aux);
	}
	return;
}

void exarg_show_usage (int show_header)
{
	char            * string_aux = NULL;
	ExArgNodeOption * node;
	
	if (show_header && (__exarg_usage_header && (* __exarg_usage_header)))
		printf ("%s", __exarg_usage_header);

	printf ("Usage: %s ", exarg_exec_name);
	
	/* get the first node */
	node = argument_options;
	while (node != NULL) {
		/* call to the foreach function */
		__exarg_show_usage_foreach ((epointer) node->arg_name, node, &string_aux);
		
		/* update to the next */
		node = node->next;
		
	} /* end while */

	exarg_wrap_and_print (string_aux, 55, "               ");
	printf ("\n");

	/* free string created */
	exarg_free (string_aux);

	if (show_header && (__exarg_post_usage_header && (* __exarg_post_usage_header)))
		printf ("%s", __exarg_post_usage_header);
	
	return;
}

char * __exarg_build_dep_string (ExArgNodeOption * node, int exclude)
{
	char            * result;
	char            * aux;
	ExArgDependency * dep;

	/* check node dependency */
	if (!exclude && ! node->depends)
		return NULL;
	if (exclude && ! node->excludes)
		return NULL;

	if (exclude) 
		result = exarg_strdup ("[excludes: ");
	else
		result = exarg_strdup ("[depends on: ");
	
	/* foreach each dependency configured */
	if (exclude)
		dep    = node->excludes;
	else
		dep    = node->depends;
	while (dep != NULL) {

		aux    = result;
		if (dep->next != NULL)
			result = exarg_strdup_printf ("%s --%s", result, dep->node->arg_name);
		else
			result = exarg_strdup_printf ("%s --%s]", result, dep->node->arg_name);
		exarg_free (aux);
		
		/* get next dependency */
		dep = dep->next;

	} /* end while */

	/* return string created */
	return result;
}

void __exarg_show_help_foreach (epointer key, epointer value, epointer user_data)
{
	ExArgNodeOption * node = (ExArgNodeOption  *) value;
	char            * dep;
	int               chars = 35;
	int               iterator = 0;
	
	/* print argument help */
	if (node->arg_short_name) {
		printf ("  -%s, --%-18s       ", 
			node->arg_short_name, node->arg_name);
		exarg_wrap_and_print (node->description, 40, "                                 ");

	}else {
		printf ("  --%-22s       ", node->arg_name);
		exarg_wrap_and_print (node->description, 40, "                                 ");
	}

	/* print argument dependency */
	dep = __exarg_build_dep_string (node, 0);
	if (dep != NULL) {
		/* write spaces */
		while (iterator < chars) {
			printf (" ");
			iterator++;
		}
		exarg_wrap_and_print (dep, 40, "                                 ");
	}
	exarg_free (dep);

	/* print argument exclusion */
	iterator = 0;
	dep      = __exarg_build_dep_string (node, 1);
	if (dep != NULL) {
		/* write spaces */
		while (iterator < chars) {
			printf (" ");
			iterator++;
		}
		exarg_wrap_and_print (dep, 40, "                                 ");
	}
	exarg_free (dep);
	return;
}

void   exarg_show_help (void) 
{
	ExArgNodeOption * node;

	if (__exarg_help_header && (* __exarg_help_header))
		printf ("%s", __exarg_help_header);

	exarg_show_usage (0);

	printf ("\nCommand options:\n");

	/* get first node */
	node = argument_options;
	while (node != NULL) {
		/* call to show the node information */
		__exarg_show_help_foreach ((epointer) node->arg_name, node, NULL);

		/* update to the next node */
		node = node->next;
	} /* end while */

	printf ("\nHelp options:\n");
	printf ("  -?, --help                    Show this help message.\n");
	printf ("  --usage                       Display brief usage message.\n");

	if (__exarg_post_help_header && (* __exarg_post_help_header))
		printf ("%s", __exarg_post_help_header);

	return;
}

void exarg_check_argument_value (char ** argv, int iterator) 
{

	if (argv[iterator] == NULL) {
		printf ("error: not defined value for argument: %s, exiting..",
			argv[iterator - 1]);
		fflush (stdout);
		exit (-1);
	}

	if (exarg_is_argument (argv[iterator])) {
		printf ("error: not defined value for argument: %s, instead found another argument: %s, exiting..",
			argv[iterator - 1],
			argv[iterator]);
		fflush (stdout);
		exit (-1);
	}

	return;
}


void __exarg_parse_check_non_optional (void)
{
	ExArgNodeOption * node = argument_options;

	/* for each node */
	while (node != NULL) {
		/* check the node */
		if (! node->is_optional && ! node->is_defined) {
			exarg_msg ("error: argument '%s' is not defined, but it is required for a proper function..\n",
				   node->arg_name);
		} /* end if */

		/* get the next */
		node = node->next;

	} /* end while */

	return;
}

void __exarg_parse_check_depends (void)
{
	/* first argument */
	ExArgNodeOption * node = argument_options;
	ExArgDependency * dep;

	/* for each argument defined */
	while (node != NULL) {

		/* check if the argument was defined, and hence
		 * activates its dependencies */
		if (! node->is_defined) {
			node = node->next;
			continue;
		}

		/* check depends */
		dep = node->depends;
		while (dep != NULL) {

			/* check that the dependency is defined */
			if (! dep->node->is_defined) {
				exarg_msg ("You must define argument (--%s) if used (--%s). Try %s --help.", 
					   dep->node->arg_name, node->arg_name, exarg_exec_name);
				return;
			} /* end if */

			/* get next dependency */
			dep = dep->next;
			
		} /* end while */

		/* check depends */
		dep = node->excludes;
		while (dep != NULL) {
			
			/* check that the dependency is defined */
			if (dep->node->is_defined) {
				printf ("You can't define argument (--%s) if used (--%s). Try %s --help.\n", 
					node->arg_name, dep->node->arg_name, exarg_exec_name);
				fflush (stdout);
				return;
			} /* end if */

			/* get next dependency */
			dep = dep->next;
			
		} /* end while */

		/* get next node */
		node = node->next;
 
	} /* end whle */

	/* nothing more to check */
	return;
}


/** 
 * \brief Makes exarg to start parsing argument options.
 *
 * Makes LibExArg to start command line parsing by using arguments
 * installed. 
 * 
 * Once this functions is called it is posible to call the set of
 * function which returns data obtained: \ref exarg_is_defined,
 * \ref exarg_get_int, \ref exarg_get_string and \ref exarg_get_params.
 *
 * The advantage is that LibExArg allows you to get access to command
 * line data from any point of your program.
 * 
 * @param argc the argc value the current application have received.
 * @param argv the argv value the current application have received.
 */
void       exarg_parse         (int         argc,
				char     ** argv)
{
	int              iterator = 1;
	ExArgNodeOption * node;
	char           * argument;

	/* check how many argument have been defined */
	if (iterator == argc) {
		/* once terminated, check if the non optional options
		 * were defined */
		
		__exarg_parse_check_non_optional ();
		return;
	}

	exarg_exec_name = exarg_basename (argv[0]);
	
	/* iterate over all arguments */
	while (iterator < argc) {

		if (!exarg_is_argument (argv[iterator])) {
			/* check free argument configuration */
			if (__exarg_disable_free_args) {
				exarg_msg ("error: provided a free argument='%s', not listed in the accept command line option", argv[iterator]);

			} /* end if */

			/* save and increase iterator */
			__exarg_add_argument (argv[iterator]);
			iterator++;
			continue;
		}
		
		/* get clean argument */
		argument = exarg_get_argument (argv[iterator]);

		/* check for help argument */
		if (exarg_check_help_argument (argument)){
			exarg_show_help ();
			exarg_end ();
			exit (0);
		}
		
		/* check for usage argument */
		if (!memcmp (argument, "usage", 5)) {
			exarg_show_usage (1);
			exarg_end ();
			exit (0);
		}

		/* get node argument */
		node = exarg_lookup_node (argument);
		if (node == NULL) {
			exarg_msg ("%s error: argument not found: %s, try: %s --help\n",
				   exarg_exec_name, argv[iterator], exarg_exec_name);
		}
		
		/* check if node is defined */
		if (node->is_defined) {
			exarg_msg ("%s error: argument %s already defined, exiting..\n",
				   exarg_exec_name, argv[iterator]);
		}

		
		/* set this argument to be defined */
		node->is_defined = 1;
		switch (node->type) {
		case EXARG_NONE:
			/* nothing to do */ 
				break;
		case EXARG_INT:
			/* save int value */
			iterator++;

			exarg_check_argument_value (argv, iterator);

			node->int_value    = atoi (argv[iterator]);
			break;
		case EXARG_STRING:
			iterator++;
			
			exarg_check_argument_value (argv, iterator);

			node->string_value = argv[iterator];

			break;
		}
		
		/* update iterator */
		iterator++;
	}

	/* once terminated, check if the non optional options were
	 * defined */
	__exarg_parse_check_non_optional ();

	/* check argument dependency and argument mutual exclusion. */
	__exarg_parse_check_depends ();

	return;
}

void __exarg_end_free_dep (ExArgDependency * dep)
{
	ExArgDependency * next;

	/* foreach dependency established */
	while (dep != NULL) {

		/* free the dep node */
		next = dep->next;
		exarg_free (dep);
		dep  = next;
	} /* end while */

	return;
}

/**
 * \brief Ends exarg library execution.
 * 
 * Terminates the exarg function. This function will free all
 * resources allocated so the library cannot be used any more for the
 * current execution.
 *
 * This function is reatrant. Several threads can actually call this
 * function. It will take care about making only one thread to
 * actually free resources.
 **/
void       exarg_end           ()
{
	ExArgNodeOption * node;
	ExArgNodeOption * node2;
	
	ExArgument      * params2;
	

	if (argument_options != NULL) {
		/* get a reference to the table, and dealloc it */
		node             = argument_options;
		argument_options = NULL;
		
		while (node != NULL) {
			/* get a reference to the next */
			node2 = node->next;

			/* free node arguments dependencies and mutual
			 * exclusions */
			__exarg_end_free_dep (node->depends);
			__exarg_end_free_dep (node->excludes);

			/* free current node */
			exarg_free (node);
			
			/* update the node ref */
			node = node2;
		} /* end while */

	} /* end if */

	if (params != NULL) {
		while (params != NULL) {
			/* get a reference to the next node */
			params2 = params->next;

			/* free params node */
			exarg_free (params);

			/* configure the next argument to dealloc */
			params = params2;
		} /* end while */
	} /* end if */

	return;
}

/**
 * \brief Disable autohelp.
 * 
 * Allows to disable auto help and --help and -? option
 * recognition. This is useful if you don't want your program to
 * accept --help and --usage options.
 **/
void       exarg_disable_help ()
{
	return;
}

/**
 * \brief Adds user defined header to automatic usage command generated.
 * 
 * Once a program is linked to libexarg is able to produce a usage
 * help by accepting the --usage command line option. But that usage
 * help is showed as is. This function allows you to define a header
 * to be showed preceding the usage info. You can use this, for
 * example, to introduce your copyright.
 *
 * This function doesn't make a copy of the given string so you
 * must not free the header provided or use an static string.
 **/
void       exarg_add_usage_header (char * header)
{
	__exarg_usage_header = header;
}

/**
 * \brief Adds user defined header to automatic help command generated.
 * 
 * Once a program is linked to libexarg is able to produce a help by
 * accepting the --help or -? command line option. But that help is
 * showed as is. This function allows you to define a header to be
 * showed preceding the help info. You can use this, for example, to
 * introduce your copyright.
 *
 * This function doesn't make a copy of the given string so you
 * must not free the header provided or use an static string.
 **/
void       exarg_add_help_header  (char * header)
{
	__exarg_help_header = header;
}

/**
 * \brief Adds user defined post header for usage command.
 * 
 * This function works pretty much like \ref exarg_add_usage_header but
 * adding the header provided to be appended at the end of the usage
 * automatically generated.
 **/
void       exarg_post_usage_header (char * post_header)
{
	__exarg_post_usage_header = post_header;
}

/**
 * \brief Adds user defined post header for help command.
 * 
 * This function works pretty much like \ref exarg_add_help_header but
 * adding the header provided to be appended at the end of the help
 * automatically generated.
 **/
void       exarg_post_help_header (char * post_header)
{
	__exarg_post_help_header = post_header;
}

/**
 * \internal
 * Internal ExArg function. This function allows \ref exarg_install_arg to
 * check if there are already installed an short argument as the one
 * been installed.
 **/
void __exarg_check_short_arg (epointer key, epointer value, epointer user_data)
{
	ExArgNodeOption * node         = (ExArgNodeOption  *) value;
	char           * arg_to_check = (char *) user_data;

	if (node->arg_short_name != NULL) {
		if (!memcmp (node->arg_short_name, arg_to_check, strlen (arg_to_check))) {
			exarg_msg ("error: found that short arg installed is already found: %s\n", arg_to_check);
		} /* end if */
	} /* end if */

	return;
}

/**
 * \brief Installs a new command line to be accepted.
 * 
 * This functions allows you to install new arguments to be
 * accepted. Every argument passed in to the program which is not
 * installed throught this function will no be accepted and will
 * generate a non recognized command line error.
 *
 * Let's see an example on how to use exarg to install the --version
 * argument. You should call exarg as follows:
 * 
 * \code
 *       exarg_install_arg ("version", "v", EXARG_NONE, 
 *                          "show program version");
 *
 * \endcode
 * 
 * Previous line have installed a argument called "version" which will
 * be invoked by the user as --version. The short alias
 * in this case is "v" which as we have see will allow user to invoke
 * your program as -v.
 *
 * Because you could install arguments which may conflict, this
 * function will abort the program execution on that case. This will
 * ensure you, as programer, to have a binary compiled with no
 * problems due to exarg.
 *
 * Later on, you can use \ref exarg_is_defined to check the status of
 * installed arguments. Once you install an argument the user may
 * invoke it and you could check that status using previous
 * function. Because the "version" argument type is \ref EXARG_NONE you can
 * only use \ref exarg_is_defined. But, for other argument types as
 * \ref EXARG_STRING, you can also use \ref exarg_get_string function to get the
 * value defined by user. Let's see an example.
 *
 * \code
 *       exarg_install_arg ("load-library", "l", EXARG_STRING,
 *                          "loads the library defined as argument");
 * \endcode
 * 
 * This previous line will allow user to invoke your program as 
 * --load-library path/to/lib. Then you can use \ref exarg_get_string to get
 * the path/to/lib value by using:
 * 
 * \code
 *       // check user have defined this argument
 *       if (exarg_is_defined ("load-library")) {
 *
 *             arg_value = exarg_get_string ("load-library");
 *
 *             printf ("The library defined by user was: %s\n", 
 *                      arg_value);
 *       }
 * 
 * \endcode
 *
 * You must install all argument before calling \ref exarg_parse. That function
 * will parse argument options by using installed arguments. Check the info
 * about that function.
 * 
 * ExArg is not thread-safe which doesn't means anything wrong but you
 * must call all exarg function from the same thread to get the right
 * results. 
 *
 * This function will not do a copy from arg_name, arg_short_name or
 * description. This means you should not free that values while
 * using exarg. To end exarg using check \ref exarg_end. It is recomended to use
 * static values and shows on previous examples.
 **/
void       exarg_install_arg  (const char     * arg_name, 
			       const char     * arg_short_name, 
			       ExArgType   type,
			       const char     * description)
{
	ExArgNodeOption * node;
	ExArgNodeOption * node2;

	/* init hash table */
	if (argument_options != NULL) {
		/* check if there are an argument with the same name */
		if (exarg_lookup_node (arg_name)) {
			exarg_end ();
			exarg_msg ("error: argument being installed is already defined: %s..",
				   arg_name);
		}
		
		/* check if there are an shor argument with the same
		 * name */
		if (arg_short_name != NULL) {
			node = argument_options;
			
			/* while there are options to process */
			while (node != NULL) {
				/* call to check */
				__exarg_check_short_arg ((epointer) node->arg_name, node, (epointer) arg_short_name);

				/* update to the next */
				node = node->next;
			} /* end while */
		} /* end if */
	} /* end if */
		
	/* create node option */
	node                 = exarg_new (ExArgNodeOption, 1);
	node->arg_name       = arg_name;
	node->arg_short_name = arg_short_name;
	node->type           = type;
	node->description    = description;
	node->is_optional    = 1;

	/* lookup for the last position */
	if (argument_options == NULL)
		argument_options = node;
	else {
		/* lookup for the last */
		node2 = argument_options;
		while (node2->next != NULL)
			node2 = node2->next;

		/* set it */
		node2->next = node;
	} /* end if */

	return;
}

/**
 * \brief Installs several command lines to be accepted.
 * 
 * This function does the same that \ref exarg_install_arg but making 
 * group of argument to be installed in one step.
 *
 * Think about installing two argument. To install them we have to do
 * the following:
 *
 * \code
 *    exarg_install_arg ("version", "v", 
 *                       EXARG_NONE, "show argument version");
 *    exarg_install_arg ("load-library", "l", 
 *                       EXARG_STRING, "load my library");
 * \endcode
 *
 * Because some people doesn't like to perform several calls to the
 * same funcion the previous code can be done by using one step as:
 *
 * \code
 *    exarg_install_argv (2, "version", "v", EXARG_NONE, 
 *                        "show argument version", 
 *                        "load-library", "l",
 *                        EXARG_STRING, "load my library");
 * \endcode
 *
 * When you install argument this way you have to specify how many
 * argument is going to be installed. In this case that number is
 * 2. This allows exarg to know how many arguments needs to search
 * inside the argv. If something is wrong while specifying the number
 * or argument or the argument information itself you'll get a
 * segmentation fault or something similar.
 *
 * While calling to \ref exarg_install_arg the short_name argument can be
 * optional. This is *NOT* applied to this function. If you don't want
 * to define a short argument name you must use NULL as value.
 * 
 * @param num_arg Must be at least 1 or error will happen and library will abort
 * application execution.
 **/
void       exarg_install_argv (int num_arg, ...)
{
	va_list      args;
	int         iterator;
	char      * arg_name;
	char      * arg_short_name;
	ExArgType    type;
	char      * description;

	if (num_arg <= 0) {
		exarg_end ();
		exarg_msg ("error: calling to exarg_install_argv with num_arg equal or less to 0..");
	}

	va_start (args, num_arg);

	for (iterator = 0; iterator < num_arg; iterator++) {

		/* get the argument info */
		arg_name       = va_arg (args, char *);
		arg_short_name = va_arg (args, char *);
		type           = va_arg (args, ExArgType);
		description    = va_arg (args, char *);
		
		exarg_install_arg (arg_name, arg_short_name, type, description);
	}
	va_end (args);
	return;
}

/** 
 * @brief Allows to define a parameter dependency between the to
 * arguments defined. The kind of dependency has direction. This means
 * that the first argument will depend on the second argument, forcing
 * the user to define the second argument if the first one is defined.
 *
 * You can call to this function several times making the first
 * argument to depend on any number of argument defined. You must not
 * call to establish a dependency to the argument itself.
 * 
 * @param arg_name The argument that will be configured with an
 * argument dependency.
 *
 * @param arg_dependency The argument that will receive the
 * dependency.
 *
 *
 */
void         exarg_add_dependency   (const char * arg_name, 
				     const char * arg_dependency)
{
	ExArgNodeOption * node;
	ExArgNodeOption * node2;
	ExArgDependency * dep;
	/* check arguments received */
	if (arg_name == NULL)
		return;
	if (arg_dependency == NULL)
		return;

	/* check that both arguments aren't equal */
	if (strlen (arg_name) == strlen (arg_dependency) &&
	    !memcmp (arg_name, arg_dependency, strlen (arg_name))) {
		exarg_msg ("error: defined argument dependency with an argument itself.");
		return;
	}
	
	/* locates the argument node */
	node = exarg_lookup_node (arg_name);
	if (node == NULL) {
		exarg_msg ("error: you did especify an argument that doesn't exists (%s)", arg_name);
		return;
	}

	/* locates dependecy argument node */
	node2 = exarg_lookup_node (arg_dependency);
	if (node2 == NULL) {
		exarg_msg ("error: you did especify an argument that doesn't exists (%s)", arg_dependency);
		return;
	}

	/* make the first argument to depend on the second */
	dep = node->depends;
	
	/* create the new dependency node */
	node->depends       = exarg_new (ExArgDependency, 1);
	node->depends->node = node2;
	node->depends->next = dep;

	return;
}

/** 
 * @brief Allows to configure arguments that are mutually
 * excluyents. This function will take the first arguments to be
 * muatually excluyen with the second one without direction as it
 * happens with \ref exarg_add_dependency function.
 *
 * Once defined both arguments provided can't be defined at the same
 * time at the command line options.
 * 
 * @param arg_name The first argument to make mutual exclusion with
 * the second argument.
 *
 * @param arg_excluded Second argument to make mutual exclusion with
 * the first argument.
 */
void         exarg_add_exclusion     (const char * arg_name, 
				      const char * arg_excluded)
{
	ExArgNodeOption * node;
	ExArgNodeOption * node2;
	ExArgDependency * dep;

	/* check arguments received */
	if (arg_name == NULL)
		return;
	
	if (arg_excluded == NULL)
		return;

	/* check that both arguments aren't equal */
	if (strlen (arg_name) == strlen (arg_excluded) &&
	    !memcmp (arg_name, arg_excluded, strlen (arg_name))) {
		exarg_msg ("error: defined argument dependency with an argument itself.");
		return;
	}
	
	/* locates the argument node */
	node = exarg_lookup_node (arg_name);
	if (node == NULL) {
		exarg_msg ("error: you did especify an argument that doesn't exists (%s)", arg_name);
		return;
	}

	/* locates dependecy argument node */
	node2 = exarg_lookup_node (arg_excluded);
	if (node2 == NULL) {
		exarg_msg ("error: you did especify an argument that doesn't exists (%s)", arg_excluded);
		return;
	}

	/* make the first argument to depend on the second */
	dep = node->excludes;
	
	/* create the new dependency node */
	node->excludes       = exarg_new (ExArgDependency, 1);
	node->excludes->node = node2;
	node->excludes->next = dep;

	return;
}


/** 
 * @brief Makes an argument installed to be obligatory (not optional
 * at the user command line input).
 *
 * Once called \ref exarg_install_arg, you can use this function to
 * make the program to make the option obligatory.
 * 
 * @param arg_name The argument to make it obligatory.
 */
void       exarg_set_obligatory   (char * arg_name)
{
	ExArgNodeOption * node;

	/* perform some environment checks */
	if (arg_name == NULL)
		return;

	node = exarg_lookup_node (arg_name);
	if (node == NULL) {
		return;
	}

	/* make it to be defined */
	node->is_optional = 0;

	return;
}


/** 
 * @brief Allows to configure exarg library to accept or not free
 * arguments. 
 * 
 * Free arguments are optional parameters provided to the application,
 * such files, which aren't associated to a particular option.
 *
 * If your command line application do not uses free arguments, you
 * can use this function to enable exarg library to show an error
 * message to the user:
 *
 * \code
 * // disable free arguments
 * exarg_accept_free_args (0);
 * \endcode
 * 
 * @param accept 1 to accept free arguments. It is the default value,
 * so it is not required to enable it. 0 to disable free arguments.
 */
void         exarg_accept_free_args (int accept)
{
	/* configure free arguments */
	__exarg_disable_free_args = (accept == 0);

	return;
}

/** 
 * @brief Allows to simulate user defined command line options alread
 * installed by \ref exarg_install_arg, without requiring the user to
 * set those values.
 *
 * This function allows to install values received or to just define
 * the argument to be supported by the program, without requiring the
 * user to provide such option. This is a convenient to make some
 * options to be default, writting your application relying on
 * arguments defined by command line.
 *
 * The function won't define the argument if not installed
 * previously. If the argument isn't found, the function takes no
 * action.
 *
 * @param arg_name The argument o define as provided by the user.
 * @param value The value to be associated to the argument. Some
 * arguments doesn't require this paremeters (\ref EXARG_NONE), so,
 * you can provide NULL to this parameter.
 */
void       exarg_define           (char * arg_name,
				   char * value)
{
	ExArgNodeOption * node;

	/* perform some environment checks */
	if (arg_name == NULL)
		return;

	node = exarg_lookup_node (arg_name);
	if (node == NULL) {
		return;
	}
	/* make it to be defined */
	node->is_defined = 1;

	/* check argument value */
	if (value != NULL) {
		switch (node->type) {
		case EXARG_NONE:
			/* nothing to set */
			break;
		case EXARG_INT:
			/* integer value */
			node->int_value = strtol (value, NULL, 10);
			break;
		case EXARG_STRING:
			/* string value */
			node->string_value = value;
			break;
		} /* end switch */
	} /* end if */

	/* nothing to do over here */
	return;
}

/**
 * @brief Allows to undef the value associated and the definition
 * itself of the option provided (arg_name).
 *
 * @param arg_name The argument to undef.
 */
void         exarg_undef            (char * arg_name)
{
	ExArgNodeOption * node;

	/* perform some environment checks */
	if (arg_name == NULL)
		return;

	node = exarg_lookup_node (arg_name);
	if (node == NULL) 
		return;

	/* undef the value */
	node->is_defined = 0;

	/* check argument value */
	switch (node->type) {
	case EXARG_NONE:
		/* nothing to set */
		break;
	case EXARG_INT:
		/* integer value */
		node->int_value = 0;
		break;
	case EXARG_STRING:
			/* string value */
		node->string_value = NULL;
		break;
	} /* end switch */

	/* nothing to do over here */
	return;
}

/**
 * \brief Allows to check if a user have defined a command.
 * 
 * Once an argument is installed the user may or may not define it. To
 * define it simply means to use this argument as command line
 * option. This function allows to check if an argument was used for
 * the current command line option.
 *
 * This function is expecting to receive the argument name to lookup
 * not the short name. User may be using the short name to invoke the
 * argument but the lookup is allways done by using the argument name.
 * 
 * \return TRUE if argument was defined or FALSE if not.
 **/
int   exarg_is_defined   (char     * arg_name)
{
	ExArgNodeOption * node;

	/* perform some environment checks */
	if (arg_name == NULL)
		return 0;
	
	if (argument_options == NULL)
		return 0;

	node = exarg_lookup_node (arg_name);
	if (node == NULL) {
		return 0;
	}
	return node->is_defined;
}

/** 
 * @brief Allows to check several values to be defined at the same time.
 *
 * This allows to check if several command line options have been
 * defined at the same time. 
 * Example:
 * \code
 *   if (exarg_is_definedv ("param1", "param2", NULL)) {
 *         //param1 and param2 have been defined by the user
 *   }
 * \endcode
 *
 * This is a short way for actually doing:
 * \code
 *  if (exarg_is_defined ("param1") && exarg_is_defined ("param2")) {
 *      // param1 and para2 have been defined by the user
 *  }
 * \endcode
 * 
 * Do not forget to pass a NULL value for the last item.
 * 
 * @return TRUE if all values are defined, otherwise FALSE.
 */
int   exarg_is_definedv      (char * first_value, ...)
{
	int       result = 1;
	char    * string_value;
	va_list    args;

	if (first_value == NULL)
		return 0;

	/* check first value */
	if (!exarg_is_defined (first_value))
		return 0;

	/* open stdargs */
	va_start        (args, first_value);
	string_value = va_arg (args, char *);

	/* check for last NULL value */
	while ((string_value != NULL) && (* string_value)) {
		/* check next value */
		result       = result && exarg_is_defined (string_value);

		/* get next value */
		string_value = va_arg (args, char *);
	}

	/* return current value */
	va_end (args);
	return result;
}

/**
 * \brief Allows to get defined string for a given command line.
 * 
 * Returns the value associated with the argument name. The returned
 * value must not be deallocated. If it is needed a string copy use
 * \ref exarg_get_string_alloc.
 * 
 * \return The value associated with the param or NULL if fail.
 **/
char    * exarg_get_string   (char     * arg_name)
{
	ExArgNodeOption * node;

	if (arg_name == NULL)
		return NULL;
	
	if (argument_options == NULL)
		return NULL;

	node = exarg_lookup_node (arg_name);
	if (node == NULL) {
		exarg_msg ("error: calling to get string value for: %s, but this argument isn't defined..",
			   arg_name);
	}
	if (node->type != EXARG_STRING) {
		exarg_msg ("error: calling to get string value for: %s, but the argument wasn't defined as EXARG_STRING..",
			   arg_name);
	}
	
	return node->string_value;
}

/**
 * \brief Allows to get defined string for a given command line allocating the result.
 * 
 * Returns the value associated with the argument name. The returned
 * value must be <b>deallocated</b> using g_free. You can also use
 * \ref exarg_get_string to get a value that doesn't need to be
 * unrefered.
 * 
 * \return The value associated with the param or NULL if fail.
 **/
char    * exarg_get_string_alloc (char * arg_name)
{
	char * string_value;

	string_value = exarg_get_string (arg_name);
	if (string_value == NULL)
		return NULL;
	return exarg_strdup (string_value);
}

/**
 * \brief Allows to get int value for a given command line argument.
 * 
 * Returns the value associated with the argument name. The returned
 * may be 0 which means the user may not defined that argument or may
 * defined it by using the 0 as value. To avoid confusing cases you
 * should use \ref exarg_is_defined to know if the user have used that
 * argument and then call this function.
 * 
 * \return the value defined for this argument. If the argument
 * is null or the exarg is not initialized the function will return -1.
 **/
int       exarg_get_int      (char     * arg_name)
{
	ExArgNodeOption * node;

	if (arg_name == NULL)
		return -1;
	if (argument_options == NULL)
		return -1;

	node = exarg_lookup_node (arg_name);
	if (node == NULL) {
		exarg_msg ("error: calling to get int value for: %s, but this argument isn't defined..",
			   arg_name);
	}

	if (node->type != EXARG_INT) {
		exarg_msg ("error: calling to get int value for: %s, but the argument wasn't defined as EXARG_INT..",
			   arg_name);
	}
	
	return node->int_value;
}

/**
 * \brief Returns free params defined at command line.
 * 
 * Every value which is not an argument is considered to be a
 * parameter. All of them are stored and retrieved by using this
 * function and the following functions:
 *
 *  - \ref exarg_param_get 
 *  - \ref exarg_param_next
 *
 * An example about using this function could be the next. A program
 * have defined several arguments using the function \ref
 * exarg_install_arg but that program also needs to receive several
 * file path. 
 * 
 * Once the \ref exarg_parse have detected all argument, all
 * parameters are stored, and this function provides access to the
 * first argument *found. Then a call to \ref exarg_param_get is
 * required to get the *argument value and a call to \ref
 * exarg_param_next to get a *reference to the next argument.
 * 
 *
 * A program which may receive the argument --save-all but also several
 * files:
 *
 * \code
 *    a_program --save-all file1 file2 file3
 * \endcode
 *
 * Will need to call this function to get the list: file1 file2 and
 * file3. 
 * 
 * \return The first param provided to the program. The returned value
 * must not be deallocated.
 */
ExArgument   * exarg_get_params   ()
{
	return params;
}

/** 
 * @brief Allows to get the string value that is represeting the argument received.
 * 
 * @param arg The argument that was received by the program.
 * 
 * @return An string reference that must not be deallocated.
 */
const char * exarg_param_get        (ExArgument * arg)
{
	/* check for null value received */
	if (arg == NULL)
		return NULL;
	
	/* return the string value inside */
	return arg->string;
}

/** 
 * @brief Allows to get the next parameters defined at the command
 * line option that is following the argument provided.
 * 
 * @param arg The argument which is previous to the argument to be
 * returned.
 * 
 * @return An argument reference to the next or NULL if there are no
 * more arguments.
 */
ExArgument * exarg_param_next       (ExArgument * arg)
{
	/* check for null value received */
	if (arg == NULL)
		return NULL;
	
	/* return the next argument */
	return arg->next;
}


/** 
 * @brief Allows to get the number of parameters that were defined by
 * the user. 
 *
 * Check also the following function \ref exarg_get_params_num.
 * 
 * @return The number of parameters starting from 0.
 */
int       exarg_get_params_num   ()
{
	ExArgument * arg    = NULL;
	int          result = 0;

	if (params == NULL)
		return 0;

	/* count the number of params */
	arg = params;
	while (arg != NULL) {
		/* update the count */
		result++;

		/* update to the next */
		arg = arg->next;

	} /* end while */

	/* return current count */
	return result;
}

/* @} */


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>