/**************************************************************

params.c (C-Munipack project)
Parameter string parsing function
Copyright (C) 2003 David Motl, dmotl@volny.cz

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 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 <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "cmdline.h"
#include "utils.h"

/***********************   LOCAL FUNCTIONS   ***************************/

/* Find option by its long name */
static CmdOption *find_option_long(CmdOption *opts, const char *name)
{
	int i;

	if (opts && name) {
		for (i=0; opts[i].name!=NULL; i++) {
			if (strcmp(opts[i].name, name)==0) {
				/* Found */
				return opts+i;
			}
		}
	}
	/* Not found */
	return NULL;
}

/* Find option by its short name */
static CmdOption *find_option_short(CmdOption *opts, char abbrev)
{
	int i;

	if (opts && abbrev) {
		for (i=0; opts[i].name!=NULL; i++) {
			if (opts[i].abbrev!=0 && opts[i].abbrev == abbrev) {
				/* Found */
				return opts+i;
			}
		}
	}
	/* Not found */
	return NULL;
}

/* Find option which specifies value for configuration parameter */
static const char *find_option_key(CmdOption *opts, const char *param)
{
	int i, j;

	if (opts && param) {
		for (i=0; opts[i].name!=NULL; i++) {
			if (opts[i].type==CMD_PTYPE_PARAMLIST) {
				if (opts[i].inst) {
					CmdParamData *data = &opts[i].inst->data;
					for (j=0; j<data->count; j+=2) {
						if (strcmp(data->val.str_vec[j], param)==0)
							/* Found */
							return data->val.str_vec[j+1];
					}
				}
			}
		}
	}
	/* Not found */
	return NULL;
}

/* Find parameter by position index */
static CmdParam *find_param_index(CmdParam *params, int position)
{
	int i, j;

	if (params && position>=0) {
		j = 0;
		for (i=0; params[i].name!=NULL; i++) {
			if (j==position || params[i].type == CMD_PTYPE_FILELIST)
				return params+i;
			j++;
		}
	}
	/* Not found */
	return NULL;
}

/* Find parameter by position index */
static CmdParam *find_param_name(CmdParam *params, const char *name)
{
	int i;

	if (params && name) {
		for (i=0; params[i].name!=NULL; i++) {
			if (strcmp(params[i].name, name)==0)
				return params+i;
		}
	}
	/* Not found */
	return NULL;
}

/* Convert string to data type and set it to the instance */
static int set_data(const char *str, CmdParamInstance *inst)
{
	int x, *intv, count;
	double d, *dblv;
	char *endptr, *key, *val, *buf;
	CmdParamData *data = &inst->data;

	if (str && inst) {
		switch (inst->type)
		{
		case CMD_PTYPE_INT:
			str += strspn(str, " (");
			x = strtol(str, &endptr, 10);
			if (endptr!=str) {
				data->val.int_val = x;
				return 1;
			}
			break;

		case CMD_PTYPE_DOUBLE:
			str += strspn(str, " (");
			d = strtod(str, &endptr);
			if (endptr!=str) {
				data->val.dbl_val = d;
				return 1;
			}
			break;

		case CMD_PTYPE_STRING:
			data->val.str_val = StrDup(str);
			return 1;

		case CMD_PTYPE_FILEPATH:
			buf = StrDup(str);
			if (CheckFilePath(buf)) {
				data->val.str_val = buf;
				return 1;
			} else {
				free(buf);
				return 0;
			}
			break;

		case CMD_PTYPE_FILEMASK:
			buf = StrDup(str);
			if (CheckFileMask(buf)) {
				data->val.str_val = buf;
				return 1;
			} else {
				free(buf);
				return 0;
			}
			break;

		case CMD_PTYPE_PARAMLIST:
			if (StrToKeyVal(str, &key, &val)) {
				if (data->count+2>data->capacity) {
					data->capacity += 16;
					char** newptr = (char**)realloc(data->val.str_vec, data->capacity * sizeof(char*)); 
					if (!newptr)
						free(data->val.str_vec);
					data->val.str_vec = newptr;
				}
				if (data->val.str_vec) {
					data->val.str_vec[data->count++] = key;
					data->val.str_vec[data->count++] = val;
				}
				return 1;
			}
			break;

		case CMD_PTYPE_INT_V:
			str += strspn(str, " (");
			if (StrToIntV(str, &intv, &count)) {
				free(data->val.int_vec);
				data->count = count;
				data->val.int_vec = intv;
				return 1;
			}
			break;

		case CMD_PTYPE_DOUBLE_V:
			str += strspn(str, " (");
			if (StrToDoubleV(str, &dblv, &count)) {
				free(data->val.dbl_vec);
				data->count = count;
				data->val.dbl_vec = dblv;
				return 1;
			}
			break;

		case CMD_PTYPE_FILELIST:
			buf = StrDup(str);
			if (CheckFilePath(buf)) {
				if (data->count>=data->capacity) {
					data->capacity += 16;
					char** newptr = (char**)realloc(data->val.str_vec, data->capacity * sizeof(char*));
					if (!newptr)
						free(data->val.str_vec);
					data->val.str_vec = newptr;
				}
				if (data->val.str_vec) {
					data->val.str_vec[data->count++] = buf;
				}
				return 1;
			} else {
				free(buf);
				return 0;
			}
			break;
			
		default:
			break;
		}
	}
	return 0;
}

