//------------------------------------------------------------
// $Id: mpi2ReaderClass.cc,v 1.5.2.1 2000/06/14 15:00:11 yamauchi Exp $
//------------------------------------------------------------
//	mpi2ReaderClass.cc
//	read (M\pi)^2 data file implementation 
//	(this data format is delived mgf data format)
//
//	1996/9/25
//	Copyright (C) 1996--1998 YAMAUCHI Hitoshi 山内 斉
//	refer readfile.doc
// 
// 1997-3-21 読み込みながら送信などの処理ができなくては困るという
// ことが判明したので書き直しが必要となった。 
//
// 1997年8月31日(日) 空虚な空間をスキップする。しかし、omega net のよ
// うにどこでも通信できる場合を想定している
//------------------------------------------------------------
#include "mpi2exit.h"
#include "mpi2ReaderClass.h"
#include "constants.h"
#include "SpaceParam.h"

extern YorN readSpcparamFile(const char *spcpmFile,  SpaceParam *pSpcPrm);

//------------------------------------------------------------
// protected functions
//------------------------------
// 一行読み込み、行頭を見て何かを判別する
//------------------------------
int mpi2ReaderClass::
getFirstTokenOfLine(void)
{
    static char ftokenbuff[MAX_LINE]; // 最初の token を置くバッファ
    char *retptr = fgets(this->mReadBuff, MAX_LINE, this->mpFp);
    this->mReadLine++;			// 読み込んだ行数の増加
    if(retptr == NULL)
    {
	return(EOF_tkn);
    }

    // 行頭の空白文字がある場合には警告を発っしてコメントとみなす
    if((this->mReadBuff[0] == ' ') && (this->mReadBuff[0] == '\t')) 
    {
	cout << "host:: Warning! : There is white space at top of "
	    "line at " << this->mReadLine << endl;
	return(COMMENT_tkn);
    }

    // 行頭が \n の時には空行であり、コメントと同じ扱い
    if((this->mReadBuff[0] == '\n') || (this->mReadBuff[0] == '#'))
    {
	return(COMMENT_tkn);
    }

    // 空白文字でない部分をコピーする
    for(this->mIdx = 0; 
	(this->mReadBuff[this->mIdx] != ' ')  && 
	(this->mReadBuff[this->mIdx] != '\t') && 
	(this->mReadBuff[this->mIdx] != '\n') &&
	(this->mReadBuff[this->mIdx] != '\0');
	this->mIdx++)
    {
	ftokenbuff[this->mIdx] = this->mReadBuff[this->mIdx];
    }
    // 最後に \0 を入れて区切とする 
    // 	   -> mIdx は現在buffの最初の空白を指している
    ftokenbuff[this->mIdx] = '\0';
    int i;
    for(i = 0; FirstToken[i].name != NULL; i++)
    {
	if(strcmp(ftokenbuff, FirstToken[i].name) == 0)
	{
	    return(FirstToken[i].tokenID);
	}
    }
    cout << "Error! : command not found. mpi2ReaderClass::"
    	"getFirstTokenOfLine() at line " << this->getReadLineNum() << 
	" of [" << this->mFilename << "]" << endl;
    return(FIRST_TOKEN_ELSE_tkn);    
}

//------------------------------
// 一行の残りの数字部分の解析
//	引数の数分だけの double 値を返す
// 	残念ながらこれを呼んだらそのあと getNextString を呼ぶことはできない
//	クラスの内部のポインタ mIdx を更新していない
//------------------------------
YorN mpi2ReaderClass::
getRestDoublePart(int numberOfArgs, double retvals[])
{
    int i;
    char *ptr = NULL;
    char *pNumStartPtr = &(this->mReadBuff[this->mIdx]);
    for(i = 0; i < numberOfArgs; i++)
    {
	ptr = NULL;
	// strtod を arg の数分の回数適用する
	retvals[i] = strtod(pNumStartPtr, &ptr);
	if(pNumStartPtr == ptr)	
	{
	    // no conversion だった場合には ptr が進んでいない
	    cout << "Error! : number of argment must be " <<
		numberOfArgs << " at line " << this->mReadLine << endl;
	    return(NO);
	}
	pNumStartPtr = ptr;
    }
    return(YES);
}

