

/***

mversion
-object [object-list for making]
-source [source list filename]
-prefix [for object-list ...]
-base [work dir] [src dir]
-except [except sourcecode dir. or file path]
-work [version work file]
-c [version file for c]
-xl [version file for xl]
-current [current version file]
-log [cvs.log file]
-app [application]
-update (force update)
-code [struct name and codetype]
-on / -off (enable / disenable the mversion)
***/

#include	<stdlib.h>
#include	<string.h>
#include	<stdio.h>
#include	<fcntl.h>
#include	<time.h>



typedef struct str_list {
	struct str_list *	next;
	char *			str;
	int *			rev;
} STR_LIST;

typedef struct arg_work {
	int	argc;
	char **	argv;
} ARG_WORK;

typedef struct gb_version {
	short	ver;
	short	rev1;
	short	rev2;
	char	status;
	char	type;
#define VT_BRA	1
#define VT_REL	2
#define VT_VER	3
} GB_VERSION;


typedef struct log {
	struct log	*	next;
	GB_VERSION		v;
	STR_LIST *		src;
	STR_LIST *		vwork_src;
	int			flags;
#define LF_INLOG	0x00000001
} LOG;

STR_LIST *	object_list;
STR_LIST *	source_list;
STR_LIST *	prefix_list;
char * work_dir;
char * src_dir;
STR_LIST *	except_list;
char * version_work_file;
char *	output_c;
char *	output_xl;
GB_VERSION	current_version;
STR_LIST *	abb;
char * message;
char * log_file;
LOG *		log_list;
char * log_base_dir;
char * log_src_dir;
char * app_name;
char update;
char * last_message;
char * struct_name = "gb_version";
char * code_type = "AP.code";


GB_VERSION target_version;

void
mem_test(char * str)
{
int i;
char ** d;
#define SIZ	10000

printf("mem %s\n",str);
	d = malloc(SIZ*sizeof(char*));
	for ( i = 0 ; i < SIZ ; i ++ )
		d[i] = malloc(i+1);
	for ( i = 0 ; i < SIZ ; i ++ )
		free(d[i]);
	free(d);
}


char *
copy_str(char * str)
{
char * ret;
	ret = malloc(strlen(str)+1);
	memcpy(ret,str,strlen(str)+1);
	return ret;
}


STR_LIST *
loading_file(char * filename)
{
FILE * fd;
char *buf,*s;
STR_LIST * ret, **sp, * n;
int len;
	fd = fopen(filename,"r");
	if ( fd == 0 )
		return 0;
	buf = malloc(1000);
	ret = 0;
	sp = &ret;
	for ( ; ; ) {
		s = fgets(buf,1000,fd);
		if ( s == 0 )
			break;
		len = strlen(buf);
		if ( len > 0 && buf[len-1] == '\n' )
			buf[len-1] = 0;
		n = malloc(sizeof(*n));
		n->str = copy_str(buf);
		n->next = 0;
		*sp = n;
		sp = &n->next;
	}
	fclose(fd);
	free(buf);
	return ret;
}


STR_LIST *
div_word(char * str)
{
int p,q;
STR_LIST * ret, ** sp, *n;
	ret =0;
	sp =&ret;
	p = 0;
	for ( ; ; ) {
		for ( ; str[p] &&
				(str[p] == ' ' ||
				str[p] == '\t');
				p ++ );
		if ( str[p] == 0 )
			break;
		q = p;
		for ( ; str[q] &&
				(str[q] != ' ' &&
				str[q] != '\t') ;
				q ++);
		n = malloc(sizeof(*n));
		n->str = malloc(q - p + 1);
		memcpy(n->str,&str[p],q - p);
		n->str[q-p] = 0;
		n->next = 0;
		*sp = n;
		sp = &n->next;
		p = q;
	}
	return ret;
}



void
free_str_list(STR_LIST * sl)
{
STR_LIST * s;
	for ( ; sl ; ) {
		s = sl;
		sl = sl->next;
		free(s->str);
		free(s);
	}
}

STR_LIST *
merge_str_list(STR_LIST * sl_1,STR_LIST * sl_2,int same_flag)
{
int cmp;
STR_LIST * ret, ** sp, * n, * n2;
	ret = 0;
	sp = &ret;
	for ( ; sl_1 && sl_2 ; ) {
		cmp = strcmp(sl_1->str,sl_2->str);
		if ( cmp < 0 ) {
			n = sl_1;
			sl_1 = n->next;
		}
		else if ( cmp > 0 ) {
			n = sl_2;
			sl_2 = n->next;
		}
		else {
			n = sl_1;
			sl_1 = n->next;
			if ( same_flag ) {
				n2 = sl_2;
				sl_2 = n2->next;
				free(n2->str);
				free(n2);
			}
		}
		n->next = 0;
		*sp = n;
		sp = &n->next;
	}
	if ( sl_1 )
		*sp = sl_1;
	else	*sp = sl_2;
	return ret;
}

