/* Copyright (c) 2000-2003                                           */
/*   Information-technology Promotion Agency, Japan (IPA)            */
/*   All rights reserved                                             */

/*   The code is developed by Yamashita-lab, Ritsumeikan University  */
/*   The code is ported to Win32 by Studio ARC, ASTEM RI/Kyoto       */

#include	<stdio.h>
//#include	<stdlib.h>
#include	<string>
#include	<setjmp.h>

#ifndef WIN32
#include	<unistd.h>
#include	<sys/wait.h>
#endif

#ifdef WIN32
#include <windows.h>
#define WORDS_LITTLEENDIAN
#endif

#include	"command.h"
#include	"confpara.h"
#include	"main.h"
#include	"synthesis.h"
#include    "hmmsynth.h"
#include    "mlpg.h"
#include    "model.h"
#include    "tag.h"
#include    "slot.h"
#include    "defaults.h"

#define INIT_SLOT_TABLE
#include	"slot.h"

//*******↓for server mode *******
#include "Sock.h"
CSock g_Socket;
//*******↑***********************

#define YesNoSlot(s)  ( ( (s==1) ? "YES" : "NO" ) )

char *moduleVersion = "GalateaTalk Ver. 1.0 (gtalk-030822)";
char *protocolVersion = "Protocol Ver. 1.0";

/* synthesis.h グローバル変数の定義 */
MORPH *mphead;
MORPH *mptail;
PHONEME *phhead;
PHONEME *phtail;
MORA *mrhead;
MORA *mrtail;
APHRASE *ahead;
APHRASE *atail;
BREATH *bhead;
BREATH *btail;
SENTENCE *shead;
SENTENCE *stail;
SENTENCE *sentence;
WAVE wave;
PARAM power;
PARAM f0;
PARAM alpha;
//*******↓for server mode *******
bool s_mode;
int nPort;
//*******↑***********************

char chasen_input[MAX_UTTER];

/* confpara.h グローバル変数の定義 */
char *phlist_file;
char *chasen_bin;
char *chasen_dll;
char *chasen_rc;
char *chaone_bin;
char *read_number;
char *read_alphabet;
char *read_date;
char *read_time;
int n_speaker;	/* 登録された話者数 */
int spid;	/* 現在の話者ID */
FILE *logfp;
SPEAKER speaker[MAX_SPEAKER];

/* hmmsynth.h グローバル変数定義 */
int nstate;
int pitchstream;
int mcepvsize;
ModelSet mset[MAX_SPEAKER];
double **mcep;  /* generated mel-cepstrum */
double **coeff; /* mlsa filter coefficients */
int totalframe;

/* mlpg.h */
PStream pitchpst;
PStream mceppst;
Boolean *voiced;

/* model.h */
Model *mhead;
Model *mtail;
FILE *durmodel;
FILE *pitchmodel;
FILE *mcepmodel;

/* tag.h */
TAG *tag[MAX_TAG];
int n_tag;

/* slot.h */
SlotProp prop_Run;
SlotProp prop_ModuleVersion;
SlotProp prop_ProtocolVersion;
SlotProp prop_SpeakerSet;
SlotProp prop_Speaker;
SlotProp prop_Text;
SlotProp prop_Text_text;
SlotProp prop_Text_pho;
SlotProp prop_Text_dur;
SlotProp prop_Speak;
SlotProp prop_Speak_text;
SlotProp prop_Speak_pho;
SlotProp prop_Speak_dur;
SlotProp prop_Speak_utt;
SlotProp prop_Speak_len;
SlotProp prop_Speak_stat;

/* slots */
char slot_Run[20];
char slot_Speak_stat[20];
char slot_Log_file[256];
char slot_Err_file[256];
int slot_Log_chasen;
int slot_Log_tag;
int slot_Log_phoneme;
int slot_Log_mora;
int slot_Log_morph;
int slot_Log_aphrase;
int slot_Log_breath;
int slot_Log_conf;
int slot_Log_text;
int slot_Log_arranged_text;
int slot_Log_sentence;

/* chaone */
#ifdef WIN32
#include "chaone.h"
char *chaone_xsl;
#endif

extern FILE *fp_err;

void init_slot_prop()
{
	prop_Run = AutoOutput;
	prop_ModuleVersion = AutoOutput;
	prop_ProtocolVersion = AutoOutput;
	prop_SpeakerSet = AutoOutput;
	prop_Speaker = AutoOutput;
	prop_Text = AutoOutput;
	prop_Text_text = AutoOutput;
	prop_Text_pho = AutoOutput;
	prop_Text_dur = AutoOutput;
	prop_Speak = AutoOutput;
	prop_Speak_text = AutoOutput;
	prop_Speak_pho = AutoOutput;
	prop_Speak_dur = AutoOutput;
	prop_Speak_utt = AutoOutput;
	prop_Speak_len = AutoOutput;
	prop_Speak_stat = AutoOutput;
}

