#define SOLARIS

#include <sys/types.h>
#include <sys/stat.h>
#ifdef SOLARIS
#include <dirent.h>
#else
#include <sys/dir.h>
#endif
#include	<stdio.h>
#include	<string.h>
#include	<stdlib.h>
#include	<unistd.h>
#include	<errno.h>
#include	<fcntl.h>

#define BUFFER_SIZE 	2000
#define BUFFERP_SIZE	1000
#define NAME_SIZE	100

#define DO_FINISH	(-1)
#define DO_SKIP		(-2)

typedef struct file_dir {
	struct file_dir *	fd_parent;
	struct file_dir *	fd_children;
	struct file_dir *	fd_chnext;
	char			fd_name[NAME_SIZE];
	long			fd_flags;
#define FD_SOURCE		0x00000001
#define FD_WORK			0x00000002
#define FD_FILE			0x00000010
#define FD_DIR			0x00000020
#define FD_DELETE		0x00000100
#define FD_INSERT		0x00000200
#define FD_DONTMAKE		0x80000000
	struct file_dir *	fd_pair;
} FILE_DIR;

typedef struct append_file {
	struct append_file *	a_next;
	char			a_name[NAME_SIZE];
} APPEND_FILE;

typedef struct file_list {
	struct file_list *	fl_next;
	APPEND_FILE *		fl_append;
	int			fl_len;
	FILE_DIR *		fl_file_dir;
} FILE_LIST;

typedef struct stack {
	struct stack *		s_parent;
	char			s_name[NAME_SIZE];
	char *			s_data;
} STACK;

char * filename;
char makefile[] = "makefile";
FILE_DIR * source_dir, * work_dir;
FILE_LIST * fl_buffer;
STACK * stack_top;
long	start_of_make;
long	line_start;
int 	make_active;

char * dont_delete_list[100];


char *
fgets_c(char * buf,int size,FILE * fd)
{
char * s, * p,* q, * ret;
int cnt;
int f;
	p = buf;
	ret = 0;
	f = 0;
	for ( ; size > 0 ; ) {
		if ( fgets(p,size,fd) == 0 )
			break;
		if ( f ) {
			cnt = 0;
			for ( q = p ; *q == ' ' || *q == '\t' ; q ++ );
			memmove(p,q,strlen(q)+1);
		}
		ret = buf;
		cnt = 0;
		for ( ; *p ; p ++ , cnt ++ );
		if ( cnt < 2 )
			break;
		if ( *(p-2) != '\\' )
			break;
		p = p - 2;
		cnt -= 2;
		size -= cnt;
		f = 1;
	}
	return ret;
}


int
char_ptr_2_line(FILE * fd,int ptr)
{
int t;
int ret;
char * buf;
	t = ftell(fd);
	if ( ptr < 0)
		ptr = t;
	fseek(fd,0,SEEK_SET);
	ret = 0;
	buf = malloc(1000);
	for ( ; ; ) {
		if ( ftell(fd) >= ptr )
			break;
		if ( fgets(buf,1000,fd) == 0 )
			break;
		ret ++;
	}
	fseek(fd,t,SEEK_SET);
	return ret;
}

push_stack(char * name,char * data)
{
STACK * new;
	new = malloc(sizeof(STACK));
	new->s_parent = stack_top;
	new->s_data = malloc(strlen(data)+1);
	strcpy(new->s_name,name);
	strcpy(new->s_data,data);
	stack_top = new;
}

pop_stack()
{
STACK * f;
	if ( stack_top == 0 )
		return;
	f = stack_top;
	stack_top = f->s_parent;
	free(f->s_data);
	free(f);
}

STACK *
search_stack(char * name)
{
STACK * s;
	for ( s = stack_top ; s ; s = s->s_parent ) {
		if ( strcmp(s->s_name,name) == 0 )
			return s;
	}
	return 0;
}

parge_stack(STACK * p)
{
	for ( ; p != stack_top ; ) {
		pop_stack();
	}
}

char *
change_macro(char * org)
{
char * ret;
char * p1,* p2,* p3;
STACK * s;
int flag;
int bsize;
int start_flag;
int sub,len;
char ch;
	ret = malloc(2*BUFFER_SIZE);
	bsize = 2*BUFFER_SIZE;
	start_flag = 0;
start:
	p1 = org;
	p2 = ret;
	flag = 0;
	for ( ; ; ) {
		switch ( *p1 ) {
		case 0:
			*p2 = 0;
			if ( flag ) {
				if ( start_flag )
					free(org);
				start_flag = 1;
				org = ret;
				ret = malloc(bsize);
				goto start;
			}
			return ret;
		case '$':
			if ( *(p1+1) != '{' )
				goto def;
			for ( p3 = p1+2 ; *p3 && *p3 != '}' ; p3 ++ );
			if ( *p3 == 0 )
				goto def;
			ch = *p3;
			*p3 = 0;
			s = search_stack(p1+2);
			if ( s == 0 ) {
				*p3 = ch;
				goto def;
			}
			sub = p2 - ret;
			len = sub + strlen(s->s_data) + 2;
			if ( len > bsize ) {
				bsize = len;
				ret = realloc(ret,bsize);
				p2 = ret + sub;
			}
			strcpy(p2,s->s_data);
			for ( ; *p2 ; p2 ++ );
			*p3 = '}';
			p1 = p3+1;
			flag = 1;
			break;
		default:
		def:
			*p2++ = *p1++;
		}
		sub = p2 - ret;
		if ( sub+BUFFER_SIZE >= bsize ) {
			bsize += BUFFER_SIZE;
			ret = realloc(ret,bsize);
			p2 = ret + sub;
		}
	}
}


FILE_LIST *
new_file_list()
{
FILE_LIST * ret;
	ret = malloc(sizeof(FILE_LIST));
	ret->fl_append = 0;
	ret->fl_next = 0;
	ret->fl_len = 0;
	ret->fl_file_dir = 0;
	return ret;
}

free_file_list(FILE_LIST * f)
{
FILE_LIST * fl1;
	for ( ; f ; ) {
		fl1 = f;
		f = f->fl_next;
		free(fl1);
	}
}