void
divide_str_list(STR_LIST ** r1,STR_LIST ** r2,STR_LIST * in)
{
STR_LIST * ret1, * ret2, * n;
	ret1 = ret2 = 0;
	for ( ; in ; ) {
		n = in;
		in = n->next;
		n->next = ret1;
		ret1 = n;

		if ( in == 0 )
			break;
		n = in;
		in = n->next;
		n->next = ret2;
		ret2 = n;
	}
	*r1 = ret1;
	*r2 = ret2;
}

int
cmp_str_list(STR_LIST * s1,STR_LIST * s2)
{
	for ( ; s1 && s2 ; ) {
		if ( strcmp(s1->str,s2->str) )
			return 1;
		s1 = s1->next;
		s2 = s2->next;
	}
	if ( s1 || s2 )
		return 1;
	return 0;
}


STR_LIST *
sort_str_list(STR_LIST * sl,int same_flag)
{
STR_LIST * r1, * r2;
	if ( sl == 0 )
		return 0;
	if ( sl->next == 0 )
		return sl;
	divide_str_list(&r1,&r2,sl);
	return merge_str_list(
		sort_str_list(r1,same_flag),
		sort_str_list(r2,same_flag),
		same_flag);
}


int *
convert_rev(char * str)
{
int * ret;
int len;
char * p;
int n;
	ret = malloc(sizeof(int));
	p = str;
	len = 0;
	for ( ; *p ; ) {
		n = 0;
		for ( ; ; p ++ ) {
			if ( *p < '0' )
				break;
			if ( *p > '9' )
				break;
			n = n * 10 + *p - '0';
		}
		ret = realloc(ret,sizeof(int)*(len+1));
		ret[len] = n;
		len ++;
		for ( ; *p &&
			(*p < '0' ||
			*p > '9');
			p ++ );
	}
	ret = realloc(ret,sizeof(int)*(len+1));
	ret[len] = 0;
	return ret;
}

int
rev_len(int * rev)
{
int ret;
	ret = 0;
	for ( ; *rev ; rev ++ , ret ++ );
	return ret;
}

int
cmp_rev(int * r1,int *r2)
{
	for ( ; *r1 && *r2 ; ) {
		if ( *r1 > *r2 )
			return 1;
		if ( *r1 < *r2 )
			return -1;
		r1 ++;
		r2 ++;
	}
	if ( *r1 )
		return 1;
	if ( *r2 )
		return -1;
	return 0;
}

void
fprint_rev(FILE * fd,int * rev)
{
	for ( ; *rev ; rev ++ )
		fprintf(fd,"%i.",*rev);
}

int * 
copy_rev(int * rev)
{
int * ret;
int len;
	len = rev_len(rev);
	ret = malloc(sizeof(int)*(len+1));
	memcpy(ret,rev,sizeof(int)*(len+1));
	return ret;
}

char * check_num(short * num,char * ptr)
{
int n,d;
	if ( '0' > *ptr || *ptr > '9' ) {
		*num = -1;
		return 0;
	}
	n = 0;
	for ( ; *ptr ; *ptr ++ ) {
		d = *ptr - '0';
		if ( d < 0 || d > 9 )
			break;
		n = n* 10 + d;
	}
	*num = n;
	return ptr;
}


char
inc_status(char status)
{
	switch ( status ) {
	case 'a':
		return 'b';
	case 'b':
		return 'r';
	case 'r':
		return 0;
	default:
		fprintf(stderr,"?????\n");
		exit(1);
	}
	return 0;
}