//------------------------------
// 読み込んだ文字列の最初の token を除き、先頭の空白を除いた文字列をコ
// ピーして返す pRetStr は呼び出し側で確保すること
// 一回の呼び出して一つの文字列を返し、クラス内部の解析ポインタを進める
//------------------------------
void mpi2ReaderClass::
getNextString(char *pRetStr)
{
    // 先頭の空白を読み飛ばす
    while((this->mReadBuff[this->mIdx] == ' ') || 
	  (this->mReadBuff[this->mIdx] == '\t'))
    {
	this->mIdx++;
    }

    // 空白を含まない文字列の終わりまでコピーする
    int i;
    for(i = 0; 
	(this->mReadBuff[this->mIdx] != ' ')  && 
	(this->mReadBuff[this->mIdx] != '\t') &&
	(this->mReadBuff[this->mIdx] != '\n') && 
	(this->mReadBuff[this->mIdx] != '\0');
	this->mIdx++, i++)
    {
	pRetStr[i] = this->mReadBuff[this->mIdx];
    }
    pRetStr[i] = '\0'; 
}

//------------------------------------------------------------
// public functions
//------------------------------------------------------------
// destructor
//------------------------------
mpi2ReaderClass::
~mpi2ReaderClass(void)
{
    if(this->mpFp != NULL)
    {
	fclose(this->mpFp);
    }
};

//------------------------------
// 一行 get する何かは不明なので、引数は何が来ても良いように準備する
//	token を返し、その token にみあった引数を返却する。
//	呼び出しの引数は実体を確保したものを渡す
//------------------------------
int mpi2ReaderClass::
getOneLine(int *pNumOfToken, double retval[], char *pRetStr)
{
    int  tkn = this->getFirstTokenOfLine();
    YorN isOK = YES;		// 引数の数は正しかったか?
    switch(tkn)
    {
    case TRIANGLE_POLY_tkn:	case TRIANGLE_POLY_WITH_RADIO_tkn:
    case SPHERE_tkn:		case CYLINDER_tkn:
    case CONE_tkn:		case RING_tkn:
    case TORUS_tkn:
	(*pNumOfToken) = FirstToken[tkn].numberOfToken;
	isOK = this->getRestDoublePart((FirstToken[tkn].numberOfToken - 1),
				       retval);
	// コマンド名を除いた部分が arg の数なので - 1
	pRetStr[0] = '\0';
	break;

    case DIFF_REF_tkn:		case DIFF_TRANS_tkn:
    case DIFF_EMIT_tkn:		case SPEC_REF_tkn:
    case SPEC_TRANS_tkn:	case INDEX_REF_tkn:
    case IES_tkn:		case FRUSTUM_HALFTOPRAD_tkn:
	(*pNumOfToken) = FirstToken[tkn].numberOfToken;
	// material の名前を取得する
	this->getNextString(pRetStr);
	// 残りの引数を取得する (コマンド名 + 名前) の分 2 を引く
	isOK = this->getRestDoublePart(FirstToken[tkn].numberOfToken - 2,
				       retval);
	break;

    case MATERIAL_NAME_tkn:
	(*pNumOfToken) = FirstToken[tkn].numberOfToken;
	this->getNextString(pRetStr);
	break;

    case EOF_tkn:
    case COMMENT_tkn:
	break;

    case FIRST_TOKEN_ELSE_tkn:
    default:
	cerr << "Error! : parse error. Is this file mpi2 format file?"
	    << endl;
	commMpi2_exit(1);
	break;
    }

    if(isOK == YES)
    {
	return(tkn);
    }else
    {
	return(ERROR_tkn);
    }
}

//------------------------------
// YorN open(const char *pFilename);
//	読み込むファイルの指定(成功 YES: 失敗 NO)
//------------------------------
YorN mpi2ReaderClass::
open(const char *pFilename)
{
    // already open ?
    if(this->mpFp != NULL)
    {
	cout << "Error! : can't open " << pFilename << ". because of " << 
	    this->mFilename << " is already opened at mpi2ReaderClass::open." 
		<< "(only one file can be opened at once.) " << endl;
	return(NO);
    }

    // filename is OK?
    if((pFilename == NULL) || (pFilename[0] == '\0'))
    {
	cout << "Error! : illegal filename (null or 0) at "
	    "mpi2ReaderClass::open" << endl;
	return(NO);
    }

    // can open file?
    if(strncmp(pFilename, "(stdin)", strlen("(stdin)")) == 0)
    {
	this->mpFp = stdin;
    }
    else if((this->mpFp = fopen(pFilename, "r")) == NULL)
    {
	cout << "Error! : can't open " << pFilename << " mpi2ReaderClass::open"
	    << endl;
	return(NO);
    }

    // all correct
    this->mFilename = myString(pFilename);
    this->mReadLine = 0;
    this->mIdx = 0;
    return(YES);
}