/* 初期化: プログラム起動時に一度だけ実行 */
void initialize()
{
  //*******↓for server mode *******
  if (s_mode) {
	WinSockInit();
	init_sock();
	g_Socket.Listen();
	g_Socket.Accept();
  }
  //*******↑***********************

	void setRun( char* , char* );

	void __cdecl init_sentence();

	#ifdef LINUX
	setpgrp();
	#endif /* LINUX */
	set_da_signal();

	init_slot_prop();
	init_text_analysis( NULL );
	init_hmmsynth();
	read_phonemes( phlist_file );
	init_tag();
	init_mora();
	init_morph();
	init_aphrase();
	init_breath();
	init_phoneme();
	init_sentence();
	strcpy( slot_Speak_stat, "IDLE" );
	setRun( "=", "LIVE" );
	strcpy( slot_Log_file, "NO" );   logfp = NULL;
	slot_Log_chasen= slot_Log_tag = slot_Log_phoneme = 0;
	slot_Log_mora = slot_Log_morph = slot_Log_aphrase = 0;
	slot_Log_breath = slot_Log_sentence = 0;
	strcpy( slot_Err_file, "CONSOLE" );
}

/* 初期化: 合成を行うたびに実行 */
void refresh()
{
  //	refresh_speaker();
	refresh_tag();
	refresh_mora();
	refresh_morph();
	refresh_aphrase();
	refresh_breath();
	refresh_phoneme();
	refresh_sentence();
	refresh_hmmsynth();
/* for win */
#ifdef WIN32
	refresh_chaone();
#endif
}

int commandID( char *com )
{
	int 	i;
	for( i=0; i<NUM_COMMAND; ++i )  {
	if( strcmp(com,commandTable[i].name)==0 )  return commandTable[i].id;
	}
	return -1;
}

int slotID( char *slot )
{
	int 	i;
	for( i=0; i<NUM_SLOT; ++i )  {
		if( strcmp(slot,slotTable[i].name)==0 )  return slotTable[i].id;
	}
	return -1;
}

#define	MAX_CLINE	9192
static char cline[MAX_CLINE];

int read_command( char **args )
{
	int 	n=0, p=0, c, pre_c;

	while ( (c= getchar()) == EOF);

/* to skip space */
	while( c==' ' || c=='\t' )  { c = getchar(); };

/* to get a command name */
	*(args++) = &(cline[p]);
	while( c!=' ' && c!='\t' && c!='\n' && c!= EOF )  {
		cline[p++] = c;  c = getchar();
	};
	cline[p++] = '\0';  ++n;

/* to skip space */
	while( c==' ' || c=='\t' )  { c = getchar(); };

/* to get a slot name */
	*(args++) = &(cline[p]);
	while( c!=' ' && c!='\t' && c!='=' && c!='<' && c!='\n' && c!= EOF )  {
		cline[p++] = c;  c = getchar();
	};
	cline[p++] = '\0';  ++n;

/* to skip space */
	while( c==' ' || c=='\t' )  { c = getchar(); };

/* to get relation */
	*(args++) = &(cline[p]);
	if( c=='=' || c=='<' )  {
		cline[p++] = pre_c = c;  c = getchar();
		if( pre_c=='<' && c=='<' )  {
			cline[p++] = c;  c = getchar();
		}
		cline[p++] = '\0';  ++n;
	}

/* to skip space */
	while( c==' ' || c=='\t' )  { c = getchar(); };

/* to get a value */
	*(args++) = &(cline[p]);
	while( c!='\n' && c!= EOF )  {
		cline[p++] = c;  c = getchar();
		if( p >= MAX_CLINE )  {
			ErrMsg( "* Command line is too long\n" );
			restart( 1 );
		}
	};
	cline[p++] = '\0';  ++n;

	return n;
}


/*---------------------------------------------------------*/
/*      inq command                                        */
/*---------------------------------------------------------*/

void inqRun()
{
	RepMsg( "rep Run = %s\n", slot_Run );
}

void inqModuleVersion()
{
	RepMsg( "rep ModuleVersion = \"%s\"\n", moduleVersion );
}

void inqProtocolVersion()
{
	RepMsg( "rep ProtocolVersion = \"%s\"\n", protocolVersion );
}

void inqSpeakerSet()
{
	send_speakerset();
}

void inqSpeaker()
{
	send_speaker();
}

void inqTextText()
{
	send_text( "Text.text" );
}

void inqTextPho()
{
	send_phonemes( "Text.pho" );
}

void inqTextDur()
{
	send_duration( "Text.dur" );
}

void inqSpeakText()
{
	send_text( "Speak.text" );
}

void inqSpeakPho()
{
	send_phonemes( "Speak.pho" );
}

void inqSpeakDur()
{
	send_duration( "Speak.dur" );
}