int
convert_ver(GB_VERSION * v,char * _str)
{
char * ptr;
char punc;
char * str;
int ret;
	ret = -1;
	str = copy_str(_str);
	if ( memcmp(str,"bra-",4) == 0 ) {
		v->type = VT_BRA;
	}
	else if ( memcmp(str,"rel-",4) == 0 ) {
		v->type = VT_REL;
	}
	else if ( memcmp(str,"ver.",4) == 0 ) {
		v->type = VT_VER;
	}
	else 	goto err;
	punc = str[3];
	v->ver = str[4] - 'A';
	ret = -2;
	if ( v->ver < 0 || v->ver > 'Z' - 'A'  )
		goto err;
	ret = -3;
	if ( str[5] != punc )
		goto err;
	switch ( str[6] ) {
	case 'a':
	case 'b':
	case 'r':
		v->status = str[6];
		ptr = &str[7];
		break;
	default:
		v->status = 'r';
		ptr = &str[6];
		break;
	}
	ptr = check_num(&v->rev1,ptr);
	ret = -4;
	if ( v->rev1 < 0 )
		goto err;
	if ( *ptr != punc ) {
		v->rev2 = 0;
		goto ok;
	}
	ptr = check_num(&v->rev2,ptr+1);
	if ( v->rev2 < 0 )
		v->rev2 = 0;
	goto ok;
err:
	v->type = ret;
ok:
	free(str);
	return v->type;
}

int
cmp_version(GB_VERSION * v1,GB_VERSION * v2)
{
	if ( v1->ver < v2->ver )
		return -1;
	if ( v1->ver > v2->ver )
		return 1;
	if ( v1->status < v2->status )
		return -1;
	if ( v1->status > v2->status )
		return 1;
	if ( v1->rev1 < v2->rev1 )
		return -1;
	if ( v1->rev1 > v2->rev1 )
		return 1;
	if ( v1->rev2 < v2->rev2 )
		return -1;
	if ( v1->rev2 > v2->rev2 )
		return 1;
	return 0;
}

void
fprint_ver(FILE * fd,GB_VERSION * v)
{
char punc;
STR_LIST * s;
int ver;
	switch ( v->type ) {
	default:
		fprintf(fd,"err");
		return;
	case VT_BRA:
		fprintf(fd,"bra-");
		punc = '-';
		break;
	case VT_REL:
		fprintf(fd,"rel-");
		punc = '-';
		break;
	case VT_VER:
		fprintf(fd,"ver.");
		punc = '.';
		break;
	}
	fprintf(fd,"%c%c",
		v->ver + 'A',
		punc);
	switch ( v->status ) {
	case 'a':
		fprintf(fd,"a%02i",
			v->rev1);
		break;
	case 'b':
		fprintf(fd,"b%02i",
			v->rev1);
		break;
	case 'r':
		fprintf(fd,"%02i",
			v->rev1);
		break;
	default:
		fprintf(stderr,"???\n");
		exit(1);
	}
	if ( v->rev2 ) {
		fprintf(fd,"%c%02i",
			punc,
			v->rev2);
	}
	ver = v->ver;
	for ( s = abb ; s && ver ; ver -- , s = s->next );
	if ( s == 0 )
		return;
	fprintf(fd,"(%s)",s->str);
}

char *
get_arg(ARG_WORK * aw)
{
char * ret;
	if ( aw->argc == 0 )
		return 0;
	ret = *aw->argv++;
	aw->argc --;
	return ret;
}

void
pop_arg(ARG_WORK * aw)
{
	aw->argc ++;
	aw->argv --;
}

STR_LIST *
arg_2_str_list(ARG_WORK * aw)
{
STR_LIST * n;
STR_LIST * ret, ** sp;
char * arg;
	ret = 0;
	sp = &ret;
	for ( ; ; ) {
		arg = get_arg(aw);
		if ( arg == 0 )
			break;
		if ( arg[0] == '-' ) {
			pop_arg(aw);
			break;
		}
		n = malloc(sizeof(*n));
		n->str = copy_str(arg);
		n->next = 0;
		*sp = n;
		sp = &n->next;
	}
	return ret;
}


void
insert_log(GB_VERSION * v,char * target,int * rev,int flags)
{
LOG * lg, ** lgp;
int cmp;
STR_LIST * sl;
	for ( lgp = &log_list ; *lgp ; lgp = &(*lgp)->next ) {
		cmp = cmp_version(v,&(*lgp)->v);
		if ( cmp > 0 )
			break;
		if ( cmp < 0 )
			continue;
		lg = *lgp;
		goto next;
	}
	lg = malloc(sizeof(*lg));
	memset(lg,0,sizeof(*lg));
	lg->v = *v;
	lg->next = *lgp;
	*lgp = lg;
next:
	sl = malloc(sizeof(*sl));
	memset(sl,0,sizeof(*sl));
	sl->str = copy_str(target);
	sl->rev = copy_rev(rev);
	sl->next = lg->src;
	lg->src = sl;
	lg->flags |= flags;
}

void
mv_object(ARG_WORK * aw)
{
	object_list = arg_2_str_list(aw);
}

void
mv_prefix(ARG_WORK * aw)
{
	prefix_list = arg_2_str_list(aw);
}