//------------------------------
// YorN close(void);
// 	ファイルのクローズ
//------------------------------
YorN mpi2ReaderClass::
close(void)
{
    if(strncmp(this->mFilename, "(stdin)", strlen("(stdin)")) == 0)
    {
	// nothing to do
	return(YES);
    }
    else if(this->mpFp != NULL)
    {
	fclose(this->mpFp);
	return(YES);
    }else
    {
	cout << "Warning! : called close but no file is opened at " << 
	    "mpi2ReaderClass::close" << endl;
	return(NO);
    }
};

//------------------------------------------------------------
// material 読み屋 material のリストを作成する。
//------------------------------------------------------------
// material の検索を行う
//	存在する場合にはリストの中から current material を返す
//	存在しない場合にはリストに追加し、それを current material とし
//	て返す
//------------------------------
materialClass *searchAndNewAdd(const char *pMatName, 
			       SLList < materialClass * > *pMatList)
{
    YorN isFind = NO;
    Pix pidx;
    materialClass *pMat = NULL;
    for(pidx = pMatList->first(); pidx != NULL; pMatList->next(pidx))
    {
	pMat = (*pMatList)(pidx);
	if(strncmp(pMatName, pMat->getName(), MAX_MATERIAL_NAME_LEN) == 0)
	{
	    isFind = YES;
	    break;
	}
    }
    if(isFind == YES)
    {
	return(pMat);
    }else
    {
	materialClass *pm = new materialClass;	
	pm->setName(pMatName);
	pMatList->append(pm);
	return(pm);
    }
}

//------------------------------
// material reader
//	pMatList の指す material の実体は new されているので
//	pMatList を使用したら delete すること
//------------------------------
YorN readMatInfo(const char *pMatFname, SLList < materialClass * > *pMatList)
{
    assert(pMatFname != NULL);
    assert(pMatList  != NULL);
    static const Vector3 zero(0.0, 0.0, 0.0);

    mpi2ReaderClass matReader;
    if(matReader.open(pMatFname) == NO)
    {
	cout << NORMALHEAD << " host : Error! : can't open mat file ["
	     <<  pMatFname  <<  "]"  <<  endl;
	commMpi2_exit(1);
    }
    int 	tkn;
    double 	retval[MAX_MPI2_ARGNUM];
    char 	retStr[MAX_LINE];
    int 	numOfTkn;
    materialClass *pCurMat = NULL; // 現在注目しているマテリアル
    char matname[MAX_MATERIAL_NAME_LEN];
    const char *pMsg = " host : Warnig ! redefined ";

    do {
	tkn = matReader.getOneLine(&numOfTkn, retval, retStr);
	switch(tkn)
	{
	case COMMENT_tkn:	// コメントなら何もしない
	case EOF_tkn:		// EOF なら while の条件で抜ける
	    break;
	    
	case MATERIAL_NAME_tkn:
	    if(strlen(retStr) >= MAX_MATERIAL_NAME_LEN)
	    {
		cout << NORMALHEAD << " host : Warning! too long material name"
		  "[" << retStr << "]. material name is changed. at line " <<
		  matReader.getReadLineNum() << endl;
	    }else
	    {
		// 名前をコピーしてリストから探し無ければリストに追加する
		// 現在注目する material を返す
		strncpy(matname, retStr, MAX_MATERIAL_NAME_LEN);
		pCurMat = searchAndNewAdd(matname, pMatList);
	    }
	    break;

	case DIFF_REF_tkn:
	    if(pCurMat->getDiffRef() != zero)
	    {
		cout << NORMALHEAD << pMsg << (pCurMat->getName()) << 
		" of rd" << endl;
	    }
	    pCurMat->setDiffRef(Vector3(retval[0], retval[1], retval[2]));
	    break;

	case DIFF_TRANS_tkn:
	    if(pCurMat->getDiffTrans() != zero)
	    {
		cout << pMsg << (pCurMat->getName()) << " of td" << endl;
	    }
	    pCurMat->setDiffTrans(Vector3(retval[0], retval[1], retval[2]));
	    break;

	case DIFF_EMIT_tkn:
	    if(pCurMat->getDiffEmit() != zero)
	    {
		cout << pMsg << (pCurMat->getName()) << " of ed" << endl;
	    }
	    pCurMat->setDiffEmit(Vector3(retval[0], retval[1], retval[2]));
	    break;

	case SPEC_REF_tkn:
	    if(pCurMat->getSpecRefCosN() != 0.0)
	    {
		cout << pMsg << (pCurMat->getName()) << " of rs" << endl;
	    }
	    pCurMat->setSpecRefCosN(retval[0]);
	    pCurMat->setSpecRef(Vector3(retval[1], retval[2], retval[3]));
	    break;

	case SPEC_TRANS_tkn:
	    if(pCurMat->getSpecTransCosN() != 0.0)
	    {
		cout << pMsg << (pCurMat->getName()) << " of ts" << endl;
	    }
	    pCurMat->setSpecTransCosN(retval[0]);
	    pCurMat->setSpecTrans(Vector3(retval[1], retval[2], retval[3]));
	    break;

	case INDEX_REF_tkn:
	    //tokunaga change:
	    //読み込みます。ひとまず複素数は無視。
	    pCurMat->setIdxRefraction(retval[0]);
	    break;

	case FRUSTUM_HALFTOPRAD_tkn:
	    pCurMat->setFrustumHalfTopRad(retval[0]);   
	    break;
    
	case IES_tkn:
	    cout << "Error! : unsupported ies." << endl;	    
	    commMpi2_exit(1);
	    break;

	case ERROR_tkn:
	default:
	    cout << "Error! : Illegal token in mat file [" <<
		pMatFname << "] at line " << matReader.getReadLineNum()
		    << endl;
	    commMpi2_exit(1);
	}
    }while(tkn != EOF_tkn);

    if(pMatList->length() > 0)
    {
	return(YES);	
    }else
    {
	cout << "Error! : no material data. in [" << pMatFname << "]" << endl;
	commMpi2_exit(1);
	return(NO);
    }
}

