/**********************************************************************
 
	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 <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include	"machine/include.h"
#include	"memory_debug.h"
#include	"utils.h"
#include	"xl.h"
#include	"xlerror.h"

void gc_gb_sexp();

typedef struct path_element {
	int			type;
#define PE_DIR			1
#define PE_FILE			2
#define PE_DIR_FILE		3
	char *			name;
	int			count;
} PATH_ELEMENT;

typedef struct path_pattern {
	struct path_pattern *	next;
	int			type;
#define PP_IGNORE		1
#define PP_ACCEPT		2
#define PP_TRACE		3
	int			path_len;
	PATH_ELEMENT *		path;
} PATH_PATTERN;

XL_SEXP * xl_Rule();

void
free_path_elements(PATH_PATTERN * pp)
{
int i;
	for ( i = 0 ; i < pp->path_len ; i ++ )
		d_f_ree(pp->path[i].name);
	d_f_ree(pp->path);
}

void
free_path_pattern_list(PATH_PATTERN * pp)
{
PATH_PATTERN * pp1;
	for ( ; pp ; ) {
		pp1 = pp;
		pp = pp->next;
		free_path_elements(pp1);
		d_f_ree(pp1);
	}
}

void
free_path_pattern(PATH_PATTERN * pp,int len)
{
int i;
	for ( i = 0 ; i < len ; i ++ )
		free_path_elements(&pp[i]);
	d_f_ree(pp);
}

void
print_path(PATH_PATTERN * pp)
{
int i;
	for ( ; pp ; pp = pp->next ) {
		printf("path:");
		if ( pp->path_len == 0 )
			printf(".");
		else for ( i = 0 ; i < pp->path_len ; i ++ ) {
			printf("%s",pp->path[i].name);
			if ( i != pp->path_len-1 || 
					pp->path[i].type
						== PE_DIR )
				printf("/");
		}
		printf("\n");
	}
}

void
print_path2(PATH_PATTERN * pp)
{
int i;
	printf("path:");
	if ( pp->path_len == 0 )
		printf(".");
	else for ( i = 0 ; i < pp->path_len ; i ++ ) {
		printf("%s",pp->path[i].name);
		if ( i != pp->path_len-1 ||
				pp->path[i].type == PE_DIR )
			printf("/");
	}
	printf("\n");
}

void
parse_path(PATH_PATTERN * ppp,L_CHAR * path)
{
int cnt,len;
L_CHAR * p;
L_CHAR * buf;
int st;
PATH_ELEMENT * pl;
	len = 0;
	st = 1;
	ppp->path = d_alloc(1,500);
	for ( ; ; ) {
		for ( p = path , cnt = 0 ;
				*p &&
				*p != '/';
				p ++, cnt ++);
		if ( cnt == 0 && st == 1 ) {
			ppp->path = d_re_alloc(ppp->path,
					(len+1)*sizeof(PATH_ELEMENT));
			pl = &ppp->path[len];
			pl->name = copy_str("$");
change_memtype(pl->name,1012);
			pl->type = PE_DIR;
		}
		else {
			buf = d_alloc((cnt+1)*sizeof(L_CHAR),500);
			memcpy(buf,path,cnt*sizeof(L_CHAR));
			buf[cnt] = 0;
			ppp->path = d_re_alloc(ppp->path,
					(len+1)*sizeof(PATH_ELEMENT));
			pl = &ppp->path[len];
			pl->name = ln_copy_str(std_cm,buf);
change_memtype(pl->name,1013);
			d_f_ree(buf);
			if ( *p == '/' )
				pl->type = PE_DIR;
			else if ( strcmp(pl->name,"**") == 0 )
				pl->type = PE_DIR_FILE;
			else	pl->type = PE_FILE;
		}
		len ++;
		st = 0;
		if ( *p == 0 )
			break;
		path = p + 1;
		if ( *path == 0 )
			break;
	}
	ppp->path_len = len;
}

XL_SEXP * 
xl_ignore_accept(int type,XLISP_ENV * env,XL_SEXP * s,
		PATH_PATTERN ** ppp,
		int len)
{
XL_SEXP * path;

	if ( list_length(s) != 2 )
		return get_error(
			s->h.file,
			s->h.line,
			XLE_SEMANTICS_INV_PARAM_LENGTH,
			l_string(std_cm,"Rule/Accept"),
			n_get_string("invalid param length"));
	path = eval(env,get_el(s,1));
	switch ( get_type(path) ) {
	case XLT_ERROR:
		return path;
	case XLT_STRING:
		break;
	default:
		return get_error(
			s->h.file,
			s->h.line,
			XLE_SEMANTICS_TYPE_MISSMATCH,
			l_string(std_cm,"Rule/Accept"),
			n_get_string("type missmatch"));
	}
	*ppp = d_re_alloc(*ppp,(len+1)*sizeof(**ppp));
	parse_path(&(*ppp)[len],path->string.data);
	(*ppp)[len].type = type;
	(*ppp)[len].next = 0;
	return 0;
}

char *
make_name(PATH_PATTERN * pp)
{
char * ret;
int len,i,p;
	for ( len = 0 , i = 0 ; i < pp->path_len ; i ++ )
		len += strlen(pp->path[i].name) + 1;
	ret = d_alloc(len+1,506);
	for ( p = 0 , i = 0 ; i < pp->path_len ; i ++ ) {
		strcpy(&ret[p],pp->path[i].name);
		p += strlen(pp->path[i].name);
		if ( i < pp->path_len-1 ) {
			ret[p] = '/';
			p ++;
		}
	}
	return ret;
}

PATH_PATTERN * 
add_element(PATH_PATTERN * pp,char * name,int type)
{
PATH_PATTERN * ret;
PATH_ELEMENT * pe;
int i;
	if ( pp ) {
		ret = d_alloc(sizeof(*ret),608);
		ret->path_len = pp->path_len + 1;
		ret->path = d_alloc(sizeof(PATH_ELEMENT)*ret->path_len,609);
		memcpy(ret->path,pp->path,sizeof(PATH_ELEMENT)*pp->path_len);
		for ( i = 0 ; i < pp->path_len ; i ++ )
{
			ret->path[i].name = copy_str(ret->path[i].name);
change_memtype(ret->path[i].name,1014);
}
		pe = &ret->path[pp->path_len];
		pe->type = type;
		pe->name = copy_str(name);
change_memtype(pe->name,1015);
		pe->count = 0;
		ret->next = 0;
		ret->type = 0;
	}
	else {
		ret = d_alloc(sizeof(*ret),610);
		ret->path_len = 1;
		ret->path = d_alloc(sizeof(PATH_ELEMENT)*ret->path_len,611);
		pe = &ret->path[0];
		pe->type = type;
		pe->name = copy_str(name);
change_memtype(pe->name,1016);
		pe->count = 0;
		ret->next = 0;
		ret->type = 0;
	}
	return ret;
}

PATH_PATTERN *
trace_path(PATH_PATTERN * given_pp)
{
char * buffer, * buffer2;
struct stat sbuf;
DIR * dp;
struct dirent * d;
PATH_PATTERN * pp,* pp1;
	if ( given_pp == 0 ) {
		buffer = copy_str(".");
change_memtype(buffer,1017);
	}
	else	buffer = make_name(given_pp);
	dp = opendir(buffer);
	if ( dp == 0 ) {
		fprintf(stderr,"cannot open the dir \"%s\"\n",
			buffer);
		return 0;
		er_panic("trace_path");
	}
	pp = 0;
	for ( ; ; ) {
		d = u_readdir(dp);
		if ( d == 0 )
			break;
		if ( d->d_name[0] == '.' )
			continue;
		buffer2 = d_alloc(strlen(buffer)+
				strlen(d->d_name)+10,
				503);
		sprintf(buffer2,"%s/%s",buffer,d->d_name);
		if ( stat(buffer2, &sbuf) < 0 ) {
			fprintf(stderr,"\"%s\"",buffer2);
			perror("");
			continue;
		}
		switch (sbuf.st_mode & S_IFMT) {
		case S_IFREG:
			pp1 = add_element(given_pp,d->d_name,PE_FILE);
			pp1->next = pp;
			pp = pp1;
			break;
		case S_IFDIR:
			pp1 = add_element(given_pp,d->d_name,PE_DIR);
			pp1->next = pp;
			pp = pp1;
		}
		d_f_ree(buffer2);
	}
	closedir(dp);
	d_f_ree(buffer);
	return pp;
}


void
reset_count(PATH_PATTERN * ia)
{
int i;
	for ( i = 0 ; i < ia->path_len ; i ++ ) {
		if ( strcmp(ia->path[i].name,"**") == 0 )
			ia->path[i].count = 1;
		else	ia->path[i].count = 0;
	}
}

int
count_up(PATH_PATTERN * ia,int len)
{
int i;
	i = ia->path_len-1;
	for ( ; ; ) {
		for ( ; i >= 0 ; i -- )
			if ( ia->path[i].count )
				break;
		if ( i < 0 )
			return 0;
		ia->path[i].count ++;
		if ( ia->path[i].count <= len )
			return 1;
		ia->path[i].count = 1;
		i --;
	}
}

int
compare_dir(char * n1,char * n2)
{
int * cnt;
int len,i,j,c,len1;
	len = strlen(n2);
	len1 = strlen(n1);
	cnt = d_alloc(len*sizeof(int),507);
	for ( i = 0; i < len ; i ++ )
		if ( n2[i] == '*' )
			cnt[i] = 1;
		else	cnt[i] = 0;
	for ( ; ; ) {
		j = 0;
		for ( i = 0 ; i < len && j < len1 ; i ++ ) {
			if ( n2[i] == '*' ) {
				for ( c = 0 ; c < cnt[i] ; c ++ , j ++ );
			}
			else {
				if ( n2[i] != n1[j] )
					goto neq;
				j ++;
			}
		}
		if ( i < len || j < len1 )
			goto neq;
		d_f_ree(cnt);
		return 1;
	neq:
		for ( i = len-1; i >= 0 ; i -- ) {
			if ( cnt[i] == 0 )
				continue;
			cnt[i] ++;
			if ( cnt[i] < len1 )
				break;
			cnt[i] = 1;
		}
		if ( i < 0 ) {
			d_f_ree(cnt);
			return 0;
		}
	}
}

int
_compare_path2(PATH_PATTERN * pp,PATH_PATTERN * ia,int type)
{
int i,j,cnt;
	j = 0;
	for ( i = 0 ; i < ia->path_len ; i ++ ) {
		if ( j >= pp->path_len )
			break;
		if ( ia->path[i].count == 0 ) {
			if ( ia->path[i].type == pp->path[j].type &&
				compare_dir(pp->path[j].name,ia->path[i].name)
					== 1 ) {
				j ++;
				continue;
			}
			return 0;
		}
		else {
			switch ( ia->path[i].type ) {
			case PE_DIR:
				for ( cnt = 0;
						cnt < ia->path[i].count;
						cnt ++ , j ++ )
					if ( pp->path[j].type == PE_FILE )
						return 0;
				break;
			case PE_DIR_FILE:
				for ( cnt = 0;
						cnt < ia->path[i].count;
						cnt ++ , j ++ );
				break;
			}
		}
	}
	if ( j < pp->path_len )
		return 0;
	if ( type == 1 ) {
		if ( j >= pp->path_len && i >= ia->path_len )
			return 1;
		return 0;
	}
	return 1;
}

int
_compare_path(PATH_PATTERN * pp,PATH_PATTERN * ia,int type)
{
int i;
	reset_count(ia);
	for ( ; ; ) {
/*
printf("count = ");
for ( i = 0 ; i < ia->path_len ; i ++ )
printf("%i ",ia->path[i].count);
printf("\n");
*/
		if ( _compare_path2(pp,ia,type) )
			return 1;
		if ( count_up(ia,pp->path_len) == 0 )
			return 0;
	}
}