void
mv_source(ARG_WORK * aw)
{
	source_list = arg_2_str_list(aw);
}

void
mv_except(ARG_WORK * aw)
{
	except_list = arg_2_str_list(aw);
}

void
mv_work(ARG_WORK * aw)
{
char * arg;
	arg = get_arg(aw);
	if ( arg == 0 ) {
		fprintf(stderr,"unexpected arg end\n");
		exit(1);
	}
	version_work_file = copy_str(arg);
}

void
mv_base(ARG_WORK * aw)
{
char * arg;
	arg = get_arg(aw);
	if ( arg == 0 ) {
		fprintf(stderr,"unexpected arg end\n");
		exit(1);
	}
	work_dir = copy_str(arg);
	arg = get_arg(aw);
	if ( arg == 0 ) {
		fprintf(stderr,"unexpected arg end\n");
		exit(1);
	}
	src_dir = copy_str(arg);
}

void
mv_xl(ARG_WORK * aw)
{
char * arg;
	arg = get_arg(aw);
	if ( arg == 0 ) {
		fprintf(stderr,"unexpected arg end\n");
		exit(1);
	}
	output_xl = copy_str(arg);
}

void
mv_c(ARG_WORK * aw)
{
char * arg;
	arg = get_arg(aw);
	if ( arg == 0 ) {
		fprintf(stderr,"unexpected arg end\n");
		exit(1);
	}
	output_c = copy_str(arg);
}


void
mv_make_source_list()
{
STR_LIST * n;
STR_LIST * p;
STR_LIST ** sp;
int n_len,p_len,w_len,s_len;
char * str;
int pp;
int fd;

	if ( source_list )
		goto last;
	if ( object_list == 0 ) {
		fprintf(stderr,"required object list or sourcelist\n");
		exit(1);
	}
	source_list = object_list;
	object_list = 0;
	if ( work_dir ) {
		w_len = strlen(work_dir);
		s_len = strlen(src_dir);
		for ( n = source_list ; n ; n = n->next ) {
			n_len = strlen(n->str);
			if ( n_len < w_len )
				continue;
			if ( memcmp(work_dir,n->str,w_len) ) {
				fprintf(stderr,"not in work dir %s\n",
					n->str);
				continue;
			}
			str = malloc(s_len + n_len - w_len+ 1);
			strcpy(str,src_dir);
			strcpy(&str[s_len],&n->str[w_len]);
			free(n->str);
			n->str = str;
		}
	}
	if ( prefix_list ) {
		for( n = source_list ; n ; n = n->next ) {
			n_len = strlen(n->str);
			str = copy_str(n->str);
			for ( pp = n_len-1;
				pp >= 0 &&
				str[pp] != '.';
				pp -- );
			if ( pp < 0 ) {
				fprintf(stderr,"prefix is required %s\n",
					n->str);
				continue;
			}
			for ( p = prefix_list ; p ; p = p->next ) {
				p_len = strlen(p->str);
				if ( p_len > n_len )
					continue;
				str = realloc(str,pp + p_len + 1);
				strcpy(&str[pp],p->str);
				fd = open(str,O_RDONLY);
				if ( fd < 0 )
					continue;
				close(fd);
				free(n->str);
				n->str = str;
				break;
			}
			if ( p == 0 ) {
				fprintf(stderr,"there is no file \"%s\" of prefixed\n",
					n->str);
				continue;
			}
		}
	}
last:
	if ( except_list ) {
		for ( sp = &source_list ; *sp ; ) {
			n = *sp;
			n_len = strlen(n->str);
			for ( p = except_list ; p ; p = p->next ) {
				p_len = strlen(p->str);
				if ( p_len > n_len )
					continue;
				if ( memcmp(n->str,p->str,p_len) )
					continue;
				*sp = n->next;
				free(n->str);
				free(n);
				break;
			}
			if ( p == 0 )
				sp = &(*sp)->next;
		}
	}
}

void
mv_current(ARG_WORK * aw)
{
STR_LIST * sl;
char * arg;
	arg = get_arg(aw);
	if ( arg == 0 ) {
		fprintf(stderr,"current version file is requried\n");
		exit(1);
	}
	sl = loading_file(arg);
	if ( sl == 0 ) {
		fprintf(stderr,"current version file is empty or nothing\n");
		exit(1);
	}
	convert_ver(&current_version,sl->str);
	sl = sl->next;
	if ( sl == 0 ) {
		message = "";
		return;
	}
	message = copy_str(sl->str);
	abb = sl->next;
}