void inqSpeakUtt()
{
	send_talked_phonemes();
}

void inqSpeakLen()
{
	send_talked_duration();
}

void inqSpeakStat()
{
	RepMsg( "rep Speak.stat = %s\n", slot_Speak_stat );
}

/*---------------------------------------------------------*/
/*      set command                                        */
/*---------------------------------------------------------*/

void setRun( char *rel, char *val )
{
	if( strcmp(rel,"=")!=0 )  { unknown_com();  return; }

	if( strcmp(val,"EXIT")==0 )  {
		strcpy( slot_Run, "EXIT" );
		if( prop_Run == AutoOutput )  inqRun();
		#ifndef WIN32
		sleep(3);
		#endif
		#ifdef WIN32
		Sleep(3000);
		#endif
		exit(0);
	} else if( strcmp(val,"LIVE")==0 )  {
		strcpy( slot_Run, "LIVE" );
		if( prop_Run == AutoOutput )  inqRun();
	} else {
		unknown_com();
	}
}

void setSpeaker( char *rel, char *val )
{
	int s;

	if( strcmp(rel,"=")!=0 )  { unknown_com();  return; }

	s = speakerID( val );
	if( s >= 0 )  {
		spid = s;
		if( prop_Speaker == AutoOutput )  inqSpeaker();
	}
}

/* その時に選択されている話者 spid のαをセットする。*/
void setAlpha( char *rel, char *val )
{
	double a;

	if( strcmp(rel,"=")!=0 )  { unknown_com();  return; }

	a = atof( val );
	if( a >= 0.0 )  {
		speaker[spid].alpha = a;
	}
}

void setText( char *rel, char *val )
{
	strcpy( slot_Speak_stat, "PROCESSING" );
	if( prop_Speak_stat == AutoOutput )  inqSpeakStat();

	if( strcmp(rel,"=")==0 )  {
		refresh();
		text_analysis( val );	/* テキスト解析 */
		if( prop_Text_text == AutoOutput )  inqTextText();
		if( prop_Speak_text == AutoOutput )  inqSpeakText();

		parameter_generation();	/* パラメータ生成(F0,MLSAフィルタ係数,継続長) */
		do_synthesis();		/* 合成波形の生成 */
#ifdef PRINTDATA
		TmpMsg( "Synthesis Done.\n" );
#endif
/*	} else if( strcmp(rel,"<")==0 )  {
	} else if( strcmp(rel,"<<")==0 )  {
*/		
	} else {
		unknown_com();
	}		
	strcpy( slot_Speak_stat, "READY" );
	if( prop_Speak_stat == AutoOutput )  inqSpeakStat();
}

void setSpeak( char *rel, char *val )
{
	int error;
	long sleep_ms;

	if( strcmp(rel,"=")!=0 )  { unknown_com();  return; }

	if( strcmp(val,"NOW")==0 )  {
		strcpy( slot_Speak_stat, "SPEAKING" );
		if( prop_Speak_stat == AutoOutput )  inqSpeakStat();
		do_output(NULL);	/* 音声出力 */

	} else if( strcmp(val,"STOP")==0 )  {
		abort_output();

	} else {
		/* val = "12:34:56.789" or "+1000" */
		error = make_sleep_time( val, &sleep_ms );
		if( error )  {
			unknown_com();
		} else {
#ifdef PRINTDATA
			TmpMsg( "sleep_ms: %d\n", sleep_ms );
#endif
			if( sleep_ms > 0 )  sleepMs( sleep_ms );
			strcpy( slot_Speak_stat, "SPEAKING" );
			if( prop_Speak_stat == AutoOutput )  inqSpeakStat();
			do_output(NULL);	/* 音声出力 */
		}
	}
/*	strcpy( slot_Speak_stat, "IDLE" );
	if( prop_Speak_stat == AutoOutput )  inqSpeakStat();
*/
}

/*-------------------*/

void setSave( char *rel, char *filename )
{
	if( strcmp(rel,"=")==0 )  {
		do_output( filename );
	} else {
		unknown_com();
	}
}

/* 茶筌の結果をファイルから読み込み */
void setParsedText( char *rel, char *filename )
{
	if( strcmp(rel,"=")==0 )  {
		refresh();
		text_analysis_file( filename );	/* テキスト解析 */
		parameter_generation();	/* パラメータ生成(F0,MLSAフィルタ係数,継続長) */
		do_synthesis();		/* 合成波形の生成 */
#ifdef PRINTDATA
		TmpMsg( "Synthesis Done.\n" );
#endif
	} else {
		unknown_com();
	}		
}