int
compare_path(PATH_PATTERN * pp,PATH_PATTERN * ia_list,int len,int type)
{
int i;
	for ( i = 0 ; i < len ; i ++ ) {
		if ( _compare_path(pp,&ia_list[i],type) ) {
			switch ( ia_list[i].type ) {
			case PP_IGNORE:
				return 0;
			case PP_ACCEPT:
				return 1;
			default:
				er_panic("compare_path(1)");
			}
		}
	}
	return 0;
}

int
pp_length(PATH_PATTERN * pp)
{
int cnt;
	for ( cnt = 0 ; pp ; pp = pp->next , cnt ++ );
	return cnt;
}

PATH_PATTERN *
copy_pp(PATH_PATTERN * pp)
{
PATH_PATTERN * ret;
int i;
	ret = d_alloc(sizeof(*ret),615);
	ret->next = 0;
	ret->type = 0;
	ret->path_len = pp->path_len;
	ret->path = d_alloc(sizeof(PATH_ELEMENT)*ret->path_len,616);
	memcpy(ret->path,pp->path,sizeof(PATH_ELEMENT)*ret->path_len);
	for ( i = 0 ; i < ret->path_len ; i ++ )
{
		ret->path[i].name = copy_str(ret->path[i].name);
change_memtype(ret->path[i].name,1018);
}
	return ret;
}