FILE_LIST *
marge_file_list(FILE_LIST * fl1,FILE_LIST * fl2)
{
FILE_LIST ** flp1;
	if ( fl1 == 0 )
		return fl2;
	for ( flp1 = &fl1 ; *flp1 ; flp1 = &(*flp1)->fl_next );
	*flp1 = fl2;
	return fl1;
}


FILE_DIR *
search_file_dir(char * name,FILE_DIR * p,long flags)
{
FILE_DIR * n;
	if ( p ) {
	FILE_DIR * f;
		for ( f = p->fd_children ; f ; f = f->fd_chnext ) {
			if ( strcmp(f->fd_name,name) == 0 )
				return f;
		}
	}
	if ( flags&FD_DONTMAKE )
		return 0;
	n = malloc(sizeof(*n));
	n->fd_parent = p;
	n->fd_children = 0;
	n->fd_pair = 0;
	strcpy(n->fd_name,name);
	if ( p ) {
		n->fd_chnext = p->fd_children;
		p->fd_children = n;
	}
	else {
		n->fd_chnext = 0;
	}
	n->fd_flags = flags;
	return n;
}

FILE_DIR *
search_path(FILE_DIR * fd,char * path)
{
int len;
FILE_DIR * fd1, * fd2;
	len = strlen(fd->fd_name);
	if ( memcmp(fd->fd_name,path,len) )
		return 0;
	if ( len == strlen(path) )
		return fd;
	for ( fd1 = fd->fd_children ; fd1 ; fd1 = fd1->fd_chnext ) {
		fd2 = search_path(fd1,&path[len+1]);
		if ( fd2 )
			return fd2;
	}
	return 0;
}


FILE_LIST *
search_file_sufix(char * suf,FILE_DIR * fd)
{
FILE_LIST * fl1,* fl2;
FILE_LIST ** flp1;
FILE_DIR * fd1;
int len,len1;
char * ptr;
	fl1 = 0;
	len = strlen(suf);
	for ( fd1 = fd->fd_children ; fd1 ; fd1 = fd1->fd_chnext ) {
		if ( fd1->fd_flags&FD_DELETE )
			continue;
		if ( fd1->fd_flags&FD_DIR ) {
			fl2 = search_file_sufix(suf,fd1);
			for ( flp1 = &fl2 ; *flp1 ;
				flp1 = &(*flp1)->fl_next );
			*flp1 = fl1;
			fl1 = fl2;
			continue;
		}
		len1 = strlen(fd1->fd_name);
		if ( len1 < len )
			continue;
		ptr = &fd1->fd_name[len1-len];
		if ( strcmp(ptr,suf) == 0 ) {
			fl2 = new_file_list();
			fl2->fl_len = len1-len;
			fl2->fl_file_dir = fd1;
			fl2->fl_next = fl1;
			fl1 = fl2;
		}
	}
	return fl1;
}

FILE_LIST *
search_file_name(char * name,FILE_DIR * fd)
{
FILE_LIST * fl1,* fl2;
FILE_LIST ** flp1;
FILE_DIR * fd1;
int len,len1;
char * ptr;
	fl1 = 0;

	for ( fd1 = fd->fd_children ; fd1 ; fd1 = fd1->fd_chnext ) {

		if ( fd1->fd_flags&FD_DELETE )
			continue;
		if ( fd1->fd_flags&FD_DIR ) {
			fl2 = search_file_name(name,fd1);
			for ( flp1 = &fl2 ; *flp1 ;
				flp1 = &(*flp1)->fl_next );
			*flp1 = fl1;
			fl1 = fl2;
			continue;
		}
		if ( strcmp(fd1->fd_name,name) == 0 ) {
			fl2 = new_file_list();
			fl2->fl_len = strlen(name);
			fl2->fl_file_dir = fd1;
			fl2->fl_next = fl1;
			fl1 = fl2;
		}
	}
	return fl1;
}


divide_buffer(char * buf,char ** argv)
{
char *ptr;
char ** aptr;
int acnt;
int panc;
	ptr = buf+1;
	aptr = argv;
	acnt = BUFFERP_SIZE-1;
	for ( ; *ptr != '\n' ; ) {
		panc = 0;
		for ( ; *ptr == ' ' || *ptr == '\t' ; ptr ++ );
		if ( *ptr == '\n' || *ptr == '\r' )
			break;
		if ( *ptr == '"' ) {
			panc = 1;
			ptr ++;
		}
		*aptr = ptr;
		aptr ++;
		acnt --;
		if ( acnt < 0 ) {
			fprintf(stderr,"too many argument\n");
			exit(1);
		}
		if ( panc ) {
			for ( ; *ptr != '"' && *ptr != '\n' &&
				*ptr != '\r' ; ptr ++ );
			if ( *ptr == '"' ) {
				*ptr = 0;
				ptr ++;
			}
			else {
				fprintf(stderr,"unterminated \"\n");
				exit(1);
			}
		}
		else {
			for ( ; *ptr != ' ' && *ptr != '\t' &&
				*ptr != '\n' && *ptr != '\r' ; ptr ++ );
			if ( *ptr == '\n' || *ptr == '\r' ) {
				*ptr = 0;
				break;
			}
			*ptr = 0;
			ptr ++;
		}
	}
	*aptr = 0;
}

divide_buffer_p(char * buf,char ** argv)
{
char *ptr;
char ** aptr;
int acnt;
int panc;
	ptr = buf;
	aptr = argv;
	acnt = BUFFERP_SIZE-1;
	for ( ; *ptr != '\n' ; ) {
		panc = 0;
		for ( ; *ptr == ',' ; ptr ++ );
		if ( *ptr == '\n' || *ptr == '\r' )
			break;
		if ( *ptr == '"' ) {
			panc = 1;
			ptr ++;
		}
		*aptr = ptr;
		aptr ++;
		acnt --;
		if ( acnt < 0 ) {
			fprintf(stderr,"too many argument\n");
			exit(1);
		}
		if ( panc ) {
			for ( ; *ptr != '"' && *ptr != '\n' &&
				*ptr != '\r' ; ptr ++ );
			if ( *ptr == '"' ) {
				*ptr = 0;
				ptr ++;
			}
			else {
				fprintf(stderr,"unterminated \"\n");
				exit(1);
			}
		}
		else {
			for ( ; *ptr != ',' && *ptr != 0 ; ptr ++ );
			if ( *ptr == 0 ) {
				*ptr = 0;
				break;
			}
			*ptr = 0;
			ptr ++;
		}
	}
	*aptr = 0;
}


