/**********************************************************************
 
	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 <stdlib.h>
#include	<fcntl.h>
#include	<string.h>
#include	"memory_debug.h"
#include	"utils.h"




L_CHAR * script_path;


L_CHAR *_xlwhich(L_CHAR * path,L_CHAR * app);
L_CHAR*in_xlrc(char * home,char * file,L_CHAR * app);
L_CHAR *get_xlwhich(L_CHAR * app);

L_CHAR *
_xlwhich(L_CHAR * path,L_CHAR * app)
{
L_CHAR * p1, * p2, * p3;
int path_len;
L_CHAR * buf;
int fd;
char * filename,*_filename;
int i;
char * d = XLPATH_DELIM;
	path = ll_copy_str(path);
	buf = d_alloc((l_strlen(path) + l_strlen(app) + 10)*sizeof(L_CHAR));
	buf[0] = 0;
	for ( p1 = path ; p1 ; ) {
		p2 = p1;
		for ( ; *p2 ; p2 ++ ) {
			for ( i = 0 ; d[i] && d[i] != *p2 ; i ++ );
			if ( d[i] )
				break;
		}
		switch ( *p2 ) {
		case 0:
			p3 = 0;
			break;
		default:
			p3 = p2+1;
			*p2 = 0;
			break;
		}
		l_strcpy(buf,p1);
		path_len = l_strlen(buf);
		
		if ( '\\' != buf[path_len-1] && '/' != buf[path_len-1] ) {
			buf[path_len] = '/';
			path_len ++;
		}
		l_strcpy(&buf[path_len],app);
		filename = ln_copy_str(std_cm,buf);
		_filename = change_delim_str(filename);
		fd = u_open(_filename,O_RDONLY);
		if ( filename != _filename )
			d_f_ree(_filename);
		d_f_ree(filename);
	
		if ( fd < 0 ) {
			p1 = p3;
			continue;
		}
		u_close(fd);
		buf[path_len] = 0;
		goto end;
	}
	d_f_ree(buf);
	buf = 0;
end:
	d_f_ree(path);
	return buf;
}

XL_SEXP*
get_xlrc(char * home,char * file,L_CHAR * symbol)
{
L_CHAR * _home,*_file;
int len_home,len_file;
L_CHAR * filename;
int len;
STREAM* fd;
XL_SEXP * s, * t, * sym;
XL_SEXP * ret;
	_home = l_string(std_cm,home);
	len_home = l_strlen(_home);

	_file = l_string(std_cm,file);
	len_file = l_strlen(_file);

	filename = d_alloc(sizeof(L_CHAR)*(len_home + len_file + 10));

	l_strcpy(filename,_home);
	len = l_strlen(filename);
	if ( filename[len-1] != '/' ) {
		filename[len] = '/';
		len++;
	}

	l_strcpy(&filename[len],_file);

	fd = s_open_file(n_string(std_cm,filename),O_RDONLY);
	if ( fd == 0 ) {
		d_f_ree(filename);
		return 0;
	}
	ret = 0;
	gc_push(0,0,"get_xlrc");
	s = init_parse(fd,filename,filename);
	for ( ; get_type(s) == XLT_PAIR ; s = cdr(s) ) {
		t = car(s);
		if ( get_type(t) != XLT_PAIR )
			continue;
		sym = car(t);
		if ( get_type(sym) != XLT_SYMBOL )
			continue;
		if ( l_strcmp(sym->symbol.data,symbol) )
			continue;
		ret = cons(get_el(t,1),ret);
	}
	gc_pop(ret,gc_gb_sexp);
	s_close(fd);
	return ret;
}

L_CHAR*
in_xlrc(char * home,char * file,L_CHAR * app)
{
XL_SEXP * rec, * t;
L_CHAR * ret;
	ret = 0;
	gc_push(0,0,"in_xlrc");
	rec = get_xlrc(home,file,l_string(std_cm,"XLPATH"));
	for ( ; get_type(rec) == XLT_PAIR ; rec = cdr(rec) ) {
		t = car(rec);
		if ( get_type(t) == XLT_STRING )
			ret = _xlwhich(t->string.data,app);
		if ( ret )
			break;
	}
	gc_pop(0,0);
	return ret;
}

L_CHAR *
get_xlwhich(L_CHAR * app)
{
L_CHAR * ret;
char * home;
	ret = 0;
	home = u_getenv("XLPATH");
	if ( home )
		ret = _xlwhich(l_string(std_cm,home),app);
	if ( ret )
		return ret;
	home = get_homepath();
	if ( home )
		ret = in_xlrc(home,".xlrc",app);
	if ( ret )
		return ret;
	home = get_preference_path();
	if ( home )
		ret = in_xlrc(home,"xlrc",app);
	ret = in_xlrc("/",".xlrc",app);
	if ( ret )
		return ret;
	home = get_root_preference_path();
	if ( home )
		ret = in_xlrc(home,"xlrc",app);
	return ret;
}

L_CHAR *
get_script(L_CHAR * file,L_CHAR * script)
{
L_CHAR * buf;
int len1,len2,len3;
STREAM * st;
L_CHAR * path;
int i;

	len2 = l_strlen(script);

	/* if script exist? */

	st = s_open_file(n_string(std_cm,script),O_RDONLY);
	if ( st ) {
		s_close(st);
		return ll_copy_str(script);
	}

	if ( script[0] == '/' )
		return 0;

	/* if XL_FILE is defined? */

	if ( file ) {
		len1 = l_strlen(file);
		buf = d_alloc((len1+len2+1)*sizeof(L_CHAR));
		memcpy(buf,file,len1*sizeof(L_CHAR));
		for ( i = len1-1 ; i >= 0 && buf[i] != '/' ; i -- );
		if ( i >= 0 ) {
			memcpy(&buf[i+1],script,len2*sizeof(L_CHAR));
			buf[i+1+len2] = 0;
		}
		else {
			memcpy(buf,script,len2*sizeof(L_CHAR));
			buf[len2] = 0;
		}

		st = s_open_file(n_string(std_cm,buf),O_RDONLY);
		if ( st ) {
			s_close(st);
			return buf;
		}
	}

	/* if script_path exist? */

	if ( script_path ) {
		len1 = l_strlen(script_path);
		buf = d_alloc((len1+len2+1)*sizeof(L_CHAR));
		memcpy(buf,script_path,len1*sizeof(L_CHAR));
		memcpy(&buf[len1],script,len2*sizeof(L_CHAR));
		buf[len1+len2] = 0;
		st = s_open_file(n_string(std_cm,buf),O_RDONLY);
		if ( st ) {
			s_close(st);
			return buf;
		}
	}

	/* if xlpath exist? */


	path = get_xlwhich(script);
	if ( path == 0 )
		return 0;
	buf = ll_copy_str(path);
	len3 = l_strlen(buf);
	buf = d_re_alloc(buf,(len3+len2+1)*sizeof(L_CHAR));
	l_strcpy(&buf[len3],script);
	d_f_ree(path);
	return buf;
}