void
mv_log(ARG_WORK * aw)
{
char * arg;
	arg = get_arg(aw);
	if ( arg == 0 ) {
		fprintf(stderr,"unexpected arg end\n");
		exit(1);
	}
	log_file = copy_str(arg);
	arg = get_arg(aw);
	if ( arg == 0 ) {
		fprintf(stderr,"unexpected arg end\n");
		exit(1);
	}
	log_base_dir = copy_str(arg);
	arg = get_arg(aw);
	if ( arg == 0 ) {
		fprintf(stderr,"unexpected arg end\n");
		exit(1);
	}
	log_src_dir = copy_str(arg);
}

void
mv_app(ARG_WORK * aw)
{
char * arg;
int p;
	arg = get_arg(aw);
	if ( arg == 0 ) {
		fprintf(stderr,"application name is required\n");
		exit(1);
	}
	for ( p = strlen(arg)-1 ; p >= 0 &&
			arg[p] != '/' &&
			arg[p] != '\\' &&
			arg[p] != ':' ;
			p -- );
	p ++;
	app_name = copy_str(&arg[p]);
}

void
mv_msg(ARG_WORK * aw)
{
STR_LIST * sl, * sl_1;
int len;
char * p;
	sl = arg_2_str_list(aw);
	len = 0;
	for ( sl_1 = sl ; sl_1 ; sl_1 = sl_1->next )
		len += strlen(sl_1->str) + 1;
	last_message = malloc(len+1);
	p = last_message;
	for ( sl_1 = sl ; sl_1 ; sl_1 = sl_1->next ) {
		strcpy(p,sl_1->str);
		p += strlen(p);
		*p = ' ';
		p ++;
	}
	*p = 0;
	free_str_list(sl);
}

void
mv_code(ARG_WORK * aw)
{
STR_LIST * sl;
	sl = arg_2_str_list(aw);
	if ( sl == 0 )
		goto end;
	struct_name = copy_str(sl->str);
	sl = sl->next;
	if ( sl == 0 )
		goto end;
	code_type = copy_str(sl->str);
end:
	free_str_list(sl);
}


STR_LIST *
mv_rcs(STR_LIST * s)
{
char * target;
STR_LIST * wrd;
GB_VERSION v;
int * rev;
int * max_rev;
int flag;
int b_len,s_len,w_len;
	s = s->next;
	wrd = div_word(s->str);
	if ( strcmp(wrd->str,"Working") )
		goto err;
	b_len = strlen(log_base_dir);
	if ( memcmp(wrd->next->next->str,log_base_dir,b_len) == 0 ) {
		s_len = strlen(log_src_dir);
		w_len = strlen(wrd->next->next->str);
		target = malloc(s_len + w_len - b_len + 1);
		strcpy(target,log_src_dir);
		strcpy(&target[s_len],
			&wrd->next->next->str[b_len]);
	}
	else	target = copy_str(wrd->next->next->str);
	free_str_list(wrd);
	for ( ; s ; s = s->next ) {
		wrd = div_word(s->str);
		if ( wrd == 0 )
			continue;
		if ( strcmp(wrd->str,"symbolic") ) {
			free_str_list(wrd);
			continue;
		}
		free_str_list(wrd);
		s = s->next;
		break;
	}
	if ( s == 0 )
		goto err;
	max_rev = 0;
	flag = 0;
	for ( ; s ; s = s->next ) {
		wrd = div_word(s->str);
		if ( wrd == 0 )
			continue;
		if ( strcmp(wrd->str,"keyword") == 0 ) {
			free_str_list(wrd);
			break;
		}
		convert_ver(&v,wrd->str);
		if ( v.ver != current_version.ver ) {
			free_str_list(wrd);
			continue;
		}
		rev = convert_rev(wrd->next->str);
		free_str_list(wrd);
		if ( v.type < 0 ) {
			free(rev);
			continue;
		}
		if ( max_rev == 0 || cmp_rev(rev,max_rev) > 0 ) {
			if ( max_rev )
				free(max_rev);
			max_rev = rev;
		}
		insert_log(&v,target,rev,LF_INLOG);
	}
	for ( ; s ; s = s->next ) {
		wrd = div_word(s->str);
		if ( wrd == 0 )
			continue;
		if ( memcmp(wrd->str,"====",4) == 0 ) {
			free_str_list(wrd);
			break;
		}
		if ( strcmp(wrd->str,"revision") == 0 ) {
			rev = convert_rev(wrd->next->str);
			if ( max_rev == 0 || 
				rev_len(rev) == rev_len(max_rev) &&
					cmp_rev(rev,max_rev) > 0 ) {
				if( max_rev )
					free(max_rev);
				max_rev = rev;
				flag = 1;
			}
		}
		free_str_list(wrd);
	}
	if ( flag ) {
		insert_log(&current_version,target,max_rev,0);
	}
	free(target);
	free(max_rev);
	return s;
err:
	fprintf(stderr,"invalid format cvs.log\n");
	exit(1);
}

