#include	<stdio.h>
#include	<string.h>
#include	<ctype.h>
#include	<stdlib.h>
#include	<sys/socket.h>
#include	<netinet/in.h>
#include	<netinet/tcp.h>
#include	<netdb.h>
#include	<signal.h>
#include	<errno.h>
#include	<fcntl.h>

/*
#define	DB(x)	x
*/
#define	DB(x)

#ifdef  SJIS
#define issjiskanji(c)  ((0x81 <= (unsigned char)(c&0xff) && (unsigned char)(c&0xff) <= 0x9f)     \
	|| (0xe0 <= (unsigned char)(c&0xff) && (unsigned char)(c&0xff) <= 0xfc))
#else
#define issjiskanji(c)  0
#endif

/* バッファメモリ確保単位 */
#define	BUF_ALLOC_SIZE	(1024)
/* バッファ構造体 */
typedef	struct	{
	char	*buf;
	int	size;
	int	len;
}DATA_BUF;
/* 送信バッファ */
DATA_BUF	SendBuf={NULL,0,0};
/* 受信バッファ */
DATA_BUF	RecvBuf={NULL,0,0};

char	CurrentLine[8192]="";

extern int	Soc;

int SetBlock(int fd,int flag)
{
int	flags;

	if((flags=fcntl(fd,F_GETFL,0))==-1){
		perror("fcntl");
		return(-1);
	}
	if(flag==0){
		fcntl(fd,F_SETFL,flags|O_NDELAY);
	}
	else if(flag==1){
		fcntl(fd,F_SETFL,flags&~O_NDELAY);
	}
	return (0);
}

int SendAndRecv(char *buf,int len)
{
fd_set	read_mask,write_mask,mask;
int	width;
struct timeval	timeout;
int	end_flag;

	/* ノンブロッキングI/O */
	SetBlock(Soc,0);

	/* select()用マスクの設定 */
	width=0;
	FD_ZERO(&mask);
	FD_SET(Soc,&mask);
	width=Soc+1;

	/* 送信データセット */
	if(len>0){
		IntoSendDataBuf(buf,len);
	}

	end_flag=0;
	while(1){
		read_mask=mask;
		if(SendBuf.len>0){	/* 送信データがある場合 */
			write_mask=mask;
		}
		else{
			FD_ZERO(&write_mask);
		}
		timeout.tv_sec=10;	/* 10秒でタイムアウト */
		timeout.tv_usec=0;
		switch(select(width,(fd_set *)&read_mask,&write_mask,NULL,&timeout)){
			case	-1:
				if(errno!=EINTR){
					perror("select");
				}
				break;
			case	0:
				break;
			default:
				/* データ受信レディなら受信し、コマンド認識・実行 */
				if(FD_ISSET(Soc,&read_mask)){
					end_flag=RecvData(Soc);
				}
				/* データ送信レディなら送信バッファが空でなければ送信 */
				if(FD_ISSET(Soc,&write_mask)){
					SendData(Soc);
				}
				break;
		}
		/* 返答を受け取ったらブレーク */
		if(end_flag==1){
			break;
		}
	}

	return(0);
}

int IntoSendDataBuf(char *add_buf,int add_len)
{
	IntoDataBuf(&SendBuf,add_buf,add_len);

	return(0);
}

int IntoDataBuf(DATA_BUF *data_buf,char *add_buf,int add_len)
{
	if(add_len<=0){
		return(0);
	}

	if(data_buf->size==0){
		data_buf->size=(add_len/BUF_ALLOC_SIZE+1)*BUF_ALLOC_SIZE;
		data_buf->buf=(char *)malloc(data_buf->size);
		memcpy(data_buf->buf,add_buf,add_len);
		data_buf->len=add_len;
	}
	else{
		if(data_buf->len+add_len>=data_buf->size){
			data_buf->size+=(add_len/BUF_ALLOC_SIZE+1)*BUF_ALLOC_SIZE;
			data_buf->buf=(char *)realloc(data_buf->buf,data_buf->size);
		}
		memcpy(data_buf->buf+data_buf->len,add_buf,add_len);
		data_buf->len+=add_len;
	}

	return(0);
}

int ShiftDataBuf(DATA_BUF *data_buf,int shift_len)
{
int	i,len;
char	*ptr_new,*ptr_old;

	if(data_buf->len==0||shift_len<=0){
		return(0);
	}

	len=data_buf->len-shift_len;
	if(len<=0){
		free(data_buf->buf);
		data_buf->buf=NULL;
		data_buf->size=0;
		data_buf->len=0;
	}
	else{
		ptr_new=data_buf->buf;
		ptr_old=data_buf->buf+shift_len;
		for(i=0;i<len;i++){
			*ptr_new=*ptr_old;
			ptr_new++;
			ptr_old++;
		}
		data_buf->len=len;
	}

	return(0);
}

int RecvData(int acc)
{
char	buf[4096];
int	len;
int	end_flag,command_len;

	len=recv(acc,buf,sizeof(buf),0);
	if(len==0){	/* ソケット切断 */
		return(1);
	}

	/* 受信バッファにデータ格納 */
	IntoDataBuf(&RecvBuf,buf,len);
	while(1){
		/* コマンド実行 */
		end_flag=CheckRecvData(RecvBuf.buf,RecvBuf.len,&command_len);
		if(command_len==-1){	/* １行成立せず */
			break;
		}
		/* 確認したデータ分、受信バッファのデータをずらす */
		ShiftDataBuf(&RecvBuf,command_len);
		if(end_flag==1){	/* 終了コマンド */
			break;
		}
	}

	if(end_flag==1){	/* データ受信OK */
		return(1);
	}
	else{
		return(0);
	}
}
int SendData(int acc)
{
int	len;

	len=send(acc,SendBuf.buf,SendBuf.len,0);
	/* 送信できた分、送信バッファのデータをずらす */
	if(len>0){
		ShiftDataBuf(&SendBuf,len);
	}

	return(0);
}

int DataPrint(FILE *fp,char *buf,int len)
{
int	i;

	for(i=0;i<len;i++){
		if(isascii(buf[i])&&isprint(buf[i])){
			fputc(buf[i],fp);
		}
		else{
			fprintf(fp,"[%02x]",(unsigned int)(buf[i]&0xFF));
		}
	}

	return(0);
}

int CheckRecvData(char *buf,int len,int *command_len)
{
int	i;

	*command_len=-1;
	for(i=0;i<len;i++){
		/* SJIS漢字1バイト目、エスケープ */
		if(issjiskanji(buf[i])||buf[i]=='\\'){
			i++;
			continue;
		}
		if(buf[i]=='\n'){
			*command_len=i+1;
			break;
		}
	}

	if(*command_len==-1){	/* １行成立せず */
		return(0);
	}

	if(buf[i-1]=='\r'){
		buf[i-1]='\0';
	}
	else{
		buf[i]='\0';
	}

	DebugPrint(buf);

	strcpy(CurrentLine,buf);

	return(1);
}

char *GetCurrentLine()
{
	return(CurrentLine);
}

int ClearCurrentLine()
{
	strcpy(CurrentLine,"");
	return(0);
}