cmd_source(char ** argv)
{
DIR * dp;
char * ptr_buf;
	ptr_buf = change_macro(argv[1]);
	dp = opendir(ptr_buf);
	if ( dp == 0 ) {
		fprintf(stderr,"cannot open the dir \"%s\"\n",
			ptr_buf);
		free(ptr_buf);
		exit(1);
	}
	closedir(dp);
	source_dir = search_file_dir(ptr_buf,0,FD_DIR|FD_SOURCE);
	printf("source:%s\n",source_dir->fd_name);
	free(ptr_buf);
}

cmd_work(char ** argv)
{
DIR * dp;
char * ptr_buf;
	ptr_buf = change_macro(argv[1]);
	dp = opendir(ptr_buf);
	if ( dp == 0 ) {
		fprintf(stderr,"cannot open the dir \"%s\"\n",
			ptr_buf);
		free(ptr_buf);
		exit(1);
	}
	closedir(dp);
	work_dir = search_file_dir(ptr_buf,0,FD_DIR|FD_WORK);
	printf("work:%s\n",work_dir->fd_name);
	free(ptr_buf);
}


divide_dir(char * dir)
{
char * ptr;
int cnt;
int f;
	if ( strcmp(dir,".") == 0 ) {
		*dir = 0;
		return 0;
	}
	cnt = 1;
	f = 0;
	for ( ptr = dir ; *ptr ; ) {
		if ( *ptr == '/' ) {
			cnt ++;
			*ptr = 0;
			f = 1;
		}
		else f = 0;
		ptr ++;
	}
	if ( f ) {
		return cnt - 1;
	}
	return cnt;
}

cmd_insert(char ** argv)
{
int cnt;
FILE_DIR * s;
char * ptr;
char * macro_dir;
	if ( source_dir == 0 || work_dir == 0 ) {
		fprintf(stderr,"undefine source/work\n");
		exit(1);
	}
	macro_dir = change_macro(argv[1]);
	cnt = divide_dir(macro_dir);
	s = source_dir;
	ptr = macro_dir;
	for ( ; cnt ; cnt -- ) {
		s->fd_flags |= FD_DIR;
		s = search_file_dir(ptr,s,FD_SOURCE);
		for ( ; *ptr ; ptr ++ );
		ptr ++;
	}
	s->fd_flags |= FD_INSERT;
	free(macro_dir);
}

cmd_delete(char ** argv)
{
int cnt;
FILE_DIR * s;
char * ptr;
	if ( source_dir == 0 || work_dir == 0 ) {
		fprintf(stderr,"undefine source/work\n");
		exit(1);
	}
	cnt = divide_dir(argv[1]);
	s = source_dir;
	ptr = argv[1];
	for ( ; cnt ; cnt -- ) {
		s->fd_flags |= FD_DIR;
		s = search_file_dir(ptr,s,FD_SOURCE|FD_INSERT);
		for ( ; *ptr ; ptr ++ );
		ptr ++;
	}
	s->fd_flags &= ~FD_INSERT;
	s->fd_flags |= FD_DELETE;
}

print_dir(FILE_DIR * fd)
{
	if ( fd->fd_parent ) {
		print_dir(fd->fd_parent);
		printf("/%s",fd->fd_name);
	}
	else {
		printf("%s",fd->fd_name);
	}
}

list_dir(FILE_DIR * fd)
{
	if ( fd->fd_flags&(FD_INSERT|FD_DELETE) ) {
		if ( fd->fd_flags&FD_FILE )
			printf("FIL ");
		if ( fd->fd_flags&FD_DIR )
			printf("DIR ");
		if ( fd->fd_flags&FD_DELETE )
			printf("D");
		if ( fd->fd_flags&FD_INSERT )
			printf("I");
		printf("\t:");
		print_dir(fd);
		printf("\n");
	}
	for ( fd = fd->fd_children ; fd ; fd = fd->fd_chnext )
		list_dir(fd);
}

cmd_list(char ** argv)
{
	printf("SOURCE AERA\n");
	list_dir(source_dir);
	printf("WORK AERA\n");
	list_dir(work_dir);
}

char *
make_name(char * buf,FILE_DIR * fd)
{
char * ptr;
	if ( fd->fd_parent ) {
		ptr = make_name(buf,fd->fd_parent);
		*ptr = '/';
		ptr ++;
	}
	else ptr = buf;
	strcpy(ptr,fd->fd_name);
	for ( ; *ptr ; ptr ++ );
	return ptr;
}

char *
make_work_name(char * buf,FILE_DIR * fd)
{
char * ptr;
	if ( fd->fd_parent ) {
		ptr = make_work_name(buf,fd->fd_parent);
		*ptr = '/';
		ptr ++;
		strcpy(ptr,fd->fd_name);
		for ( ; *ptr ; ptr ++ );
		return ptr;
	}
	else {
		ptr = buf;
		strcpy(buf,work_dir->fd_name);
		for ( ; *ptr ; ptr ++ );
		return ptr;
	}
}

char *
make_work_name_plus(char * buf,FILE_DIR * fd,char * name)
{
char * ptr;
	make_work_name(buf,fd);
	ptr = buf;
	for ( ; *ptr ; ptr ++ );
	*ptr = '/';
	ptr ++;
	strcpy(ptr,name);
}

int
dont_delete(char * name)
{
int i;
	for ( i = 0 ; ; i ++ ) {
		if ( dont_delete_list[i] == 0 )
			return -1;
		if ( strcmp(dont_delete_list[i],name) == 0 )
			return 0;
	}
}