//------------------------------------------------------------
// geometry 読み屋 : geoReaderClass implementation
//	geometry を読む場合には object 毎に制御を返すよう open と get を
//	分離する
//------------------------------------------------------------
// getIdxOfmatTable : 2 分探索
//	material の table から名前を検索する
//	存在しない場合には -1 を返す
//------------------------------
int geoReaderClass::
getIdxOfmatTable(const char *pMatName)
{
    assert(this->mpMatArray != NULL);
    int min = 0;
    int max = this->mTableSize;
    int middle  = (min + max) / 2;
    int comp;
    while(min != max)
    {
	comp = strncmp(this->mppMatNameTable[middle], pMatName,
		       MAX_MATERIAL_NAME_LEN);
	if(comp > 0)
	{			// 現在の位置は後すぎるので範囲の後を前に移動
	    max = middle;
	}else if(comp < 0)
	{			// 現在の位置は前すぎるので範囲の前を後に移動
	    if(min == middle)
	    {
		// もうmiddleは移動しない．(min+max)/2は必ずminより大
		// きく，maxより小さくなくてはいけないが，切捨てのため，
		// minと同じになる場合があるその際には探索失敗
		// このバグは2000年5月16日(火)まで発見されなかった．．．
		return(-1);	
				// 
	    }
	    min = middle;
	}else			// comp == 0 -> match
	{
	    return(middle);
	}
	middle = (min + max) / 2;
    }
    // (min == max) となったので探索終了 -> match しなかった
    return(-1);
}