/* Convert string to data type and set it to the instance */
static int dump_data(CmdParamInstance *inst)
{
	int i;
	CmdParamData *data = &inst->data;

	if (inst) {
		switch (inst->type)
		{
		case CMD_PTYPE_INT:
			printf("%d", data->val.int_val);
			break;

		case CMD_PTYPE_DOUBLE:
			printf("%.3g", data->val.dbl_val);
			break;

		case CMD_PTYPE_STRING:
		case CMD_PTYPE_FILEPATH:
		case CMD_PTYPE_FILEMASK:
			printf("'%s'", data->val.str_val);
			break;

		case CMD_PTYPE_PARAMLIST:
			printf("\n");
			for (i=0; i<data->count; i+=2) 
				printf("\t\t\t%s = '%s'\n", data->val.str_vec[i], data->val.str_vec[i+1]);
			break;

		case CMD_PTYPE_INT_V:
			for (i=0; i<data->count; i++) 
				printf("%d ", data->val.int_vec[i]);
			break;

		case CMD_PTYPE_DOUBLE_V:
			for (i=0; i<data->count; i++) 
				printf("%.3g ", data->val.dbl_vec[i]);
			break;

		case CMD_PTYPE_FILELIST:
			printf("\n");
			for (i=0; i<data->count; i++) 
				printf("\t\t\t'%s'\n", data->val.str_vec[i]);
			break;
			
		default:
			break;
		}
	}
	return 0;
}

static int set_option_attr(AppInfo *cmd, CmdOption *opt, CmdParamInstance *inst, const char *str)
{
	if (set_data(str, inst)) 
		return 1;

	switch (inst->type)
	{
	case CMD_PTYPE_INT:
		fprintf(stderr, "%s: Invalid data format for option '%s': '%s' (should be integer)\n", 
			cmd->program->name, opt->name, str);
		break;
	case CMD_PTYPE_DOUBLE:
		fprintf(stderr, "%s: Invalid data format for option '%s': '%s' (should be real number)\n", 
			cmd->program->name, opt->name, str);
		break;
	case CMD_PTYPE_FILEPATH:
		fprintf(stderr, "%s: Invalid data format for option '%s': '%s' (should be file name)\n", 
			cmd->program->name, opt->name, str);
		break;
	case CMD_PTYPE_FILEMASK:
		fprintf(stderr, "%s: Invalid data format for option '%s': '%s' (should be file mask)\n", 
			cmd->program->name, opt->name, str);
		break;
	case CMD_PTYPE_PARAMLIST:
		fprintf(stderr, "%s: Invalid data format for option '%s': '%s' (should be 'key=value')\n", 
			cmd->program->name, opt->name, str);
		break;
	case CMD_PTYPE_INT_V:
		fprintf(stderr, "%s: Invalid data format for option '%s': '%s' (should be array of integers)\n", 
			cmd->program->name, opt->name, str);
		break;
	case CMD_PTYPE_DOUBLE_V:
		fprintf(stderr, "%s: Invalid data format for option '%s': '%s' (should be array of real numbers)\n", 
			cmd->program->name, opt->name, str);
		break;
	default:
		break;
	}
	return 0;
}