trace_fd(FILE_DIR * fd)
{
char buffer[1024];
struct stat sbuf;
DIR * dp;
struct dirent * d;
	make_name(buffer,fd);
	if ( stat(buffer, &sbuf) < 0 ) {
		fprintf(stderr,"\"%s\"",buffer);
		perror("");
		return 0;
	}
	switch (sbuf.st_mode & S_IFMT) {
	case S_IFREG:
		switch ( fd->fd_flags&(FD_FILE|FD_DIR) ) {
		case 0:
			fd->fd_flags |= FD_FILE;
			break;
		case FD_DIR:
			fprintf(stderr,"\"%s\" is file!!\n",
				buffer);
			exit(1);
		case FD_FILE:
			break;
		default:
			fprintf(stderr,"???\n");
			exit(1);
		}
		break;
	case S_IFDIR:
		switch ( fd->fd_flags&(FD_FILE|FD_DIR) ) {
		case 0:
			fd->fd_flags |= FD_DIR;
			break;
		case FD_FILE:
			fprintf(stderr,"\"%s\" is dir!!\n",
				buffer);
			exit(1);
		case FD_DIR:
			break;
		default:
			fprintf(stderr,"???\n");
			exit(1);
		}
		dp = opendir(buffer);
		if ( dp == 0 ) {
			fprintf(stderr,"cannot open the dir \"%s\"\n",
				buffer);
			exit(1);
		}
		for ( ; ; ) {
		FILE_DIR * fd2;
			d = readdir(dp);
			if ( d == 0 )
				break;
			if ( d->d_ino == 0 )
				continue;
			if ( d->d_name[0] == '.' )
				continue;
			if ( fd->fd_flags&FD_INSERT )
				fd2 = search_file_dir(d->d_name,fd,FD_SOURCE|FD_INSERT);
			else {
				fd2 = search_file_dir(d->d_name,fd,FD_SOURCE|FD_DONTMAKE);
				if ( fd2 == 0 )
					continue;
			}
			if ( !(fd2->fd_flags&FD_DELETE) )
				trace_fd(fd2);
		}
		closedir(dp);
		break;
/*
	case S_IFCHR:	break;
	case S_IFBLK:	break;
*/
	default:
		break;
	}
}

delete_file(char * buffer)
{
char buffer2[1024];

	sprintf(buffer2,"rm -r %s",buffer);
	system(buffer2);
}

trace_work(FILE_DIR * fd)
{
char buffer[1024];
char buffer2[1024];
struct stat sbuf;
DIR * dp;
struct dirent * d;
FILE_DIR * fd2;
int flag;
	fd->fd_flags |= FD_WORK;
	make_name(buffer,fd);
	if ( stat(buffer, &sbuf) < 0 ) {
		fprintf(stderr,"\"%s\"",buffer);
		perror("");
		return 0;
	}
	switch (sbuf.st_mode & S_IFMT) {
	case S_IFREG:
		switch ( fd->fd_flags&(FD_FILE|FD_DIR) ) {
		case FD_FILE:
			break;
		default:
			delete_file(buffer);
		}
		break;
	case S_IFDIR:
		switch ( fd->fd_flags&(FD_FILE|FD_DIR) ) {
		case FD_DIR:
			break;
		default:
			delete_file(buffer);
			mkdir(buffer,0755);
		}
	retry:
		dp = opendir(buffer);
		if ( dp == 0 ) {
			fprintf(stderr,"cannot open the dir \"%s\"\n",
				buffer);
			exit(1);
		}
		for ( ; ; ) {
			d = readdir(dp);
			if ( d == 0 )
				break;
			if ( d->d_ino == 0 )
				continue;
			if ( d->d_name[0] == '.' )
				continue;
			fd2 = search_file_dir(d->d_name,fd,FD_SOURCE|FD_DONTMAKE);
			
			if ( fd2 == 0 ) {
				sprintf(buffer2,"%s/%s",buffer,d->d_name);
				if ( stat(buffer2, &sbuf) < 0 ) {
					fprintf(stderr,"\"%s\"",buffer);
					perror("");
					return 0;
				}
				if ( (sbuf.st_mode & S_IFMT) != S_IFREG )
					goto f_delete;
			}
			else {
				if ( fd2->fd_flags&FD_DELETE ) {
				char * ptr;
				f_delete:
					if ( dont_delete(d->d_name)
							== 0 )
						goto next;
					sprintf(buffer2,
						"rm -r %s/%s",buffer,d->d_name);
					system(buffer2);
				}
				else trace_work(fd2);
			next:
				{}
			}
		}
		closedir(dp);
		flag = 0;
		for ( fd2 = fd->fd_children ; fd2 ; fd2 = fd2->fd_chnext ) {
			if ( fd2->fd_flags & FD_WORK )
				continue;
			if ( fd2->fd_flags & FD_DELETE )
				continue;
			if ( fd2->fd_flags & FD_FILE )
				continue;
			fd2->fd_flags |= FD_WORK;
			make_name(buffer2,fd2);
			mkdir(buffer2,0755);
			flag = 1;
			printf("make directory %s\n",buffer2);
		}
		if ( flag )
			goto retry;
		break;
/*
	case S_IFCHR:	break;
	case S_IFBLK:	break;
*/
	default:
		break;
	}
}

copy_dir(FILE_DIR * w,FILE_DIR * s)
{
FILE_DIR * fd1, * fd2;
	w->fd_pair = s;
	s->fd_pair = w;
	for ( fd1 = s->fd_children ; fd1 ; fd1 = fd1->fd_chnext ) {
		if ( fd1->fd_flags&FD_DELETE )
			continue;
		if ( fd1->fd_flags&FD_FILE )
			continue;
		fd2 = search_file_dir(fd1->fd_name,w,fd1->fd_flags);
		fd2->fd_pair = fd1;
		fd1->fd_pair = fd2;
		copy_dir(fd2,fd1);
	}
}

cmd_startpoint(char ** argv,FILE * fd)
{
	start_of_make = ftell(fd);
}

cmd_tree(char ** argv)
{
printf("tree\n");
	trace_fd(source_dir);
	copy_dir(work_dir,source_dir);
	trace_work(work_dir);
}