PATH_PATTERN *
filter_path(PATH_PATTERN * pp,int len)
{
PATH_PATTERN * ret,* pp1,*pp2, * pp3,* pp4;
int flag;
	ret = 0;
	for ( ; ; ) {
		pp3 = 0;
		flag = 0;
		for ( pp1 = ret ; ; ) {
			if ( pp1 != 0 ) {
				if ( compare_path(pp1,pp,len,1) ) {
					pp2 = copy_pp(pp1);
					pp2->type = PP_TRACE;
					pp2->next = pp3;
					pp3 = pp2;
				}
				if ( pp1->path[pp1->path_len-1].type
						== PE_FILE )
					goto next;
			}
			if ( pp1 != 0 )
				if ( pp1->type == PP_TRACE )
					goto next;
			pp2 = trace_path(pp1);
			for ( ; pp2 ; ) {
					pp4 = pp2->next;
				if ( compare_path(pp2,pp,len,0) ) {
					pp2->next = pp3;
					pp3 = pp2;
					flag = 1;
				}
				else {
					pp2->next = 0;
					free_path_pattern_list(pp2);
				}
				pp2 = pp4;
			}
		next:
			if ( pp1 == 0 )
				break;
			pp1 = pp1->next;
			if ( pp1 == 0 )
				break;
		}
		free_path_pattern_list(ret);
		ret = pp3;
		if ( flag == 0 )
			return ret;
	}
}