void
mv_loading_log()
{
STR_LIST * s;
STR_LIST * str;
LOG * lg;
	s = loading_file(log_file);
	if ( s == 0 ) {
		fprintf(stderr,"cannot read logfile %s\n",log_file);
		exit(1);
	}
printf("\tLOG FILE LOADED\n");
	for ( ; s ; ) {
		str = div_word(s->str);
		if ( str == 0 ) {
			s = s->next;
			continue;
		}
		if ( strcmp(str->str,"RCS") == 0 ) {
			s = mv_rcs(s);
			free_str_list(str);
			continue;
		}
		else {
			s = s->next;
		}
	}
	for ( lg = log_list ; lg ; lg = lg->next )
		lg->src = sort_str_list(lg->src,1);
}


void
mv_loading_work_file()
{
STR_LIST * sl, * top, * sl_2;
GB_VERSION v;
LOG * lg;
int flags;
	top = loading_file(version_work_file);
	if ( top == 0 )
		return;
	for ( sl = top ; sl ; ) {
		if ( sl->str[0] != '@' ) {
			sl = sl->next;
			continue;
		}
		sl = sl->next;
		if ( sl->str[0] == '*' ) {
			convert_ver(&v,&sl->str[1]);
			if ( v.type < 0 )
				continue;
			flags = 0;
			for ( lg = log_list ; lg ; lg = lg->next )
				if ( cmp_version(&lg->v,&v) == 0 )
					break;
			if ( lg == 0 )
				for ( lg = log_list ; lg ; lg = lg->next )
					if ( cmp_version(&lg->v,
						&current_version) == 0 )
						break;
		}
		else {
			convert_ver(&v,sl->str);
			if ( v.type < 0 )
				continue;
			flags = LF_INLOG;
			for ( lg = log_list ; lg ; lg = lg->next )
				if ( cmp_version(&lg->v,&v) == 0 )
					break;
		}
		if ( lg == 0 ) {
			fprintf(stderr,"uncorrespond version in workfile\n");
			continue;
		}
		sl = sl->next;
		if ( sl == 0 ) {
			lg->vwork_src = 0;
			break;
		}
		if ( sl->str[0] == '@' )
			lg->vwork_src = 0;
		else {
		 	lg->vwork_src = sl;
			if ( sl->next == 0 )
				break;
			for ( ; sl->next && sl->next->str[0] != '@';
					sl = sl->next );
			if ( sl->next == 0 )
				break;
			sl_2 = sl->next;
			sl->next = 0;
			sl = sl_2;
		}
	}
}

void
mv_save_work_file()
{
FILE * fd;
LOG * lg;
STR_LIST * sl;
int ff;
	ff = open(version_work_file,O_RDWR|O_TRUNC|O_CREAT,0644);
	close(ff);
	fd = fopen(version_work_file,"w+");
	if ( fd == 0 ) {
		fprintf(stderr,"cannot open the file %s\n",
			version_work_file);
	}
	for ( lg = log_list ; lg ; lg = lg->next ) {
		fprintf(fd,"@\n");
		if ( (lg->flags & LF_INLOG) == 0 )
			fprintf(fd,"*");
		lg->v.type = VT_VER;
		fprint_ver(fd,&lg->v);
		fprintf(fd,"\n");
		for ( sl = lg->vwork_src ; sl ; sl = sl->next )
			fprintf(fd,"%s\n",sl->str);

	}
	fclose(fd);
}

void
mv_insert_source_list()
{
int cmp;
LOG * lg;
	if ( log_list == 0 ) {
		fprintf(stderr,"log is unloaded\n");
		exit(1);
	}
	cmp = cmp_version(&log_list->v,&current_version);
	if ( cmp ) {
		if ( cmp > 0 ) {
			fprintf(stderr,"invalid current version!\n");
			fprintf(stderr,"current is too small\n");
			exit(1);
		}
		if ( log_list->v.ver == current_version.ver &&
			log_list->v.status == current_version.status &&
			log_list->v.rev1 == current_version.rev1 &&
			log_list->v.rev2+1 == current_version.rev2 )
			goto ok;
		if ( log_list->v.ver == current_version.ver &&
			log_list->v.status == current_version.status &&
			log_list->v.rev1+1 == current_version.rev1 &&
			current_version.rev2 == 0 )
			goto ok;
		if ( log_list->v.ver == current_version.ver &&
			inc_status(log_list->v.status)
					 == current_version.status &&
			current_version.rev1 == 0 &&
			current_version.rev2 == 0 )
			goto ok;
		if ( log_list->v.ver+1 == current_version.ver &&
			current_version.status == 'a' &&
			current_version.rev1 == 0  &&
			current_version.rev2 == 0 )
			goto ok;
		fprintf(stderr,"invalid current version!\n");
		fprintf(stderr,"current is uncontinous from latest version\n");
		exit(1);
	ok:
		lg = malloc(sizeof(*lg));
		memset(lg,0,sizeof(*lg));
		lg->v = current_version;
		lg->next = log_list;
		log_list = lg;
	}
	log_list->vwork_src = sort_str_list(source_list,1);
}