cmd_keep(char ** argv)
{
int i;
int j;
	for ( j = 0 ; dont_delete_list[j] ; j ++ );
	for ( i = 0 ; argv[i] ; i ++ ) {
		dont_delete_list[j] = malloc(strlen(argv[i])+1);
		strcpy(dont_delete_list[j],argv[i]);
		j ++;
	}
}


clear_file_list(FILE_LIST * fl)
{
FILE_LIST * fl1;
	for ( ; fl ; ) {
		fl1 = fl->fl_next;
		free(fl);
		fl = fl1;
	}
}


FILE_LIST *
_select_all(FILE_DIR * fd,FILE_LIST * fl)
{
FILE_DIR * fd1;
FILE_LIST * fl1;
	fd1 = fd->fd_children;
	for ( ; fd1 ; fd1 = fd1->fd_chnext ) {
		if ( fd1->fd_flags&FD_FILE ) {
			fl1 = new_file_list();
			fl1->fl_file_dir = fd1;
			fl1->fl_next = fl;
			fl = fl1;
		}
	}
	return fl;
}

FILE_LIST *
select_all()
{
FILE_LIST * fl;
	fl = _select_all(source_dir,0);
	return _select_all(work_dir,fl);
}

FILE_LIST * 
select_file(FILE_LIST * fl,int (*func)(),char * arg)
{
FILE_LIST * fl1, * fl2;
	fl1 = 0;
	for ( ; fl ; ) {
		fl2 = fl;
		fl = fl->fl_next;
		if ( (*func)(fl,arg) == 0 ) {
			fl2->fl_next = fl1;
			fl1 = fl2;
		}
		else {
			free(fl2);
		}
	}
	return fl1;
}

s_sufix(FILE_LIST * fl,char * arg)
{
int ptr;
	ptr = strlen(fl->fl_file_dir->fd_name)-strlen(arg);
	return strcmp(&fl->fl_file_dir->fd_name[ptr],arg);
}




s_dir(FILE_LIST * fl,char * arg)
{
int dcnt,i;
char * ptr;
FILE_DIR * fd1;
	dcnt = divide_dir(arg);
	if ( dcnt == 0 ) {
		if ( fl->fl_file_dir->fd_parent->fd_parent == 0 )
			return 0;
		return 1;
	}
	ptr = arg;
	for ( i = dcnt ; i ; i -- ) {
		for ( ; *ptr ; ptr ++ );
		arg ++;
	}
	fd1 = fl->fl_file_dir;
	for ( ; ptr != arg && fd1 ; ) {
		ptr -= 2;
		for ( ; *ptr && ptr != arg ; ptr -- );
		if ( *ptr == 0 )
			ptr ++;
		if ( strcmp(fd1->fd_name,ptr) )
			return 1;
		fd1 = fd1->fd_parent;
	}
	if ( fd1 == 0 && ptr == arg )
		return 0;
	return 1;
}

set_appendlist(
	char * filename,
	unsigned long * sm)
{
FILE * f;
char buffer[1024];
struct stat sbuf;
	f = fopen(filename,"r");
	if ( f == 0 ) {
		fprintf(stderr,"warning %s\n",filename);
		perror("");
		return;
	}
	for ( ; ; ) {
		if ( fscanf(f,"%s",buffer) < 0 )
			break;
		if ( stat(buffer,&sbuf) < 0 ) {
			fprintf(stderr,"%s:%s\n",filename,buffer);
			perror("command make 1");
			(*sm) = 0x7fffffff;
			continue;
		}
		if ( ((unsigned long)sbuf.st_mtime) > *sm )
			*sm = sbuf.st_mtime;
	}
	fclose(f);
}

int
get_sufix_ofs(char * buffer,char ** dest)
{
int len;
int i;
int ofs;
	len = strlen(buffer);
	for ( i = 0 ; dest[i] ; i ++ ) {
		ofs = strlen(dest[i]);
		if ( strcmp(&buffer[len-ofs],dest[i]) == 0 )
			return ofs;
	}
	return 0;
}


int
do_cmd(char * buffer)
{
char * ptr;
char * bufp[BUFFERP_SIZE];
char ** argv;
int ret;
	ptr = change_macro(buffer);
	divide_buffer(ptr,bufp);
	if ( bufp[0][0] == '(' ) {
		if ( cmd_condition(bufp[0]) == 0 ) {
			ret = DO_SKIP;
			goto end;
		}
		argv = &bufp[1];
	}
	else	argv= &bufp[0];
	if ( strcmp(argv[0],"do") == 0 ) {
		for ( ret = 0 ; memcmp(&buffer[ret],"do",2) ; ret ++ );
		ret += 2;
	}
	else if ( strcmp(argv[0],"finish") == 0 ) {
printf("DO FINISH %s\n",buffer);
		ret = DO_FINISH;
	}
	else if ( strcmp(argv[0],"set") == 0 ) {
		cmd_set(argv);
		ret = DO_SKIP;
	}
	else {
		fprintf(stderr,"invalid do command %s\n",buffer);
		exit(1);
	}
end:
	free(ptr);
	return ret;
}