//------------------------------
// open : filename と material name table を渡す
//	  material name table の実体は呼び出し側で用意する
//	  こちらは内容を check して使用する。
//	  material table は検索のために sort したものを渡す。簡単な 
//	  check を行う 
//------------------------------
YorN geoReaderClass::
open(const char *pGeoFName, int tableSize, char **appMatNameTab, 
     materialClass *pMatArray)
{
    if(this->mpGeoReader != NULL)
    {
	cerr << "Error! : geometry file is already opened, not open [" 
	    << pGeoFName << "]" << endl;
	commMpi2_exit(1);
    }
    if((tableSize <= 0) || (appMatNameTab == NULL))
    {
	cerr << "Error! : no material name table. "
	    "at geoReaderClass::open" << endl;
	commMpi2_exit(1);	
    }
    if(pMatArray == NULL)
    {
	cerr << "Error! : no material array. at geoReaderClass::open" << endl;
	commMpi2_exit(1);	
    }

    this->mpGeoReader = new mpi2ReaderClass;
    if(this->mpGeoReader->open(pGeoFName) == NO)
    {
	return(NO);
    }
    // check material table contents
    int  i;
    for(i = 0; i < tableSize; i++) 
    {
	// 異常なものが存在していないかを確認する
	if((appMatNameTab[i] == NULL) || (appMatNameTab[i][0] == '\0'))
	{
	    cerr << "Error! : material table has illegal entry at " 
		"geoReaderClass::open" << endl;
	    commMpi2_exit(1);	
	}
    }
    for(i = 0; i < (tableSize - 1); i++)
    {
	// sort 済みかを確認
	if(strncmp(appMatNameTab[i], 
		   appMatNameTab[i + 1], MAX_MATERIAL_NAME_LEN) > 0)
	{
	    cerr << "Error! : material table is not sorted." << endl;
	    cerr << "[" << i << "] = " << appMatNameTab[i]      << endl;
	    cerr << "[" << i << "] = " << appMatNameTab[i + 1]  << endl;
	    commMpi2_exit(1);		    
	}
    }

    // 確認済みの table を代入
    this->mppMatNameTable = appMatNameTab;
    this->mTableSize	  = tableSize;
    this->mCurMatIdx = -1;
    this->mpMatArray	  = pMatArray;
    return(YES);
}

// close
YorN geoReaderClass::
close(void)
{
    if(this->mpGeoReader == NULL)
    {
	cout << NORMALHEAD << 
	     " hosts : Error! : not opened geometry file. ignred." << endl;
	return(NO);
    }else
    {
	this->mppMatNameTable   = NULL;
	this->mTableSize	= -1;
	this->mCurMatIdx 	= -1;
	YorN closeStat = this->mpGeoReader->close();
	this->mpGeoReader = NULL;
	return(closeStat);
    }
}

