/**********************************************************************
 
	Copyright (C) 2003 Hirohisa MORI <joshua@nichibun.ac.jp>
 
	This program is free software; you can redistribute it 
	and/or modify it under the terms of the GLOBALBASE 
	Library General Public License (G-LGPL) as published by 

	http://www.globalbase.org/
 
	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.

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


#include	<stdio.h>
#include	<stdlib.h>
#include	<string.h>
#ifdef VA2
#include	<varargs.h>
#else
#include	<stdarg.h>
#endif
#include	"xl.h"
#include	"utils.h"

void
gf_conv_ii(XL_SEXP * s,void * d,void * d2)
{
int * pt;
L_CHAR ** u;
	pt = d;
	u = d2;
	*pt = s->integer.data;
	*u = s->integer.unit;
}

void
gf_conv_di(XL_SEXP * s,void * d,void * d2)
{
int * pt;
L_CHAR ** u;
	pt = d;
	u = d2;
	*pt = s->floating.data;
	*u = s->floating.unit;
}

void
gf_conv_if(XL_SEXP * s,void * d,void * d2)
{
float * pt;
L_CHAR ** u;
	pt = d;
	u = d2;
	*pt = s->integer.data;
	*u = s->integer.unit;
}

void
gf_conv_df(XL_SEXP * s,void * d,void * d2)
{
float * pt;
L_CHAR ** u;
	pt = d;
	u = d2;
	*pt = s->floating.data;
	*u = s->floating.unit;
}

void
gf_conv_id(XL_SEXP * s,void * d,void * d2)
{
double * pt;
L_CHAR * * u;
	pt = d;
	u = d2;
	*pt = s->integer.data;
	*u = s->integer.unit;
}

void
gf_conv_dd(XL_SEXP * s,void * d,void * d2)
{
double * pt;
L_CHAR ** u;
	pt = d;
	u = d2;
	*pt = s->floating.data;
	*u = s->floating.unit;
}

void
gf_conv_ss(XL_SEXP * s,void * d)
{
L_CHAR ** ptr;
int len1;
	ptr = d;
	*ptr = s->string.data;
}

void
gf_conv_sexp(XL_SEXP * s,void * d)
{
XL_SEXP ** p;
	p = d;
	*p = s;
}

typedef void (*conv_func)();

conv_func	cf[6][XLT_MAX] = {
	{
		0,
		0,
		0,
		0,
		0, /* string */
		0, /* integer */
		0 /* float */
	},
	{ /* integer */
		0,
		0,
		0,
		0,
		0, /* string */
		gf_conv_ii, /* integer */
		gf_conv_di /* float */
	},
	{ /* float */
		0,
		0,
		0,
		0,
		0, /* string */
		gf_conv_if, /* integer */
		gf_conv_df /* float */
	},
	{ /* double */
		0,
		0,
		0,
		0,
		0, /* string */
		gf_conv_id, /* integer */
		gf_conv_dd /* float */
	},
	{ /* string */
		0,
		0,
		0,
		0,
		gf_conv_ss, /* string */
		0, /* integer */
		0 /* float */
	},
	{ /* sexp */
		gf_conv_sexp,
		gf_conv_sexp,
		gf_conv_sexp,
		gf_conv_sexp,
		gf_conv_sexp,
		gf_conv_sexp,
		gf_conv_sexp
	}
};

int
set_data(XL_SEXP * s,
	 L_CHAR * f,int buf_type,void * d,void * d2,int * r)
{
XL_SEXP * field;
XL_SEXP * data;
XL_SEXP * ftype;
int data_type;
	for ( ; get_type(s)  ; s = cdr(s) ) {
		if ( get_type(s) != XLT_PAIR ) {
			*r = E_DB_FORMAT;
			return -1;
		}
		field = car(s);
		if ( get_type(field) != XLT_PAIR )
			continue;
		ftype = get_el(field,0);
		if ( get_type(ftype) != XLT_SYMBOL ) {
			*r = E_DB_FORMAT;
			return -1;
		}
		if ( l_strcmp(ftype->symbol.data,f) )
			continue;
		data = get_el(field,1);
		data_type = get_type(data);
		if ( cf[buf_type][data_type] == 0 ) {
			*r = E_TYPE_MISSMATCH;
			return 0;
		}
		(*cf[buf_type][data_type])(data,d,d2);
		*r = 0;
		return 0;
	}
	*r = E_NO_DATA;
	return -1;
}

int
get_field(XL_SEXP * s,...)
{
L_CHAR * f;
char * t;
void *d;
int * r;
va_list p;
int buf_type;
void * d2;

#ifdef VA2
	va_start(p);
#else
	va_start(p,s);
#endif
	for ( ; ; ) {
		f = va_arg(p,L_CHAR*);
		if ( f == 0 )
			break;
		t = va_arg(p,char*);
		if ( strcmp(t,"i") == 0 )
			buf_type = 1;
		else if ( strcmp(t,"f") == 0 )
			buf_type = 2;
		else if ( strcmp(t,"lf") == 0 )
			buf_type = 3;
		else if ( strcmp(t,"s") == 0 )
			buf_type = 4;
		else if ( strcmp(t,"sexp") == 0 )
			buf_type = 5;
		else {
			buf_type = -1;
		}
		d = va_arg(p,void *);
		r = va_arg(p,int *);
		if ( buf_type == -1 ) {
			*r = -2;
			return -1;
		}
		if ( buf_type == 1 || buf_type == 2 || buf_type == 3 )
			d2 = va_arg(p,void*);
		set_data(s,f,buf_type,d,d2,r);
	}
	va_end(p);
	return 0;
}