void setLog( char *rel, char *filename )
{
	if( strcmp(rel,"=")==0 )  {
		if( logfp && strcmp(slot_Log_file,"CONSOLE")!=0 )  {
			fclose( logfp );
			logfp = NULL;
		}
		strcpy( slot_Log_file, filename );
		if( strcmp(filename,"NO")==0 )  return;
		if( strcmp(filename,"CONSOLE")==0 ) {
			logfp = stderr;
		} else {
			logfp = fopen( filename, "a" );
			if( logfp == NULL )   {
			  ErrMsg( "log file open error ... '$s'\n", filename );
			}
		}
	} else {
		unknown_com();
	}
}

int setLogYesNo( char *rel, char *val )
{
	if( strcmp(rel,"=")==0 )  {
	  if( strcmp( val, "YES" )==0 ) {
		return 1;
	  } else {
		return 0;
	  }
	} else {
		unknown_com();
		return 0;
	}
}

void setErr( char *rel, char *filename )
{
	if( strcmp(rel,"=")==0 )  {
		if( fp_err && strcmp(slot_Err_file,"CONSOLE")!=0 )  fclose( fp_err );
		strcpy( slot_Err_file, filename );
		if( strcmp(filename,"CONSOLE")==0 ) {
			fp_err = stderr;
		} else {
			fp_err = fopen( filename, "a" );
			if( fp_err == NULL )   {
			  ErrMsg( "error log file open error ... '%s'\n", filename );
			}
		}
	} else {
		unknown_com();
	}
}

/*---------------------------------------------------------*/

void parameter_generation()
{
/* 音声合成の初期設定 */
	init_parameter();

/* 音素継続長の決定 */
	make_duration();
/* 音素継続長の変更 */
	modify_duration();
	make_cumul_time();
	modify_voice();

	if( prop_Text_pho == AutoOutput )  inqTextPho();
	if( prop_Speak_pho == AutoOutput )  inqSpeakPho();
	if( prop_Text_dur == AutoOutput )  inqTextDur();
	if( prop_Speak_dur == AutoOutput )  inqSpeakDur();


/* パラメータ生成 F0,MLSAフィルタ係数 */
	make_parameter();

/* F0, ゲイン b(0) の変更 */
	modify_f0();
	modify_power();
}

/*---------------------------------------------------------*/

int 	n_arg;
char	*v_arg[10];

void unknown_com()
{
	int 	i;
	ErrMsg( "* Unknown command line ... \n" );
	for( i=0; i<n_arg; ++i )  { ErrMsg( "%s ", v_arg[i] ); }
	ErrMsg( "\n" );
}

/*
 * エラーメッセージを出力
 */
void usage( char* com )
{
	fprintf( stderr, "%s [-v] [-p port-num] [-C conf-file]\n", com );
	fprintf( stderr, "   -v: print version and exit\n" );
	fprintf( stderr, "   -p port-num: to set port number in server mode\n" );
	fprintf( stderr, "   -C conf-gile: to set configuration file\n" );
	exit(1);
}

extern int chasen_process;
static jmp_buf ebuf;

void restart( int val )
{
	RepMsg( "rep Speak.stat = ERROR\n" );
	longjmp( ebuf, val );
	refresh();
}

//*******↓for server mode *******
void WinSockInit()
{
	// WinSockの初期化
	int		nResult;
	WORD	wRequireVersion;	// 使用するWinSockのバージョン
	WSADATA	lpWSAData;			// WinSock初期化の結果

	// WinSock2を使用するWinSockのバージョンとして設定
	wRequireVersion = MAKEWORD( 2, 0 );

	// WinSockの初期化を行なう
	nResult = WSAStartup( wRequireVersion, &lpWSAData );
	if( nResult != 0  )
	{
//		cerr << "WinSockの初期化に失敗" << endl;
	}

	// 初期化したWinSockのバージョンが要求したものか確認
	if( lpWSAData.wVersion != wRequireVersion )
	{
//		cerr << "要求したWinSockのバージョンが取得できませんでした" << endl;
	}
}

bool init_sock()
{
  //	int nPort = 10600;

	if(!g_Socket.Socket())
	{
		ErrMsg("ソケット作成失敗\n");;
		return false;
	}

	if(!g_Socket.Bind(nPort))
	{
		ErrMsg("バインド失敗\n");;
		return false;
	}
	return true;
}


bool SendMsg( const char* lpszMsg )
{
	// メッセージのサイズを調べて、全部送信できるまでひたすらsendする
	std::string msg = lpszMsg;
	size_t nSize = msg.length();
	size_t nRet = 0;
	g_Socket.Lock();
	while( 1 )
	{
		if( nRet >= nSize )
			break;
		nRet += g_Socket.Send( &msg[nRet], nSize - nRet );
	}
	g_Socket.Unlock();
	return TRUE;
}