static int set_param_attr(AppInfo *cmd, CmdParam *par, CmdParamInstance *inst, const char *str)
{
	if (set_data(str, inst))
		return 1;

	switch (inst->type)
	{
	case CMD_PTYPE_INT:
		fprintf(stderr, "%s: Invalid data format for positional parameter '%s': '%s' (should be integer)\n", 
			cmd->program->name, par->name, str);
		break;
	case CMD_PTYPE_DOUBLE:
		fprintf(stderr, "%s: Invalid data format for positional parameter '%s': '%s' (should be real number)\n", 
			cmd->program->name, par->name, str);
		break;
	case CMD_PTYPE_FILEPATH:
	case CMD_PTYPE_FILELIST:
		fprintf(stderr, "%s: Invalid data format for positional parameter '%s': '%s' (should be file name)\n", 
			cmd->program->name, par->name, str);
		break;
	case CMD_PTYPE_FILEMASK:
		fprintf(stderr, "%s: Invalid data format for positional parameter '%s': '%s' (should be file mask)\n", 
			cmd->program->name, par->name, str);
		break;
	default:
		break;
	}
	return 0;
}

static CmdParamInstance *new_instance(CmdParamType type)
{
	CmdParamInstance *inst = (CmdParamInstance*)malloc(sizeof(CmdParamInstance));
	if (inst) {
		memset(inst, 0, sizeof(CmdParamInstance));
		inst->type = type;
	}
	return inst;
}

static void free_instance(CmdParamInstance *inst)
{
	int i;

	switch (inst->type)
	{
	case CMD_PTYPE_INT_V:
		free(inst->data.val.int_vec);
		break;
	case CMD_PTYPE_DOUBLE_V:
		free(inst->data.val.dbl_vec);
		break;
	case CMD_PTYPE_FILELIST:
	case CMD_PTYPE_PARAMLIST:
		for (i=0; i<inst->data.count; i++)
			free(inst->data.val.str_vec[i]);
		free(inst->data.val.str_vec);
		break;
	case CMD_PTYPE_STRING:
	case CMD_PTYPE_FILEMASK:
	case CMD_PTYPE_FILEPATH:
		free(inst->data.val.str_val);
		break;
	default:
		break;
	}
	free(inst);
}

static int data_geti(CmdParamInstance *inst, int *value)
{
	if (inst) {
		CmdParamData *data = &inst->data;
		switch (inst->type) 
		{
		case CMD_PTYPE_INT:
			if (value) *value = data->val.int_val;
			return 1;
		case CMD_PTYPE_INT_V:
			if (value) *value = data->val.int_vec[0];
			return 1;
		case CMD_PTYPE_DOUBLE:
			if (value) *value = (int)data->val.dbl_val;
			return 1;
		case CMD_PTYPE_DOUBLE_V:
			if (value) *value = (int)data->val.dbl_vec[0];
			return 1;
		case CMD_PTYPE_STRING:
			if (value) *value = atol(data->val.str_val);
			return 1;
		default:
			break;
		}
	}
	return 0;
}

static int data_getd(CmdParamInstance *inst, double *value)
{
	if (inst) {
		CmdParamData *data = &inst->data;
		switch (inst->type) 
		{
		case CMD_PTYPE_INT:
			if (value) *value = (double)data->val.int_val;
			return 1;
		case CMD_PTYPE_INT_V:
			if (value) *value = (double)data->val.int_vec[0];
			return 1;
		case CMD_PTYPE_DOUBLE:
			if (value) *value = data->val.dbl_val;
			return 1;
		case CMD_PTYPE_DOUBLE_V:
			if (value) *value = data->val.dbl_vec[0];
			return 1;
		case CMD_PTYPE_STRING:
			if (value) *value = atof(data->val.str_val);
			return 1;
		default:
			break;
		}
	}
	return 0;
}


static int data_gets(CmdParamInstance *inst, char **value)
{
	if (inst) {
		if (value) *value = inst->data.val.str_val;
		return 1;
	}
	return 0;
}

static int data_getiv(CmdParamInstance *inst, int **intv, int *intc)
{
	if (inst) {
		CmdParamData *data = &inst->data;
		switch (inst->type) 
		{
		case CMD_PTYPE_INT:
			if (intv) *intv = &data->val.int_val;
			if (intc) *intc = 1;
			return 1;
		case CMD_PTYPE_INT_V:
			if (intv) *intv = data->val.int_vec;
			if (intc) *intc = data->count;
			return 1;
		default:
			break;
		}
	}
	return 0;
}

static int data_getdv(CmdParamInstance *inst, double **dblv, int *dblc)
{
	if (inst) {
		CmdParamData *data = &inst->data;
		switch (inst->type) 
		{
		case CMD_PTYPE_DOUBLE:
			if (dblv) *dblv = &data->val.dbl_val;
			if (dblc) *dblc = 1;
			return 1;
		case CMD_PTYPE_DOUBLE_V:
			if (dblv) *dblv = data->val.dbl_vec;
			if (dblc) *dblc = data->count;
			return 1;
		default:
			break;
		}
	}
	return 0;
}