void
set_script_path(L_CHAR * script)
{
L_CHAR * path;
int len;
int i;
	if ( script == 0 ) {
		if ( script_path )
			d_f_ree(script_path);
		script_path = 0;
		return;
	}
	path = ll_copy_str(script);
	len = l_strlen(path);
	for ( i = len-1 ; i >= 0 ; i -- ) {
		if ( path[i] == '/' )
			break;
	}
	if ( script_path )
		d_f_ree(script_path);
	if ( i == -1 ) {
		script_path = nl_copy_str(std_cm,"./");
		d_f_ree(path);
	}
	else {
		path[i+1] = 0;
		script_path = path;
	}
}


L_CHAR *
get_script_path()
{
	return ll_copy_str(script_path);
}

typedef struct path_stack {
	struct path_stack *	next;
	L_CHAR *		path;
} PATH_STACK;

PATH_STACK * push_path_stack(PATH_STACK * p,L_CHAR * path,int len);
PATH_STACK * pop_path_stack(PATH_STACK * p);
L_CHAR * _optimize_path(PATH_STACK * ps,L_CHAR st);


PATH_STACK *
push_path_stack(PATH_STACK * p,L_CHAR * path,int len)
{
PATH_STACK * n;
	n = d_alloc(sizeof(*n));
	n->next = p;
	n->path = d_alloc((len+1)*sizeof(L_CHAR));
	memcpy(n->path,path,len*sizeof(L_CHAR));
	n->path[len] = 0;
	return n;
}