// get : 読み込んだ行の token と引数を返す
int geoReaderClass::
getOneGeoData(objBaseClass **ppObject)
{
    int tkn;
    int numOfTkn;
    double retvals[MAX_MPI2_ARGNUM];
    static char retStr[MAX_LINE];
    
    // comment を読み飛ばす。
    // material name の場合には記録して読み飛ばす
    while(1)
    {
	tkn = this->mpGeoReader->getOneLine(&numOfTkn, retvals, retStr);
	if(tkn == MATERIAL_NAME_tkn)
	{			// material name ならば current として記録する
	    this->mCurMatIdx = this->getIdxOfmatTable(retStr);
	    if(this->mCurMatIdx < 0)
	    {
		cerr << "Error! : " << retStr << " is not in material table. "
		    "at line " << this->mpGeoReader->getReadLineNum() 
			<< endl;
		commMpi2_exit(2);
	    }
	}else if(tkn != COMMENT_tkn)
	{			// コメントでなければ loop を抜ける
	    break;
	}
    }
    // COMMENT_tkn でも material name でもない token が読めた
    static Vector3 v1, v2, v3, nonRadColor; // triangle
    static Vector3 center;		    // sphere
    double radius = 0.0;
    static Vector3 spcpos;
    int	   objnum = -1;

    if((this->mCurMatIdx < 0) ||
       (this->mTableSize <= this->mCurMatIdx))
    {
	// geomtry data の current material が特定できない。geometry
	// file の先頭で指定を忘れたのではないか? 
	cerr << "Error! : can not specify current material. at line " 
	    << this->mpGeoReader->getReadLineNum() << endl;
	cerr << "Did you specify material name before geometry data in "
	    "geometry file?" << endl;
	commMpi2_exit(2);
    }
    
    switch(tkn)
    {
    case TRIANGLE_POLY_tkn:
	objnum	= int(retvals[0]);
	v1.set(retvals[1], retvals[2], retvals[3]);
	v2.set(retvals[4], retvals[5], retvals[6]);
	v3.set(retvals[7], retvals[8], retvals[9]);
	spcpos.set(retvals[10], retvals[11], retvals[12]);
	if((v1 == v2) || (v1 == v3) || (v2 == v3))
	{
	    cout << "Error! : illegal triangle (There are same points) at " 
		<< this->getReadLineNum() << endl;
	    commMpi2_exit(2);
	}
	(*ppObject) 	= 
	    new triangleObjectClass(objnum, this->mCurMatIdx, 
				    v1, v2, v3, spcpos, 
				    this->mpMatArray[this->mCurMatIdx].
				    getDiffEmit());
	break;

    case TRIANGLE_POLY_WITH_RADIO_tkn:
	objnum	= int(retvals[0]);
	v1.set(retvals[1], retvals[2], retvals[3]);
	v2.set(retvals[4], retvals[5], retvals[6]);
	v3.set(retvals[7], retvals[8], retvals[9]);
	spcpos.set(retvals[10], retvals[11], retvals[12]);
	nonRadColor.set(retvals[13], retvals[14], retvals[15]);
	if((v1 == v2) || (v1 == v3) || (v2 == v3))
	{
	    cout << "Error! : illegal triangle (There are same points.) at " 
		<< this->mpGeoReader->getReadLineNum() << endl;
	    commMpi2_exit(2);
	}
	(*ppObject) 	= 
	    new triangleObjectClass(objnum, this->mCurMatIdx, 
				    v1, v2, v3, spcpos, 
				    nonRadColor);
	break;

    case SPHERE_tkn:
	objnum	= int(retvals[0]);
	center.set(retvals[1], retvals[2], retvals[3]);
	radius 	= retvals[4];
	spcpos.set(retvals[5], retvals[6], retvals[7]);	
	(*ppObject)     = 
	    new sphereObjectClass(objnum, this->mCurMatIdx, 
				  center, radius, spcpos);
	break;

    case CYLINDER_tkn:
	// 	objNum	= int(getDouble(words[1]));
	// 	center1 = getVector(words[2],  words[3],  words[4]);
	// 	center2 = getVector(words[5],  words[6],  words[7]);
	// 	radius 	= getDouble(words[8]);
	// 	spcpos 	= getVector(words[9], words[10], words[11]);	
	// 	(*ppObject) 	= new cylinderObjectClass(objNum, center1, center2, radius, spcpos);
	break;

    case CONE_tkn:
// 	int	objNum	= int(getDouble(words[1]));
// 	Vector3 center1 = getVector(words[2],  words[3],  words[4]);
// 	double  radius1 = getDouble(words[5]);
// 	Vector3 center2 = getVector(words[6],  words[7],  words[8]);
// 	double  radius2	= getDouble(words[9]);
// 	Vector3 spcpos 	= getVector(words[10], words[11], words[12]);	
// 	(*ppObject) 	= new coneObjectClass(objNum,  
// 				center1, radius1, 
// 				center2, radius2, spcpos);
	break;

    case RING_tkn:
// 	int	objNum	= int(getDouble(words[1]));
// 	Vector3 center 	= getVector(words[2],  words[3],  words[4]);
// 	Vector3 normal	= getVector(words[5],  words[6],  words[7]);
// 	double  inRadius	= getDouble(words[8]);
// 	double  outRadius	= getDouble(words[9]);
// 	Vector3 spcpos 	= getVector(words[10], words[11], words[12]);	
// 	(*ppObject)	= new ringObjectClass(objNum,   center,    normal, 
// 				inRadius, outRadius, spcpos);
	break;

    case TORUS_tkn:
// 	int	objNum	= int(getDouble(words[1]));
// 	Vector3 center 	= getVector(words[2],  words[3],  words[4]);
// 	Vector3 normal	= getVector(words[5],  words[6],  words[7]);
// 	double  inRadius	= getDouble(words[8]);
// 	double  outRadius	= getDouble(words[9]);
// 	Vector3 spcpos 	= getVector(words[10], words[11], words[12]);	
// 	(*ppObject)	= new torusObjectClass(objNum,   center,    normal, 
// 				 inRadius, outRadius, spcpos);
	break;

    case EOF_tkn:		// EOF は許容される token である
#ifndef NULL
	(*ppObject) = NULL;
#endif
	break;

    case ERROR_tkn:		// ERROR token の場合は引数不足などが発生
    default:			// 物体以外の tkn(comment matname除く)は失敗
	cerr << "Error! : illegal line in geometry file at line " 
	    << this->mpGeoReader->getReadLineNum() << endl;
	cerr << "Error! : Is this geometry file? token = " << tkn << endl;
	commMpi2_exit(1);
	break;
    }
    return(tkn);
}