static int data_getsv(CmdParamInstance *inst, char ***strv, int *strc)
{
	if (inst) {
		CmdParamData *data = &inst->data;
		switch (inst->type) 
		{
		case CMD_PTYPE_STRING:
		case CMD_PTYPE_FILEMASK:
		case CMD_PTYPE_FILEPATH:
			if (strv) *strv = &data->val.str_val;
			if (strc) *strc = 1;
			return 1;
		case CMD_PTYPE_FILELIST:
			if (strv) *strv = data->val.str_vec;
			if (strc) *strc = data->count;
			return 1;
		default:
			break;
		}
	}
	return 0;
}

/************************   PUBLIC FUNCTIONS   ***************************/

/* Parses the command line and fills the information to 'cmd' structure */
void cmdline_init(AppInfo *cmd)
{
	int i;

	/* Init variables */
	if (cmd->options) {
		for (i=0; cmd->options[i].name; i++) 
			cmd->options[i].inst = NULL;
	}
	if (cmd->params) {
		for (i=0; cmd->params[i].name; i++) 
			cmd->params[i].inst = NULL;
	}
}

/* Parses the command line and fills the information to 'cmd' structure */
int cmdline_parse(int argc, char **argv, AppInfo *cmd)
{
	int i, res = 1, namelen, paramindex = 0;
	char *par, *ptr, *name;
	CmdOption *opt;

	/* Process command line parameters */
	i = 1;
	while (i<argc && res) {
		par = argv[i++];
		/* Option or file name */
		if (par[0]=='-') {
			if (par[1] == '-') {
				/* This is a long name of an option */
				par+=2;
				ptr = strchr(par, '=');
				if (ptr) {
					/* Long option with attribute value */
					namelen = (int)(ptr-par);
					if (namelen==0 || strlen(ptr+1)==0) {
						fprintf(stderr, "%s: Invalid syntax: '%s'\n", 
							cmd->program->name, par);
						res = 0;
						break;
					}
					name = (char*)malloc((namelen+1)*sizeof(char));
					if (name) {
						memcpy(name, par, (namelen)*sizeof(char));
						name[namelen] = '\0';
						opt = find_option_long(cmd->options, name);
						if (!opt) {
							/* Option not found */
							fprintf(stderr, "%s: Unknown option: '%s'\n", 
								cmd->program->name, name);
							res = 0;
						}
						if (res && opt && !opt->attribute) {
							/* This option do not expect value */
							fprintf(stderr, "%s: Unexpected value for option '%s': '%s'\n", 
								cmd->program->name, opt->name, ptr+1);
							res = 0;
						}
						if (res && opt) {
							if (!opt->inst)
								opt->inst = new_instance(opt->type);
							if (!set_option_attr(cmd, opt, opt->inst, ptr+1)) {
								/* Syntax error in option value */
								res = 0;
							}
						}
						free(name);
					}
				} else {
					/* Long option without attribute value */
					opt = find_option_long(cmd->options, par);
					if (!opt) { 
						/* Option not found */
						fprintf(stderr, "%s: Unknown option: '%s'\n", cmd->program->name, par);
						res = 0;
						break;
					}
					if (!opt->inst)
						opt->inst = new_instance(opt->type);
					if (opt->attribute) {
						if (i<argc) {
							/* Attribute value is in the next argument */
							if (!set_option_attr(cmd, opt, opt->inst, argv[i++])) {
								/* Syntax error in attribute value */
								res = 0;
							}
						} else {
							/* Missing option value */
							fprintf(stderr, "%s: Missing value for option '%s'\n", 
								cmd->program->name, opt->name);
							res = 0;
						}
					}
				}
			} else {
				/* This is an abbreviation */
				par++;
				while (res && *par!='\0') {
					opt = find_option_short(cmd->options, *par);
					if (!opt) {
						fprintf(stderr, "%s: Unknown option: '%c'\n", cmd->program->name, *par);
						res = 0;
						break;
					}
					if (!opt->inst)
						opt->inst = new_instance(opt->type);
					if (opt->attribute) {
						if (strlen(par+1)>0) {
							/* Attribute value follows the abbreviation */
							if (!set_option_attr(cmd, opt, opt->inst, par+1)) {
								/* Syntax error in attribute value */
								res = 0;
							}
						} else if (i<argc) {
							/* Attibute value in the next argument */
							if (!set_option_attr(cmd, opt, opt->inst, argv[i++])) { 
								/* Syntax error in attribute value */
								res = 0;
							}
						} else {
							/* Missing option value */
							fprintf(stderr, "%s: Missing value for option '%s'\n", 
								cmd->program->name, opt->name);
							res = 0;
						}
						break;
					}
					par++;
				}
			}
		} else {
			CmdParam *param = find_param_index(cmd->params, paramindex);
			if (param) {
				if (!param->inst) 
					param->inst = new_instance(param->type);
				if (!set_param_attr(cmd, param, param->inst, par)) {
					/* Syntax error in positional parameter */
					res = 0;
				}
				paramindex++;
			} else {
				/* Redundant positional parameter */
				fprintf(stderr, "%s: Redundant positional parameter: '%s'\n", 
					cmd->program->name, par);
				res = 0;
			}
		}
	}

	if (!res) {
		fprintf(stderr, "%s: Type '%s --help' to get the list of options\n",
			cmd->program->name, cmd->program->name);
	}
	return res;
}