make_file(FILE_LIST * fl,char ** dest,
		long start_ofs,long end_ofs,FILE * fd)
{
char buffer1[1024];
char buffer2[1024];
int i;
FILE_DIR * fd1,* fd2, * p;
APPEND_FILE * ap;
unsigned long dest_min,src_max;
struct stat sbuf;

	fd1 = fl->fl_file_dir;

	if ( fd1->fd_flags & FD_DELETE )
		return;
	strcpy(buffer1,fd1->fd_name);
	dest_min = 0xffffffff;
	make_name(buffer2,fd1);
	if ( stat(buffer2,&sbuf) < 0 ) {
		fprintf(stderr,"%s\n",buffer2);
		perror("command make 2");
		exit(1);
	}
	src_max = sbuf.st_mtime;
	p = fd1->fd_parent;
	if ( p->fd_flags&FD_WORK )
		make_name(buffer2,p);
	else	make_name(buffer2,p->fd_pair);
	strcpy(&buffer2[strlen(buffer2)],"/");
	strcpy(&buffer2[strlen(buffer2)],fd1->fd_name);
	strcpy(&buffer2[strlen(buffer2)],".ap");
	set_appendlist(buffer2,&src_max);
	for ( i = 0 ; dest[i] ; i ++ ) {
		strcpy(&buffer1[fl->fl_len],dest[i]);
		p = fd1->fd_parent;
		if( p->fd_flags&FD_WORK ) {
			fd2 = search_file_dir(buffer1,p,
					FD_WORK|FD_FILE|FD_DONTMAKE);
			if ( fd2 == 0 )
				make_active = 1;
			fd2 = search_file_dir(buffer1,p,FD_WORK|FD_FILE);
		}
		else {
			fd2 = search_file_dir(buffer1,p->fd_pair,
					FD_WORK|FD_FILE|FD_DONTMAKE);
			if ( fd2 == 0 )
				make_active = 1;
			fd2 = search_file_dir(buffer1,p->fd_pair,
							FD_WORK|FD_FILE);
		}
		make_name(buffer2,fd2);
		if ( stat(buffer2, &sbuf) < 0 ) {
			if ( errno == ENOENT )
				dest_min = 0;
			else {
				fprintf(stderr,"%s\n",buffer2);
				perror("command make 3");
			}
		}
		else if ( ((unsigned long)sbuf.st_mtime) < dest_min )
			dest_min = sbuf.st_mtime;
	}
	for ( ap = fl->fl_append ; ap ; ap = ap->a_next ) {
		if ( stat(ap->a_name,&sbuf) < 0 ) {
			fprintf(stderr,"%s\n",ap->a_name);
			perror("command make 4");
			exit(1);
		}
		if ( ((unsigned long)sbuf.st_mtime) > src_max )
			src_max = sbuf.st_mtime;
	}
	if ( src_max >= dest_min ) {
	char buffer[BUFFER_SIZE];
	char * ptr_buf;
	char * s;
	int now_ofs;
	STACK * p;
	int ofs;
	char * pp;
	int do_ret;
		p = stack_top;
		make_name(buffer,fd1);
		push_stack("from",buffer);
		make_name(buffer,fd2);

		ofs = get_sufix_ofs(buffer,dest);
		buffer[strlen(buffer)-ofs] = 0;
		push_stack("to",buffer);

		ofs = strlen(buffer)-1;
		for ( ; ofs >=0 &&
			buffer[ofs] != '\\' &&
			buffer[ofs] != '/' ;
			ofs -- );
		ofs ++;
		push_stack("to_leaf",&buffer[ofs]);

		make_name(buffer,fd1->fd_parent);
		push_stack("from_dir",buffer);
		make_name(buffer,fd2->fd_parent);
		push_stack("to_dir",buffer);
		fseek(fd,start_ofs,SEEK_SET);
		if ( fd1->fd_flags&FD_WORK )
			make_name(buffer,fd1->fd_parent->fd_pair);
		else	make_name(buffer,fd1->fd_parent);
		push_stack("src_dir",buffer);
		for ( ; ; ) {
			now_ofs = ftell(fd);
			if ( now_ofs >= end_ofs )
				break;
			s = fgets_c(buffer,BUFFER_SIZE,fd);
			if ( s == 0 )
				break;
			switch ( buffer[0] ) {
			case '.':
				do_ret =  do_cmd(buffer);
				break;
			case '@':
				fprintf(stderr,"make_file(1)\n");
				exit(1);
			default:
				do_ret = 0;
			}
			switch ( do_ret ) {
			case DO_SKIP:
				break;
			case DO_FINISH:
				goto finish;
			default:
				if ( do_ret < 0 ) {
					fprintf(stderr,"???\n");
					exit(1);
				}
				ptr_buf = change_macro(&buffer[do_ret]);
				for ( pp = ptr_buf ; *pp
					&& (
					*pp == '\t' ||
					*pp == ' ' ||
					*pp == '\r' ||
					*pp == '\n');
					pp ++ );
				if ( *pp == 0 ) {
					free(ptr_buf);
					break;
				}
				printf("%s",ptr_buf);
				if ( system(ptr_buf) != 0 ) {
					fprintf(stderr,"make error\n");
					exit(1);
				}
				free(ptr_buf);
				break;
			}
			continue;
		finish:
			break;
		}
		parge_stack(p);
printf("ACTIVE\n");
		make_active = 1;
	}
}


make_file_end(FILE_LIST * fl,char * dest_file,
		long start_ofs,long end_ofs,FILE * fd)
{
char buffer1[1024];
char buffer2[1024];
int i;
FILE_DIR * fd1,* fd2, * p;
APPEND_FILE * ap;
unsigned long dest_min,src_max;
struct stat sbuf;
char * from_list;
int from_size,from_bsize,len;


	if ( stat(dest_file, &sbuf) < 0 ) {
		if ( errno == ENOENT )
			dest_min = 0;
		else {
			fprintf(stderr,"%s\n",dest_file);
			perror("command make 5");
		}
	}
	else	dest_min = sbuf.st_mtime;

	from_size = 0;
	from_bsize = BUFFER_SIZE;
	from_list = malloc(from_bsize);
	from_list[0] = 0;

	src_max = 0;
	for ( ; fl ; fl = fl->fl_next ) {
		fd1 = fl->fl_file_dir;
		make_name(buffer2,fd1);
		len = strlen(buffer2);
		if ( from_bsize - strlen(from_list) < len+2 ) {
			from_bsize += len+2;
			from_list = realloc(from_list,from_bsize);
		}
		from_list[from_size] = ' ';
		from_size ++;
		strcpy(&from_list[from_size],buffer2);
		from_size = strlen(from_list);
		if ( stat(buffer2,&sbuf) < 0 ) {
			fprintf(stderr,"%s\n",buffer2);
			perror("command make 6");
			exit(1);
		}
		if ( src_max < ((unsigned long)sbuf.st_mtime) )
			src_max = sbuf.st_mtime;
		for ( ap = fl->fl_append ; ap ; ap = ap->a_next ) {
			if ( stat(ap->a_name,&sbuf) < 0 ) {
				fprintf(stderr,"%s\n",ap->a_name);
				perror("command make 7");
				exit(1);
			}
			if ( ((unsigned long)sbuf.st_mtime) > src_max )
				src_max = sbuf.st_mtime;
		}
	}
	if ( src_max >= dest_min ) {
	char buffer[BUFFER_SIZE];
	char * ptr_buf;
	char * s;
	int now_ofs;
	STACK * p;
	int ofs;
	int do_ret;
	char * pp;
		p = stack_top;
		push_stack("from",from_list);
		free(from_list);

		printf("DO line=%i\n",char_ptr_2_line(fd,start_ofs));
		fseek(fd,start_ofs,SEEK_SET);
		for ( ; ; ) {
			now_ofs = ftell(fd);
			if ( now_ofs >= end_ofs )
				break;
			s = fgets_c(buffer,BUFFER_SIZE,fd);
			if ( s == 0 )
				break;
			switch ( buffer[0] ) {
			case '.':
				do_ret = do_cmd(buffer);
				break;
			case '@':
				fprintf(stderr,"make_file(1)\n");
				exit(1);
			default:
				do_ret = 0;
			}
			switch ( do_ret ) {
			case DO_SKIP:
				break;
			case DO_FINISH:
				goto finish;
			default:
				if ( do_ret < 0 ) {
					fprintf(stderr,"????\n");
					exit(1);
				}
				ptr_buf = change_macro(&buffer[do_ret]);
				for ( pp = ptr_buf ; *pp
					&& (
					*pp == ' ' ||
					*pp == '\t' ||
					*pp == '\n' ||
					*pp == '\r');
					pp ++ );
				if ( *pp == 0 ) {
					free(ptr_buf);
					break;
				}
				printf("%s",ptr_buf);
				if ( system(ptr_buf) != 0 ) {
					fprintf(stderr,"make error\n");
					exit(1);
				}
				free(ptr_buf);
			}
			continue;
		finish:
			break;
		}
		parge_stack(p);
		make_active = 1;
	}
}