int split_command( char **args, LPCTSTR lpszCommand )
{
	int 	n=0, p=0, c, pre_c;
	int nIndex=0;

	c = lpszCommand[nIndex];
	nIndex++;
/* to skip space */
	while( c==' ' || c=='\t' )
	{ 
		c = (int)lpszCommand[nIndex];
		nIndex++;
	}

/* to get a command name */
	*(args++) = &(cline[p]);
	while( c!=' ' && c!='\t' && c!='\n' && c!= EOF )  {
		cline[p++] = c;  c = (int)lpszCommand[nIndex];
		nIndex++;
	};
	cline[p++] = '\0';  ++n;

/* to skip space */
	while( c==' ' || c=='\t' )
	{ 
		c = (int)lpszCommand[nIndex];
		nIndex++;
	}

/* to get a slot name */
	*(args++) = &(cline[p]);
	while( c!=' ' && c!='\t' && c!='=' && c!='<' && c!='\n' && c!= EOF )  {
		cline[p++] = c;  c = (int)lpszCommand[nIndex];
		nIndex++;
	};
	cline[p++] = '\0';  ++n;

/* to skip space */
	while( c==' ' || c=='\t' )
	{ 
		c = (int)lpszCommand[nIndex];
		nIndex++;
	}

/* to get relation */
	*(args++) = &(cline[p]);
	if( c=='=' || c=='<' )  {
		cline[p++] = pre_c = c;  c = (int)lpszCommand[nIndex];
		nIndex++;
		if( pre_c=='<' && c=='<' )  {
			cline[p++] = c;  c = (int)lpszCommand[nIndex];
			nIndex++;
		}
		cline[p++] = '\0';  ++n;
	}

/* to skip space */
	while( c==' ' || c=='\t' )
	{ 
		c = (int)lpszCommand[nIndex];
		nIndex++;
	}

/* to get a value */
	*(args++) = &(cline[p]);
	while( c!='\n' && c!= EOF )  {
		cline[p++] = c;  c = (int)lpszCommand[nIndex];
		nIndex++;
		if( p >= MAX_CLINE )  {
			ErrMsg( "* Command line is too long\n" );
			restart( 1 );
		}
	};
	cline[p++] = '\0';  ++n;
	return n;
}
//*******↑***********************

/*
 * メイン関数
 */