/* Free memory allocated in the 'cmd' structure */
void cmdline_clean(AppInfo *cmd)
{
	int i;

	if (cmd->options) {
		for (i=0; cmd->options[i].name!=NULL; i++) {
			if (cmd->options[i].inst)
				free_instance(cmd->options[i].inst);
			cmd->options[i].inst = NULL;
		}
	}

	if (cmd->params) {
		for (i=0; cmd->params[i].name!=NULL; i++) {
			if (cmd->params[i].inst)
				free_instance(cmd->params[i].inst);
			cmd->params[i].inst = NULL;
		}
	}
}

/* Returns nonzero if the parameter is present */
int cmdline_isdef(AppInfo *cmd, const char *name)
{
	CmdOption *opt = find_option_long(cmd->options, name);
	return (opt!=NULL ? opt->inst!=NULL : 0);
}

/* Get parameter attribute value */
int cmdline_geti(AppInfo *cmd, const char *name, int *value)
{
	CmdOption *opt = find_option_long(cmd->options, name);
	if (opt)
		if (data_geti(opt->inst, value))
			return 1;
	if (value) *value = 0;
	return 0;
}

/* Get parameter attribute value */
int cmdline_getd(AppInfo *cmd, const char *name, double *value)
{
	CmdOption *opt = find_option_long(cmd->options, name);
	if (opt)
		if (data_getd(opt->inst, value))
			return 1;
	if (value) *value = 0.0;
	return 0;
}

/* Get parameter attribute value */
int cmdline_gets(AppInfo *cmd, const char *name, char **value)
{
	CmdOption *opt = find_option_long(cmd->options, name);
	if (opt)
		if (data_gets(opt->inst, value))
			return 1;
	if (value) *value = NULL;
	return 0;
}

/* Get parameter attribute value */
int cmdline_getiv(AppInfo *cmd, const char *name, int **intv, int *intc)
{
	CmdOption *opt = find_option_long(cmd->options, name);
	if (opt)
		if (data_getiv(opt->inst, intv, intc))
			return 1;
	if (intv) *intv = NULL;
	if (intc) *intc = 0;
	return 0;
}

/* Get parameter attribute value */
int cmdline_getdv(AppInfo *cmd, const char *name, double **dblv, int *dblc)
{
	CmdOption *opt = find_option_long(cmd->options, name);
	if (opt)
		if (data_getdv(opt->inst, dblv, dblc))
			return 1;
	if (dblv) *dblv = NULL;
	if (dblc) *dblc = 0;
	return 0;
}

void cmdline_dump(AppInfo *cmd)
{
	int i, j;

	if (cmd->options) {
		j = 0;
		printf("Options:\n");
		for (i=0; cmd->options[i].name; i++) {
			if (cmd->options[i].attribute) {
				if (cmd->options[i].inst) {
					printf("\t%s %s = ", cmd->options[i].name, cmd->options[i].attribute);
					dump_data(cmd->options[i].inst);
					printf("\n");
					j++;
				}
			} else {
				if (cmd->options[i].inst) {
					printf("\t%s\n", cmd->options[i].name);
					j++;
				}
			}
		}
		if (j==0) {
			printf("\tNone.\n");
		}
	}
	if (cmd->params) {
		j = 0;
		printf("Parameters:\n");
		for (i=0; cmd->params[i].name!=NULL; i++) {
			if (cmd->params[i].inst) {
				printf("\t%s = ", cmd->params[i].name);
				dump_data(cmd->params[i].inst);
				printf("\n");
				j++;
			}
		}
		if (j==0) {
			printf("\tNone.\n");
		}
	}
}