make_files(FILE_LIST* fl,char ** dest,long s,long e,FILE * fd)
{
	for ( ; fl ; fl = fl->fl_next )
		make_file(fl,dest,s,e,fd);
}

get_start2end(long * s,long * e,FILE * fd)
{
char * str;
char buffer[BUFFER_SIZE];
	*s = ftell(fd);
	for ( ; ; ) {
		*e = ftell(fd);
		str = fgets_c(buffer,BUFFER_SIZE,fd);
		if ( str == 0 )
			break;
		if ( buffer[0] == '@' )
			break;
	}
}


cmd_make(char ** argv,FILE * fd)
{
int i;
FILE_LIST * fl1,* fl2, * fl3;
int src_flag;
char * dest_sufix[10];
int dest_ptr;
long start_ofs,end_ofs;
char * dest_file;
FILE_DIR * fd1;
char * src_file;
	if ( start_of_make == -1 )
		start_of_make = line_start;
	src_flag = 0;
	dest_ptr = 0;
	fl1 = 0;
	dest_file = 0;
	for ( i = 1 ; argv[i] ; ) {
		if ( strcmp(argv[i],"sufix") == 0 ) {
			if ( src_flag ) {
			char * dir_name;
			char * suf;
				i ++;
				dir_name = change_macro(argv[i]);
				i ++;
				suf = change_macro(argv[i]);
				i ++;
				if ( strcmp(dir_name,"-" ) == 0 ) {
					fl3 = search_file_sufix(
							suf,source_dir);
					fl2 = search_file_sufix(
							suf,work_dir);
					fl3 = marge_file_list(fl3,fl2);
				}
				else {
					fd1 = search_path(source_dir,dir_name);
					if ( fd1 )
						fl3 = search_file_sufix(
							suf,fd1);
					else	fl3 = 0;
					fd1 = search_path(work_dir,dir_name);
					if ( fd1 )
						fl2 = search_file_sufix(
							suf,fd1);
					else	fl2 = 0;
					fl3 = marge_file_list(fl3,fl2);
				}
				fl1 = marge_file_list(fl3,fl1);
				free(dir_name);
				free(suf);
			}
			else {
				i ++;
				dest_sufix[dest_ptr] = change_macro(argv[i]);
				dest_ptr ++;
				i ++;
			}
		}
		else if ( strcmp(argv[i],"file") == 0 ) {
			if ( src_flag ) {
			char * dir_name;
				i ++;
				dir_name = change_macro(argv[i]);
				i ++;
				fd1 = search_path(source_dir,dir_name);
				if ( fd1 )
					fl3 = search_file_name(src_file,fd1);
				else	fl3 = 0;
				fd1 = search_path(work_dir,dir_name);

				for ( ; ; ) {
					if ( argv[i] == 0 )
						break;
					if ( strcmp(argv[i],"file") == 0 )
						break;
					if ( strcmp(argv[i],"sufix") == 0 )
						break;
					src_file = change_macro(argv[i]);
					i ++;
					if ( fd1 )
						fl2 = search_file_name(
							src_file,fd1);
					else	fl2 = 0;
					fl3 = marge_file_list(fl3,fl2);
					free(src_file);
				}
				fl1 = marge_file_list(fl3,fl1);
				free(dir_name);
			}
			else {
			int ofs;
				i ++;
				dest_file = change_macro(argv[i]);
				i ++;

				push_stack("to",dest_file);

				ofs = strlen(dest_file)-1;
				for ( ; ofs >=0 &&
					dest_file[ofs] != '\\' &&
					dest_file[ofs] != '/' ;
					ofs -- );
				ofs ++;
				push_stack("to_leaf",&dest_file[ofs]);

			}
		}
		else if ( strcmp(argv[i],"from") == 0 ) {
			src_flag = 1;
			dest_sufix[dest_ptr] = 0;
			i ++;
		}
		else {
		int ag;
			fprintf(stderr,"invalid argment \"%s\"\n",
				argv[i]);
			fprintf(stderr,"command ");
			for ( ag = 0 ; ag <= i ; ag ++ )
				fprintf(stderr,"%s ",argv[ag]);
			fprintf(stderr,"\n");

			i ++;
		}
	}
	get_start2end(&start_ofs,&end_ofs,fd);

	if ( dest_file )
		make_file_end(fl1,dest_file,start_ofs,end_ofs,fd);
	else	make_files(fl1,dest_sufix,start_ofs,end_ofs,fd);
	free_file_list(fl1);
	fseek(fd,end_ofs,SEEK_SET);
	for ( i = 0 ; i < 10 ; i ++ ) {
		if ( dest_sufix[i] == 0 )
			break;
		free(dest_sufix[i]);
	}
	if ( dest_file )
		free(dest_file);
}