XL_SEXP *
check_target(XL_SEXP * list,unsigned long to_time)
{
XL_SEXP * ret;
unsigned long from_time;
struct stat sbuf;
	switch ( get_type(list) ) {
	case XLT_ERROR:
		return list;
	case XLT_PAIR:
		for ( ; get_type(list) ; list = cdr(list) ) {
			ret = check_target(car(list),to_time);
			if ( get_type(ret) == XLT_ERROR )
				return ret;
		}
		return 0;
	case XLT_STRING:
		if ( stat(n_string(std_cm,list->string.data),&sbuf) < 0 )
			return get_error(
				list->h.file,
				list->h.line,
				XLE_SYSTEM_LOOP_BREAK,
				l_string(std_cm,"Target"),
				0);
		else	from_time = sbuf.st_mtime;
		if ( to_time < from_time )
			return 0;
		return get_error(
			list->h.file,
			list->h.line,
			XLE_SYSTEM_LOOP_BREAK,
			l_string(std_cm,"Target"),
			0);
	default:
		return get_error(
			list->h.file,
			list->h.line,
			XLE_SEMANTICS_TYPE_MISSMATCH,
			l_string(std_cm,"Target"),
			0);
	}
}

int
make_dir(L_CHAR * dir,int mode)
{
PATH_PATTERN * pp;
int i,len;
char * buf;
int er;


	pp = d_alloc(sizeof(*pp),617);
	parse_path(pp,dir);
	pp->next = 0;
	len = pp->path_len;
	for ( pp->path_len = 1 ; pp->path_len <= len ; pp->path_len ++ ) {
		if ( pp->path[pp->path_len-1].type != PE_DIR )
			break;
		buf = make_name(pp);
		if ( mkdir(buf,mode) < 0 ) {
			if ( errno != EEXIST ) {
				d_f_ree(buf);
				perror("buf");
				return -1;
			}
		}
		chmod(buf,mode);
		d_f_ree(buf);
	}
	pp->path_len = len;
	free_path_pattern_list(pp);
	return 0;
}