void
mv_version_check()
{
LOG * lg, * lg_target, * lg_old;
STR_LIST * sl;
STR_LIST * sll, * sll_1;
int cmp;
	if ( log_list->next == 0 ) {
		target_version = log_list->v;
		goto end;
	}
	sl = log_list->vwork_src;
	sll = log_list->src;
	for ( ; sl && sll ; ) {
		cmp = strcmp(sl->str,sll->str);
		if ( cmp == 0 ) {
			target_version = log_list->v;
			goto end;
		}
		if ( cmp < 0 ) {
			sl = sl->next;
			continue;
		}
		sll = sll->next;
	}
	lg_target = log_list->next;
	if( lg_target->vwork_src &&
			cmp_str_list(log_list->vwork_src,
				lg_target->vwork_src) ) {
		target_version = log_list->v;
		goto end;
	}
	if ( lg_target->next == 0 ) {
		target_version = lg_target->v;
		goto end;
	}
	lg_old = lg_target;
	for ( lg = lg_target->next ; lg ; ) {
		if ( lg->vwork_src &&
			cmp_str_list(log_list->vwork_src,
				lg->vwork_src) ) {
			target_version = lg_old->v;
			goto end;
		}
		sl = log_list->vwork_src;
		sll = lg->src;
		sll_1 = lg_target->src;
		for ( ; sl ; sl = sl->next ) {
			for ( ; sll ; ) {
				cmp = strcmp(sl->str,sll->str);
				if ( cmp < 0 ) {
					target_version = lg_old->v;
					goto end;
				}
				if( cmp > 0 ) {
					sll = sll->next;
					continue;
				}
				break;
			}
			for ( ; sll_1 ; ) {
				cmp = strcmp(sl->str,sll_1->str);
				if( cmp < 0 ) {
					target_version = lg_old->v;
					goto end;
				}
				if( cmp > 0 ) {
					sll_1 = sll_1->next;
					continue;
				}
				break;
			}
			if ( sll == 0 || sll_1 == 0 ) {
				target_version = lg_old->v;
				goto end;
			}
			if ( cmp_rev(sll->rev,sll_1->rev) ) {
				target_version = lg_old->v;
				goto end;
			}
		}
		lg_old = lg_old->next;
		lg = lg->next;
	}
	target_version = lg_old->v;
end:
	target_version.type = VT_VER;
	printf("\tVERSION=");
	fprint_ver(stdout,&target_version);
	printf("\n");
}

int
check_update(char * file)
{
STR_LIST * sl;
GB_VERSION v;
STR_LIST * wrd;
int ret;
	ret = 0;
	sl = loading_file(file);
	wrd = 0;
	if ( sl ) {
		wrd = div_word(sl->str);
		if ( wrd ) {
			if ( wrd->next ) {
				convert_ver(&v,wrd->next->str);
				if( v.type < 0 ) {
					ret = 1;
				}
				else if ( cmp_version(&v,
						&target_version) ) {
					ret = 1;
				}
				else	ret = 0;
			}
		}
		else	ret = 1;
	}
	else	ret = 1;
	free_str_list(sl);
	free_str_list(wrd);
	return ret;
}