/* Prints help */
void cmdline_help(AppInfo *cmd)
{
	int i;

	if (cmd->options) {
		printf("Options:\n");
		for (i=0; cmd->options[i].name; i++) {
			printf("\t--%s", cmd->options[i].name);
			if (cmd->options[i].abbrev)
				printf(", -%c", cmd->options[i].abbrev);
			if (cmd->options[i].attribute)
				printf(" %s", cmd->options[i].attribute);
			printf("\n");
			printf("\t\t%s\n", cmd->options[i].description);
		}
		printf("\n");
	}
	if (cmd->params) {
		printf("Positional parameter(s):\n");
		for (i=0; cmd->params[i].name; i++) {
			printf("\t%s\n\t\t%s\n", cmd->params[i].name, cmd->params[i].description);
		}
		printf("\n");
	}
}

/* Returns nonzero if the parameter is present */
int cmdline_iscfgdef(AppInfo *cmd, const char *name)
{
	return find_option_key(cmd->options, name)!=NULL;
}

/* Get parameter attribute value */
int cmdline_getcfgi(AppInfo *cmd, const char *param, int *value)
{
	const char *data = find_option_key(cmd->options, param);
	if (data) {
		if (value) *value = atol(data);
		return 1;
	} else {
		if (value) *value = 0;
		return 0;
	}
}

/* Get parameter attribute value */
int cmdline_getcfgd(AppInfo *cmd, const char *param, double *value)
{
	const char *data = find_option_key(cmd->options, param);
	if (data) {
		if (value) *value = atof(data);
		return 1;
	} else {
		if (value) *value = 0.0;
		return 0;
	}
}

/* Get parameter attribute value */
int cmdline_getcfgs(AppInfo *cmd, const char *param, char **value)
{
	const char *data = find_option_key(cmd->options, param);
	if (data) {
		if (value) *value = (char*)data;
		return 1;
	} else {
		if (value) *value = NULL;
		return 0;
	}
}

/* Get parameter attribute value */
int cmdline_getcfgiv(AppInfo *cmd, const char *param, int **intv, int *intc)
{
	const char *data = find_option_key(cmd->options, param);
	if (data) {
		StrToIntV(data, intv, intc);
		return intv!=NULL;
	}
	if (intv) *intv = NULL;
	if (intc) *intc = 0;
	return 0;
}

/* Get parameter attribute value */
int cmdline_getcfgdv(AppInfo *cmd, const char *param, double **dblv, int *dblc)
{
	const char *data = find_option_key(cmd->options, param);
	if (data) {
		StrToDoubleV(data, dblv, dblc);
		return dblv!=NULL;
	}
	if (dblv) *dblv = NULL;
	if (dblc) *dblc = 0;
	return 0;
}

/* Is positional parameter defined? */
int cmdline_ispardef(AppInfo *cmd, const char *param)
{
	return find_param_name(cmd->params, param)!=NULL;
}

/* Get positional parameter value (integer number) */
int cmdline_getpari(AppInfo *cmd, const char *param, int *value)
{
	CmdParam *par = find_param_name(cmd->params, param);
	if (par)
		if (data_geti(par->inst, value))
			return 1;
	if (value) *value = 0;
	return 0;
}
	
/* Get positional parameter value (real number) */
int cmdline_getpard(AppInfo *cmd, const char *param, double *value)
{
	CmdParam *par = find_param_name(cmd->params, param);
	if (par)
		if (data_getd(par->inst, value))
			return 1;
	if (value) *value = 0.0;
	return 0;
}

/* Get positional parameter value (string) */
int cmdline_getpars(AppInfo *cmd, const char *param, char **value)
{
	CmdParam *par = find_param_name(cmd->params, param);
	if (par)
		if (data_gets(par->inst, value))
			return 1;
	if (value) *value = NULL;
	return 0;
}
	
/* Get positional parameter value (array of integer numbers) */
int cmdline_getparsv(AppInfo *cmd, const char *param, char ***array, int *count)
{
	CmdParam *par = find_param_name(cmd->params, param);
	if (par)
		if (data_getsv(par->inst, array, count))
			return 1;
	if (array) *array = NULL;
	if (count) *count = 0;
	return 0;
}