XL_SEXP *
xl_Exist(XLISP_ENV * e,XL_SEXP * s)
{
struct stat sbuf;
XL_SEXP * file;
	file = get_el(s,1);
	if ( get_type(file) != XLT_STRING )
		goto type_missmatch;
	if ( stat(n_string(std_cm,file->string.data),&sbuf) < 0 )
		return get_error(
			s->h.file,
			s->h.line,
			XLE_SYSTEM_LOOP_BREAK,
			l_string(std_cm,"Exist"),
			0);
	else	return 0;
type_missmatch:
	return get_error(
		s->h.file,
		s->h.line,
		XLE_SEMANTICS_TYPE_MISSMATCH,
		l_string(std_cm,"Exist"),
		0);
}

void
init_Exist(XLISP_ENV * env)
{
	set_env(env,l_string(std_cm,"Exist"),
		get_func_prim(xl_Exist,FO_APPLICATIVE,0,2,-1));
}

XL_SEXP *
xl_NotExist(XLISP_ENV * e,XL_SEXP * s)
{
struct stat sbuf;
XL_SEXP * file;
	file = get_el(s,1);
	if ( get_type(file) != XLT_STRING )
		goto type_missmatch;
	if ( stat(n_string(std_cm,file->string.data),&sbuf) < 0 )
		return 0;
	else	return get_error(
			s->h.file,
			s->h.line,
			XLE_SYSTEM_LOOP_BREAK,
			l_string(std_cm,"Exist"),
			0);
type_missmatch:
	return get_error(
		s->h.file,
		s->h.line,
		XLE_SEMANTICS_TYPE_MISSMATCH,
		l_string(std_cm,"Exist"),
		0);
}

void
init_NotExist(XLISP_ENV * env)
{
	set_env(env,l_string(std_cm,"NotExist"),
		get_func_prim(xl_NotExist,FO_APPLICATIVE,0,2,-1));
}

XL_SEXP *
xl_Target(XLISP_ENV * env,XL_SEXP * s,XLISP_ENV * a_env,XL_SYM_FIELD * sf)
{
struct stat sbuf;
XL_SEXP * to,* from;
unsigned long to_time;
int mode;
int dir_mode;
#define DM_MAKE		1
#define DM_DONTMAKE	2
	mode = 0755;
	dir_mode = DM_DONTMAKE;
	for ( ; sf ; sf = sf->next ) {
		if ( l_strcmp(sf->name,l_string(std_cm,"mode")) == 0 ) {
			sscanf(n_string(std_cm,sf->data),"%i",&mode);
		}
		else if ( l_strcmp(sf->name,l_string(std_cm,"dir")) == 0 ) {
			if ( l_strcmp(sf->data,
					l_string(std_cm,"make")) == 0 )
				dir_mode = DM_MAKE;
			else	dir_mode = DM_DONTMAKE;
		}
	}
	to = get_el(s,1);
	switch ( get_type(to) ) {
	case XLT_ERROR:
		return to;
	case XLT_STRING:
		break;
	default:
		goto type_missmatch;
	}
	if ( stat(n_string(std_cm,to->string.data),&sbuf) < 0 ) {
		if ( dir_mode == DM_MAKE )
			make_dir(to->string.data,mode);
		else 	return get_error(
				s->h.file,
				s->h.line,
				XLE_SYSTEM_LOOP_BREAK,
				l_string(std_cm,"Target"),
				0);
		return 0;
	}
	else {
		to_time = sbuf.st_mtime;
		return check_target(cdr(cdr(s)),to_time);
	}
type_missmatch:
	return get_error(
		s->h.file,
		s->h.line,
		XLE_SEMANTICS_TYPE_MISSMATCH,
		l_string(std_cm,"Target"),
		0);
}

void
init_Target(XLISP_ENV * env)
{
	set_env(env,l_string(std_cm,"Target"),
		get_func_prim(xl_Target,FO_APPLICATIVE,0,3,-1));
}

void
init_Rule(XLISP_ENV * env)
{
XLISP_ENV * c_env;
	c_env = new_env(0);
	init_Target(c_env);
	init_Exist(c_env);
	init_NotExist(c_env);

	set_env(env,l_string(std_cm,"Rule"),
		get_func_prim(xl_Rule,FO_NORMAL,c_env,2,-1));
}