cmd_set(char ** argv)
{
	push_stack(argv[1],argv[2]);
}

cmd_condition(char * arg)
{
char * ptr, * pp;
char * cargv[10];
int i;
int len;
int ret;
int fd;
	ptr = change_macro(arg);
	divide_buffer_p(ptr+1,cargv);
	for ( i = 0 ; cargv[i] ; i ++ ) {
		len = strlen(cargv[i]);
		if ( cargv[i][len-1] != ')' )
			continue;
		cargv[i][len-1] = 0;
		cargv[i+1] = 0;
		break;
	}
	if ( strcmp(cargv[0],"eq") == 0 ) {
		if ( strcmp(cargv[1],cargv[2]) == 0 )
			ret = 1;
		else	ret = 0;
	}
	else if ( strcmp(cargv[0],"neq") == 0 ) {
		if ( strcmp(cargv[1],cargv[2]) == 0 )
			ret = 0;
		else	ret = 1;
	}
	else if ( strcmp(cargv[0],"def") == 0 ) {
		if ( search_stack(cargv[1]) )
			ret = 1;
		else	ret = 0;
	}
	else if ( strcmp(cargv[0],"ndef") == 0 ) {
		if ( search_stack(cargv[1]) )
			ret = 0;
		else	ret = 1;
	}
	else if ( strcmp(cargv[0],"exist") == 0 ) {
		fd = open(cargv[1],O_RDONLY);
		if ( fd < 0 )
			ret = 0;
		else {
			ret = 1;
			close(fd);
		}
	}
	else if ( strcmp(cargv[0],"nexist") == 0 ) {
		fd = open(cargv[1],O_RDONLY);
		if ( fd < 0 )
			ret = 1;
		else {
			ret = 0;
			close(fd);
		}
	}
	else {
		fprintf(stderr,"invalid condition \"%s\"\n",
			arg);
		exit(1);
	}
	free(ptr);
	return ret;
}


commands(char ** argv,FILE * fd)
{
	if ( argv[0][0] == '(' ) {
		if ( cmd_condition(argv[0]) == 0 )
			return 0;
		argv ++;
	}
	if ( strcmp(argv[0],"source") == 0 )
		cmd_source(argv);
	else if ( strcmp(argv[0],"work") == 0 )
		cmd_work(argv);
	else if ( strcmp(argv[0],"insert") == 0 )
		cmd_insert(argv);
	else if ( strcmp(argv[0],"delete") == 0 )
		cmd_delete(argv);
	else if ( strcmp(argv[0],"list") == 0 )
		cmd_list(argv);
	else if ( strcmp(argv[0],"tree") == 0 )
		cmd_tree(argv);
	else if ( strcmp(argv[0],"make") == 0 )
		cmd_make(argv,fd);
	else if ( strcmp(argv[0],"startpoint") == 0 )
		cmd_startpoint(argv,fd);
	else if ( strcmp(argv[0],"set") == 0 )
		cmd_set(argv);
	else if ( strcmp(argv[0],"keep") == 0 )
		cmd_keep(argv);
	else if ( strcmp(argv[0],"stop") == 0 ) {
		fprintf(stderr,"stopped.\n");
		exit(0);
	}
	else {
		fprintf(stderr,"invalid command \"%s\"\n",
			argv[0]);
		exit(1);
	}
}

set_uname()
{
int p[2];
int id;
char buf[100];
int er;
	pipe(p);
	id = fork();
	if ( id == 0 ) {
		close(1);
		dup(p[1]);
		close(p[0]);
		system("uname");
		exit(0);
	}
	close(p[1]);
	er = read(p[0],buf,100);
	close(p[0]);
	if ( er < 0 )
		return -1;
	buf[er-1] = 0;
	push_stack("UNAME",buf);
	printf("uname : %s\n",buf);
}

scan_file()
{
FILE * fd;
char * s;
char buffer[BUFFER_SIZE];
char * bufp[BUFFERP_SIZE];
char * ret_buf;
	fd = fopen(filename,"r");
	if ( fd == 0 ) {
		fprintf(stderr,"%s\n",filename);
		perror("");
		exit(1);
	}
	set_uname();
start:
	make_active = 0;
	for ( ; ; ) {
		line_start = ftell(fd);
		s = fgets_c(buffer,BUFFER_SIZE,fd);
		if ( s == 0 )
			break;
		switch ( buffer[0] ) {
		case '@':
			divide_buffer(buffer,bufp);
			commands(bufp,fd);
			break;
		case '#':
			break;
		case '\n':
		case '\r':
			break;
		default:
			fprintf(stderr,"invalid character\n");
			break;
		}
	}
	if ( make_active ) {
		fseek(fd,start_of_make,SEEK_SET);
		goto start;
	}
	fclose(fd);
}


set_arg_stack(char * arg)
{
char * ptr;
char * data;
	ptr = malloc(strlen(arg)+1);
	strcpy(ptr,arg);
	for ( data = ptr ; *data && *data != '=' ; data ++ );
	if ( *data == 0 ) {
		fprintf(stderr,"invalid argumet %s\n",arg);
		free(ptr);
		exit(1);
	}
	*data = 0;
	data ++;
	push_stack(ptr,data);
}


int
equ_check(char * arg)
{
char * pp;
	for ( pp = arg ; *pp && *pp != '=' ; pp ++ );
	if ( *pp == 0 )
		return 1;
	return 0;
}

main(int argc,char ** argv)
{
int i;
	start_of_make = -1;
	filename = makefile;
	if ( argc > 1 ) {
		if ( equ_check(argv[1]) ) {
			filename = argv[1];
			i = 2;
		}
		else	i = 1;
		for ( ; i < argc ; i ++ )
			set_arg_stack(argv[i]);
	}
	scan_file();
}