PATH_STACK *
pop_path_stack(PATH_STACK * p)
{
PATH_STACK * ret;
	ret = p->next;
	d_f_ree(p->path);
	d_f_ree(p);
	return ret;
}

L_CHAR *
_optimize_path(PATH_STACK * ps,L_CHAR st)
{
L_CHAR * g;
int g_len,ps_len;
	if ( ps == 0 || ps->path[0] == 0 )
		return nl_copy_str(std_cm,"");
	g = _optimize_path(ps->next,st);
	g_len = l_strlen(g);
	ps_len = l_strlen(ps->path);
	g = d_re_alloc(g,(g_len+ps_len+3)*sizeof(L_CHAR));
	if ( g_len || st == '/' ) {
		memcpy(&g[g_len+1],ps->path,ps_len*sizeof(L_CHAR));
		g[g_len] = '/';
		g[g_len+ps_len+1] = 0;
	}
	else {
		memcpy(&g[g_len],ps->path,ps_len*sizeof(L_CHAR));
		g[g_len+ps_len] = 0;
	}
	return g;
}

L_CHAR *
optimize_path(L_CHAR * path)
{
L_CHAR * p, * q;
PATH_STACK * ps;
L_CHAR * ret;

	ps = 0;
	for ( p = path ; *p ; ) {
		if ( memcmp(p,l_string(std_cm,"../"),3*sizeof(L_CHAR))
				== 0 ) {
			if ( ps )
				ps = pop_path_stack(ps);
			else	ps = push_path_stack(ps,p,2);
			p += 3;
			continue;
		}
		if ( memcmp(p,l_string(std_cm,"./"),2*sizeof(L_CHAR)) 
				== 0 ) {
			if ( ps == 0 )
				ps = push_path_stack(ps,p,1);
			p += 2;
			continue;
		}
		if ( l_strcmp(p,l_string(std_cm,"..")) == 0 ) {
			if ( ps )
				ps = pop_path_stack(ps);
			else	ps = push_path_stack(ps,p,2);
			p += 2;
			continue;
		}
		if ( l_strcmp(p,l_string(std_cm,".")) == 0 ) {
			if ( ps )
				ps = push_path_stack(ps,p,1);
			p += 1;
			continue;
		}
		for ( q = p ; *q && *q != '/' ; q ++ );
		ps = push_path_stack(ps,p,q - p);
		if ( *q == 0 )
			p = q;
		else	p = q + 1;
	}
	ret = _optimize_path(ps,path[0]);
	if ( path[l_strlen(path)-1] == '/' ) {
		ret[l_strlen(ret)] = '/';
		ret[l_strlen(ret)+1] = 0;
	}
	else {
		ret[l_strlen(ret)] = 0;
	}
	for ( ; ps ; )
		ps = pop_path_stack(ps);
	return ret;
}

L_CHAR *
get_absolute_path(L_CHAR * path)
{
L_CHAR * ret,* _ret;
int p_len,s_len;
	p_len = l_strlen(path);
	if ( path[0] == '/' )
		ret = ll_copy_str(path);
	else if ( script_path ) {
		s_len = l_strlen(script_path);
		ret = d_alloc((s_len+p_len+1)*sizeof(L_CHAR));
		memcpy(ret,script_path,s_len*sizeof(L_CHAR));
		memcpy(&ret[s_len],path,p_len*sizeof(L_CHAR));
		ret[s_len+p_len] = 0;
	}
	else 	ret = ll_copy_str(path);
	_ret = optimize_path(ret);
	d_f_ree(ret);
	return _ret;
}

L_CHAR *
get_relative_path(L_CHAR * path)
{
int len;
	len = l_strlen(script_path);
	if ( memcmp(script_path,path,len*sizeof(L_CHAR)) )
		return ll_copy_str(path);
	return ll_copy_str(&path[len]);
}