XL_SEXP *
exec_1by1(PATH_PATTERN * pp,XLISP_ENV * env,XL_SEXP * s)
{
XL_SEXP * r;
PATH_PATTERN * pp1;
char * buf;
XLISP_ENV * nenv;
XL_SEXP * ss;
	for ( pp1 = pp ; pp1 ; pp1 = pp1->next ) {
		nenv = new_env(env);
		buf = make_name(pp1);
		set_env(nenv,l_string(std_cm,"from"),
			n_get_string(buf));
		d_f_ree(buf);
		r = 0;
		for ( ss = s ; get_type(ss) ; ss = cdr(ss) ) {
			gc_push(0,0,"exec_1by1");
			r = car(ss);
			if ( get_type(r) == XLT_ERROR ) {
				gc_pop(r,gc_gb_sexp);
				return r;
			}
			r = eval(nenv,r);
			if ( get_type(r) == XLT_ERROR ) {
				gc_pop(r,gc_gb_sexp);
				if ( r->err.code == XLE_SYSTEM_LOOP_BREAK )
					goto next;
				return r;
			}
			gc_pop(0,0);
		}
	next:	{}
	}
	return 0;
}

XL_SEXP *
exec_allfor1(PATH_PATTERN * pp,XLISP_ENV * env,XL_SEXP * s)
{
XL_SEXP * r;
PATH_PATTERN * pp1;
char * buf;
XLISP_ENV * nenv;
XL_SEXP * from;
	from = 0;
	for ( pp1 = pp ; pp1 ; pp1 = pp1->next ) {
		buf = make_name(pp1);
		cons(n_get_string(buf),from);
		d_f_ree(buf);
	}


	nenv = new_env(env);
	set_env(nenv,l_string(std_cm,"from"),from);
	r = 0;
	for ( ; get_type(s) ; s = cdr(s) ) {
		r = car(s);
		if ( get_type(r) == XLT_ERROR )
			return r;
		r = eval(nenv,r);
		if ( get_type(r) == XLT_ERROR ) {
			if ( r->err.code == XLE_SYSTEM_LOOP_BREAK )
				return 0;
			return r;
		}
	}
	return r;
}


XL_SEXP *
xl_Rule(XLISP_ENV * env,XL_SEXP * s,XLISP_ENV * a_env,XL_SYM_FIELD * sf)
{
XL_SEXP * r, * sym;
PATH_PATTERN * pp, * pp_ret;
int len;
XLISP_ENV * nenv;
XL_SEXP * ret;
int exec_type;
#define ET_1BY1		1
#define ET_ALLFOR1	2

	pp = d_alloc(1,501);
	len = 0;
	s = cdr(s);
	for ( ; get_type(s) ; s = cdr(s) ) {
		r = car(s);
		if ( get_type(r) == XLT_ERROR )
			return r;
		if ( get_type(r) != XLT_PAIR )
			break;
		sym = car(r);
		if ( get_type(sym) != XLT_SYMBOL ) {
			if ( get_type(sym) == XLT_ERROR )
				return sym;
			else
				break;
		}
		if ( l_strcmp(sym->symbol.data,
				l_string(std_cm,"Ignore")) == 0 ) {
			sym = xl_ignore_accept(PP_IGNORE,env,r,&pp,len);
			len ++;
			if ( get_type(sym) == XLT_ERROR )
				return sym;
		}
		else if ( l_strcmp(sym->symbol.data,
				l_string(std_cm,"Accept")) == 0 ) {
			sym = xl_ignore_accept(PP_ACCEPT,env,r,&pp,len);
			len ++;
			if ( get_type(sym) == XLT_ERROR )
				return sym;
		}
		else
			break;
	}
	pp_ret = filter_path(pp,len);
	free_path_pattern(pp,len);

	exec_type = ET_1BY1;
	for ( ; sf ; sf = sf->next ) {
		if ( l_strcmp(sf->name,l_string(std_cm,"target"))
				== 0 ) {
			if ( l_strcmp(sf->data,l_string(std_cm,
					"1by1")) == 0 )
				exec_type = ET_1BY1;
			else if ( l_strcmp(sf->data,l_string(std_cm,
					"allfor1")) == 0 )
				exec_type = ET_ALLFOR1;
		}
	}

	nenv = new_env_pair(a_env,env);

	switch ( exec_type ) {
	case ET_1BY1:
		ret = exec_1by1(pp_ret,nenv,s);
		break;
	case ET_ALLFOR1:
		ret = exec_allfor1(pp_ret,nenv,s);
		break;
	default:
		ret = 0;
	}
	free_path_pattern_list(pp_ret);
	return ret;
}