void main( int argc, char **argv )
{
	int n;
	char *com;

	// エラーログ出力ファイル
	fp_err = stderr;

	//*******↓for server mode *******
	int nRecv;						// 受信したサイズを保持
	std::string strMsg;					// 受信データを格納する
	char szBuff[RECV_BUFFER_SIZE+1];		// 受信用バッファ
	//*******↑***********************

	// 初期化処理
	init_conf();

	// コマンドライン処理
	com = argv[0];
	--argc;  ++argv;
	bool argconf;
	while( argc > 0 && argv[0][0] == '-' )  {
		switch( argv[0][1] )  {
		case 'C':
			// 引数が不正な場合はエラー出力
			if( argc < 2 )  usage( com );
			// 設定ファイルの読み込み
			read_conf( argv[1] );
			argconf = true;
			--argc;  ++argv;
			break;
		//*******↓for server mode *******
		case 'p':
			// 引数が不正な場合はエラー出力
			if( argc < 2 )  usage( com );
			// ポート番号の読み込み
			nPort = atoi(argv[1]);
			s_mode = true;
			--argc;  ++argv;
			break;
		//*******↑***********************
		case 'v':
			printf( "%s\n", moduleVersion );
			printf( "%s\n", protocolVersion );
			exit(0);
		default:
			usage( com );
		}
		--argc;  ++argv;
	}

	//設定ファイルの読み込み
	//if (!(argconf))
	//  read_conf("C:\\Program Files\\gtalk\\ssm.conf");

	// 設定ファイルから読み込んでいない項目をデフォルトで設定
	set_default_conf();

	// 初期化
	initialize();

	n = setjmp( ebuf );
	if( n > 0 )  chasen_process = 0;	/* to restart 'chasen' process */

	for( ;; )  {

	  if (!(s_mode)) {
#ifdef PRINTDATA
		TmpMsg( "> " );
#endif
		n_arg = read_command( v_arg );

#ifdef PRINTDATA
		{
			int i;
			TmpMsg( "command is \n" );
			for( i=0; i<n_arg; ++i )  {
				TmpMsg( "  %d: %s\n", i+1, v_arg[i] );
			}
		}
#endif
	  }

	  if (s_mode) {
		szBuff[0] = '\0';
		nRecv = g_Socket.Recv( szBuff );
		if( nRecv == SOCKET_ERROR )
		{
			int ret = WSAGetLastError();
			printf("SOCKET_ERROR\n");
			break;
		}

		strMsg.append( szBuff, nRecv );		
		int nIndex = strMsg.find("./\n",0);

		while(nIndex != -1)
		{
			std::string strCommand = strMsg.substr(0,nIndex);
			strMsg.erase(0,nIndex+3);
			strCommand.append("\n");
			n_arg = split_command( v_arg,strCommand.c_str() );

			printf("%s",strCommand.c_str());
			if(strCommand.find("set Run = EXIT") != std::string::npos)
			{
				g_Socket.Close();
				WSACleanup();
				exit(0);
			}

			/* 「o」 で set Speak = NOW のショートカット */
			if( strcmp(v_arg[0],"o")==0 )  {
			  setSpeak( "=", "NOW" );
			  continue;
			}

			if( n_arg < 2 )  { unknown_com();  continue; }

			switch( commandID( v_arg[0] ) )  {
			  case C_set:
				if( n_arg < 4 )  { unknown_com();  break; }
				switch( slotID( v_arg[1] ) )  {
				  case S_Run:   setRun( v_arg[2], v_arg[3] );  break;
				  case S_Speaker:  setSpeaker( v_arg[2], v_arg[3] );  break;
				  case S_Alpha: setAlpha( v_arg[2], v_arg[3] );  break;
				  case S_Text:  setText( v_arg[2], v_arg[3] );  break;
				  case S_Speak: setSpeak( v_arg[2], v_arg[3] );  break;
				  case S_Save:  setSave( v_arg[2], v_arg[3] );  break;
				  case S_ParsedText: setParsedText( v_arg[2], v_arg[3] );  break;
				  case S_Log:   setLog( v_arg[2], v_arg[3] ); break;
				  case S_Log_conf:
				    slot_Log_conf = setLogYesNo( v_arg[2], v_arg[3] ); break;
				  case S_Log_text:
				    slot_Log_text = setLogYesNo( v_arg[2], v_arg[3] ); break;
				  case S_Log_arranged_text:
				    slot_Log_arranged_text = setLogYesNo( v_arg[2], v_arg[3] ); break;
				  case S_Log_chasen:
				    slot_Log_chasen = setLogYesNo( v_arg[2], v_arg[3] ); break;
				  case S_Log_tag:
				    slot_Log_tag = setLogYesNo( v_arg[2], v_arg[3] ); break;
				  case S_Log_phoneme:
				    slot_Log_phoneme = setLogYesNo( v_arg[2], v_arg[3] ); break;
				  case S_Log_mora:
				    slot_Log_mora = setLogYesNo( v_arg[2], v_arg[3] ); break;
				  case S_Log_morph:
				    slot_Log_morph = setLogYesNo( v_arg[2], v_arg[3] ); break;
				  case S_Log_aphrase:
				    slot_Log_aphrase = setLogYesNo( v_arg[2], v_arg[3] ); break;
				  case S_Log_breath:
				    slot_Log_breath = setLogYesNo( v_arg[2], v_arg[3] ); break;
				  case S_Log_sentence:
				    slot_Log_sentence = setLogYesNo( v_arg[2], v_arg[3] ); break;
				  case S_Err:          setErr( v_arg[2], v_arg[3] ); break;
				  default:
					unknown_com();
				}
				break;
			  case C_inq:
				switch( slotID( v_arg[1] ) ) {
				  case S_Run:        inqRun();  break;
				  case S_ModuleVersion: inqModuleVersion();  break;
				  case S_ProtocolVersion: inqProtocolVersion();  break;
				  case S_SpeakerSet: inqSpeakerSet();  break;
				  case S_Speaker:    inqSpeaker();  break;
				  case S_Text_text:  inqTextText();  break;
				  case S_Text_pho:   inqTextPho();  break;
				  case S_Text_dur:   inqTextDur();  break;
				  case S_Speak_text: inqSpeakText();  break;
				  case S_Speak_pho:  inqSpeakPho();  break;
				  case S_Speak_dur:  inqSpeakDur();  break;
				  case S_Speak_utt:  inqSpeakUtt();  break;
				  case S_Speak_len:  inqSpeakLen();  break;
				  case S_Speak_stat: inqSpeakStat();  break;
				  case S_Log:
				    RepMsg( "rep Log = %s\n", slot_Log_file );  break;
				  case S_Log_conf:
				    RepMsg( "rep Log.conf = %s\n", YesNoSlot(S_Log_conf) );  break;
				  case S_Log_text:
				    RepMsg( "rep Log.text = %s\n", YesNoSlot(S_Log_text) );  break;
				  case S_Log_arranged_text:
				    RepMsg( "rep Log.arranged_text = %s\n", YesNoSlot(S_Log_arranged_text) );  break;
				  case S_Log_chasen:
				    RepMsg( "rep Log.chasen = %s\n", YesNoSlot(S_Log_chasen) );  break;
				  case S_Log_tag:
				    RepMsg( "rep Log.tag = %s\n", YesNoSlot(S_Log_tag) );  break;
				  case S_Log_phoneme:
				    RepMsg( "rep Log.phoneme = %s\n", YesNoSlot(S_Log_phoneme) );  break;
				  case S_Log_mora:
				    RepMsg( "rep Log.mora = %s\n", YesNoSlot(S_Log_mora) );  break;
				  case S_Log_morph:
				    RepMsg( "rep Log.morph = %s\n", YesNoSlot(S_Log_morph) );  break;
				  case S_Log_aphrase:
				    RepMsg( "rep Log.aphrase = %s\n", YesNoSlot(S_Log_aphrase) );  break;
				  case S_Log_breath:
				    RepMsg( "rep Log.breath = %s\n", YesNoSlot(S_Log_breath) );  break;
				  case S_Log_sentence:
				    RepMsg( "rep Log.sentence = %s\n", YesNoSlot(S_Log_sentence) );  break;
				  case S_Err:
				    RepMsg( "rep Err = %s\n", slot_Err_file );  break;
				  default:
					unknown_com();
				}
				break;
			  case C_prop:
				{ SlotProp prop;
				if( strcmp(v_arg[2],"=")!=0 )  { unknown_com(); break; }
				if( strcmp(v_arg[3],"AutoOutput")==0 )  {
					prop = AutoOutput;
				} else if(strcmp(v_arg[3],"NoAutoOutput")==0 )  {
					prop = NoAutoOutput;
				} else {
					unknown_com(); break;
				}
				switch( slotID( v_arg[1] ) ) {
				  case S_Run:        prop_Run = prop;  break;
				  case S_ModuleVersion: prop_ModuleVersion = prop;  break;
				  case S_ProtocolVersion: prop_ProtocolVersion = prop;  break;
				  case S_SpeakerSet: prop_SpeakerSet = prop;  break;
				  case S_Speaker:    prop_Speaker = prop;  break;
				  case S_Text:       prop_Text = prop;  break;
				  case S_Text_text:  prop_Text_text = prop;  break;
				  case S_Text_pho:   prop_Text_pho = prop;  break;
				  case S_Text_dur:   prop_Text_dur = prop;  break;
				  case S_Speak:      prop_Speak = prop;  break;
				  case S_Speak_text: prop_Speak_text = prop;  break;
				  case S_Speak_pho:  prop_Speak_pho = prop;  break;
				  case S_Speak_dur:  prop_Speak_dur = prop;  break;
				  case S_Speak_utt:  prop_Speak_utt = prop;  break;
				  case S_Speak_len:  prop_Speak_len = prop;  break;
				  case S_Speak_stat: prop_Speak_stat = prop;  break;
				  default:
					unknown_com();
				}
				}
				break;
			  default:
				unknown_com();
			}
			nIndex = strMsg.find("./\n",0);
		}
	  }
	  else {
		  	if( n_arg < 2 )  { unknown_com();  continue; }
			/* 「o」 で set Speak = NOW のショートカット */
			if( strcmp(v_arg[0],"o")==0 )  {
			  setSpeak( "=", "NOW" );
			  continue;
			}

			switch( commandID( v_arg[0] ) )  {
			  case C_set:
				if( n_arg < 4 )  { unknown_com();  break; }
				switch( slotID( v_arg[1] ) )  {
				  case S_Run:   setRun( v_arg[2], v_arg[3] );  break;
				  case S_Speaker:  setSpeaker( v_arg[2], v_arg[3] );  break;
				  case S_Alpha: setAlpha( v_arg[2], v_arg[3] );  break;
				  case S_Text:  setText( v_arg[2], v_arg[3] );  break;
				  case S_Speak: setSpeak( v_arg[2], v_arg[3] );  break;
				  case S_Save:  setSave( v_arg[2], v_arg[3] );  break;
				  case S_ParsedText: setParsedText( v_arg[2], v_arg[3] );  break;
				  case S_Log:   setLog( v_arg[2], v_arg[3] ); break;
				  case S_Log_conf:	   slot_Log_conf = setLogYesNo( v_arg[2], v_arg[3] ); break;
				  case S_Log_text:     slot_Log_text = setLogYesNo( v_arg[2], v_arg[3] ); break;
				  case S_Log_chasen:   slot_Log_chasen = setLogYesNo( v_arg[2], v_arg[3] ); break;
				  case S_Log_tag:      slot_Log_tag = setLogYesNo( v_arg[2], v_arg[3] ); break;
				  case S_Log_phoneme:  slot_Log_phoneme = setLogYesNo( v_arg[2], v_arg[3] ); break;
				  case S_Log_mora:     slot_Log_mora = setLogYesNo( v_arg[2], v_arg[3] ); break;
				  case S_Log_morph:    slot_Log_morph = setLogYesNo( v_arg[2], v_arg[3] ); break;
				  case S_Log_aphrase:  slot_Log_aphrase = setLogYesNo( v_arg[2], v_arg[3] ); break;
				  case S_Log_breath:   slot_Log_breath = setLogYesNo( v_arg[2], v_arg[3] ); break;
				  case S_Log_sentence: slot_Log_sentence = setLogYesNo( v_arg[2], v_arg[3] ); break;
				  case S_Err:          setErr( v_arg[2], v_arg[3] ); break;
				  default:
					unknown_com();
				}
				break;
			  case C_inq:
				switch( slotID( v_arg[1] ) ) {
				  case S_Run:        inqRun();  break;
				  case S_ModuleVersion: inqModuleVersion();  break;
				  case S_ProtocolVersion: inqProtocolVersion();  break;
				  case S_SpeakerSet: inqSpeakerSet();  break;
				  case S_Speaker:    inqSpeaker();  break;
				  case S_Text_text:  inqTextText();  break;
				  case S_Text_pho:   inqTextPho();  break;
				  case S_Text_dur:   inqTextDur();  break;
				  case S_Speak_text: inqSpeakText();  break;
				  case S_Speak_pho:  inqSpeakPho();  break;
				  case S_Speak_dur:  inqSpeakDur();  break;
				  case S_Speak_utt:  inqSpeakUtt();  break;
				  case S_Speak_len:  inqSpeakLen();  break;
				  case S_Speak_stat: inqSpeakStat();  break;
				  case S_Log:
				    RepMsg( "rep Log = %s\n", slot_Log_file );  break;
				  case S_Log_conf:
				    RepMsg( "rep Log.conf = %s\n", YesNoSlot(S_Log_conf) );  break;
				  case S_Log_text:
				    RepMsg( "rep Log.text = %s\n", YesNoSlot(S_Log_text) );  break;
				  case S_Log_arranged_text:
				    RepMsg( "rep Log.arranged_text = %s\n", YesNoSlot(S_Log_arranged_text) );  break;
				  case S_Log_chasen:
				    RepMsg( "rep Log.chasen = %s\n", YesNoSlot(S_Log_chasen) );  break;
				  case S_Log_tag:
				    RepMsg( "rep Log.tag = %s\n", YesNoSlot(S_Log_tag) );  break;
				  case S_Log_phoneme:
				    RepMsg( "rep Log.phoneme = %s\n", YesNoSlot(S_Log_phoneme) );  break;
				  case S_Log_mora:
				    RepMsg( "rep Log.mora = %s\n", YesNoSlot(S_Log_mora) );  break;
				  case S_Log_morph:
				    RepMsg( "rep Log.morph = %s\n", YesNoSlot(S_Log_morph) );  break;
				  case S_Log_aphrase:
				    RepMsg( "rep Log.aphrase = %s\n", YesNoSlot(S_Log_aphrase) );  break;
				  case S_Log_breath:
				    RepMsg( "rep Log.breath = %s\n", YesNoSlot(S_Log_breath) );  break;
				  case S_Log_sentence:
				    RepMsg( "rep Log.sentence = %s\n", YesNoSlot(S_Log_sentence) );  break;
				  case S_Err:
				    RepMsg( "rep Err = %s\n", slot_Err_file );  break;
				  default:
					unknown_com();
				}
				break;
			  case C_prop:
				{ SlotProp prop;
				if( strcmp(v_arg[2],"=")!=0 )  { unknown_com(); break; }
				if( strcmp(v_arg[3],"AutoOutput")==0 )  {
					prop = AutoOutput;
				} else if(strcmp(v_arg[3],"NoAutoOutput")==0 )  {
					prop = NoAutoOutput;
				} else {
					unknown_com(); break;
				}
				switch( slotID( v_arg[1] ) ) {
				  case S_Run:        prop_Run = prop;  break;
				  case S_ModuleVersion: prop_ModuleVersion = prop;  break;
				  case S_ProtocolVersion: prop_ProtocolVersion = prop;  break;
				  case S_SpeakerSet: prop_SpeakerSet = prop;  break;
				  case S_Speaker:    prop_Speaker = prop;  break;
				  case S_Text:       prop_Text = prop;  break;
				  case S_Text_text:  prop_Text_text = prop;  break;
				  case S_Text_pho:   prop_Text_pho = prop;  break;
				  case S_Text_dur:   prop_Text_dur = prop;  break;
				  case S_Speak:      prop_Speak = prop;  break;
				  case S_Speak_text: prop_Speak_text = prop;  break;
				  case S_Speak_pho:  prop_Speak_pho = prop;  break;
				  case S_Speak_dur:  prop_Speak_dur = prop;  break;
				  case S_Speak_utt:  prop_Speak_utt = prop;  break;
				  case S_Speak_len:  prop_Speak_len = prop;  break;
				  case S_Speak_stat: prop_Speak_stat = prop;  break;
				  default:
					unknown_com();
				}
				}
				break;
			  default:
				unknown_com();
			}
	  }
	}

	//*******↓for server mode *******
	if (s_mode) {
	  g_Socket.Close();
	  WSACleanup();
	}
	//*******↑***********************

	exit(0);
}

void process_vn_arg () {

}