void
mv_save_xl_file()
{
FILE * fd;
struct tm * tp;
time_t tt;

	if ( output_xl == 0 )
		return;
	if ( update == 0 && check_update(output_xl) == 0 )
		return;
	tt = time(0);
	tp = localtime(&tt);

	fd = fopen(output_xl,"w+");
	fprintf(fd,"<!-- ");
	fprint_ver(fd,&target_version);
	fprintf(fd," -->\n");
	fprintf(fd,"<?xml version=\"1.0\" ?>\n");
	fprintf(fd,"<version-info>\n");
	fprintf(fd,"\t<version>");
		fprint_ver(fd,&target_version);
		fprintf(fd,"</version>\n");
	fprintf(fd,"\t<code.type>%s</code.type>\n",
			code_type);
	fprintf(fd,"\t<application>%s</application>\n",
			app_name);
	fprintf(fd,"\t<publisher>%s</publisher>\n",
			message);
	fprintf(fd,"\t<date>%i-%i-%i</date>\n",
			tp->tm_year+1900,
			tp->tm_mon+1,
			tp->tm_mday);
	fprintf(fd,"\t<message>%s</message>\n",
		last_message);
	fprintf(fd,"</version-info>\n\n");
	fclose(fd);
}

void
mv_save_c_file()
{
FILE * fd;
struct tm * tp;
time_t tt;
	if ( output_c == 0 )
		return;
	if ( update == 0 && check_update(output_c) == 0 )
		return;
	tt = time(0);
	tp = localtime(&tt);

	fd = fopen(output_c,"w+");
	fprintf(fd,"/* ");
	fprint_ver(fd,&target_version);
	fprintf(fd," */\n\n\n");

	fprintf(fd,"#include \"version.h\"\n\n\n");
	fprintf(fd,"VERSION %s = {\n",struct_name);
	fprintf(fd,"\t\"%s\",\n",code_type);
	fprintf(fd,"\t\"%s\",\n",app_name);
	fprintf(fd,"\t\"%s\",\n",message);
	fprintf(fd,"\t\"");
	fprint_ver(fd,&target_version);
	fprintf(fd,"\",\n");
	fprintf(fd,"\t%i,%i,%i,\n",
		tp->tm_year+1900,
		tp->tm_mon+1,
		tp->tm_mday);
	fprintf(fd,"\t0,\n");
	fprintf(fd,"\t\"%s\",\n",
			last_message);
	fprintf(fd,"};\n\n");
	fclose(fd);
}

int
main(int argc,char ** argv)
{
/*
mversion
-object [object-list for making]
-source [source list filename]
-prefix [for object-list ...]
-base [work dir] [src dir]
-except [except sourcecode dir. or file path]
-work [version work file]
-c [version file for c]
-xl [version file for xl]
-current [current version file]
-log [cvs.log file]
-app [application]
-msg [message]
-update (force update)
-code [struct name and codetype]
-on / -off (enable / disenable the mversion)
*/
ARG_WORK aw;
char * arg;
	aw.argc = argc;
	aw.argv = argv;
	get_arg(&aw);

	for ( ; ; ) {
		arg = get_arg(&aw);
		if ( arg == 0 )
			break;
		if ( strcmp(arg,"-object") == 0 )
			mv_object(&aw);
		else if ( strcmp(arg,"-source") == 0 )
			mv_source(&aw);
		else if ( strcmp(arg,"-prefix") == 0 )
			mv_prefix(&aw);
		else if ( strcmp(arg,"-base") == 0 )
			mv_base(&aw);
		else if ( strcmp(arg,"-except") == 0 )
			mv_except(&aw);
		else if ( strcmp(arg,"-work") == 0 )
			mv_work(&aw);
		else if ( strcmp(arg,"-c") == 0 )
			mv_c(&aw);
		else if ( strcmp(arg,"-xl") == 0 )
			mv_xl(&aw);
		else if ( strcmp(arg,"-current") == 0 )
			mv_current(&aw);
		else if ( strcmp(arg,"-log") == 0 )
			mv_log(&aw);
		else if ( strcmp(arg,"-app") == 0 )
			mv_app(&aw);
		else if ( strcmp(arg,"-update") == 0 )
			update = 1;
		else if ( strcmp(arg,"-msg") == 0 )
			mv_msg(&aw);
		else if ( strcmp(arg,"-code") == 0 )
			mv_code(&aw);
		else if ( strcmp(arg,"-off") == 0 )
			exit(0);
		else if ( strcmp(arg,"-on") == 0 )
			{}
		else {
			fprintf(stderr,"undefined argment \"%s\"\n",arg);
			exit(1);
		}
	}
printf("MAKE SRC LIST\n");
	mv_make_source_list();
printf("LOADING LOG\n");
	mv_loading_log();
printf("LOADING WORK FILE\n");
	mv_loading_work_file();
printf("INSERT SOURCE LIST\n");
	mv_insert_source_list();
printf("VERSION CHECKING\n");
	mv_version_check();
printf("SAVE WORK FILE\n");
	mv_save_work_file();
printf("SAVE CODES\n");
	mv_save_xl_file();
	mv_save_c_file();
	exit(0);
}

