/*****************************************************************************
 * Bison/Flexプログラム部分をテストするための、Windowsアプリケーションの雛型 *
 * □ビルド・実行方法:                                                       *
 * ┃"C:\Program Files (x86)\Microsoft Visual Studio\VC98\Bin\VCVARS32.BAT"  *
 * ┃make -f winapp.mk run                                                   *
 *****************************************************************************/
#include "winapp.h"
//-----------------------------------------------------------------------------
//警告定義
enum {
	WARN_CAST,			//暗黙の型変換で誤差が生じたら、警告を表示し最終的にエラー終了します。このオプションを指定しなければ、警告表示もエラー終了もしません。
};
static const char* const warn_tokens[]={
	"cast",				//暗黙の型変換で誤差が生じたら、警告を表示し最終的にエラー終了します。このオプションを指定しなければ、警告表示もエラー終了もしません。
NULL};//終端
int warn;				//各警告(WARN_*)について(warn&(1<<WARN_*))がセットされていたらその警告がOnである事を示します。
/*---------------------------------------------------------------------------*/
//ローカル変数定義
static GSList* pMeshList;		//メッシュリスト
//ラベル名のソート方法
int (*fnLabCmp)(const void*, const void*) = strcmp;	//'n'オプションが指定されたらstrnatcmpに変更する。
//{{進捗表示用
static int opt_q;
static int newMsgLen, oldMsgLen = 0;
//}}進捗表示用
/*---------------------------------------------------------------------------*/
//エラーログ用
static char err_path[_MAX_PATH];	//'-e'オプションが指定されたら、エラーログファイル名を格納する。
static FILE* fp_err;			//最初のエラーログを記録する時に、エラーログファイルを作成する。
//{{2016/09/24追加:エラーメッセージに、現在の行番号だけでなく、現在のファイル名も表示するようにしました。
typedef struct _ST_Location {
	const char*	path;					//push_location()が呼び出された直前のファイル名
	int		line;					//push_location()が呼び出された直前の行番号
} ST_Location;
static ST_Location TBL_Location[16/*調整可*/];			//ロケーションスタック
static nLocation;						//ロケーションスタックの格納数
static const char* filename = "-";				//現在のファイル名(popen時はコマンド名)。現在の行番号はyylinenoを参照して下さい。
static void init_location(const char* path) {
	nLocation = 0;						//ロケーションスタックを空にする。
	filename = strdup(path);				//現在のファイル名をコピーして保持する。
	yylineno = 1;						//現在の行番号を初期化する。	yylex_init()でも初期化しているのでこの行は無くても構わないのだが、判り易さのためにここでも初期化する事にした。
}
void push_location(const char* path) {
	if(nLocation >= ARRAY_SIZE(TBL_Location)) { DIE(); }	//ロケーションスタックがフルでない事を確認する。
	TBL_Location[nLocation].path = filename;		//現在のファイル名をロケーションスタックに退避する。
	TBL_Location[nLocation].line = yylineno;		//現在の行番号をロケーションスタックに退避する。
	nLocation++;						//ロケーションスタックの格納数を増やす。
	filename = strdup(path);				//現在のファイル名をコピーして保持する。
	yylineno = 1;						//現在の行番号を初期化する。
}
void pop_location() {
	if(!nLocation) { DIE(); }				//ロケーションスタックが空でない事を確認する。
	nLocation--;						//ロケーションスタックの格納数を減らす。
	filename = TBL_Location[nLocation].path;		//現在のファイル名をロケーションスタックから復元する。
	yylineno = TBL_Location[nLocation].line;		//現在の行番号をロケーションスタックから復元する。
}
//}}2016/09/24追加:エラーメッセージに、現在の行番号だけでなく、現在のファイル名も表示するようにしました。
void yyerror(const char* fmt, ...) {	//←{{2015/03/06:'-e'オプション対応のためにwinapp.cから移動しました。}}
	//'-e'オプションが指定されていて、最初のエラーログを記録する時ならば…
	if(*err_path && !fp_err) {
		//エラーログファイルを作成する。
		fp_err = fopen(err_path, "w");
		if(!fp_err) { error(EXIT_FAILURE, errno, "%s が作成できません。", err_path); }	//{{2016/09/21変更:die(〜)で終了していた箇所を、error(EXIT_FAILURE,〜)で終了するように変更しました。}}	//{{2016/09/28変更:error()の文字列の最後に余計な改行が付いていたのを削除しました。}}
		//エラーログファイルの出力ストリームは、バッファリング無しとする。
		// - die()で終了した時(abort()時)に、バッファ分がフラッシュされないようなので、こうしておく必要が有る。
		//   別の案として、この下の処理で毎回fflush()する方法も有るが、バッファリング無しとする方が簡単だろう。
		setbuf(fp_err, NULL);
	}
	//エラーメッセージ(,及び,エラーログ)を出力する。
//{{2016/09/24変更:エラーメッセージに、現在の行番号だけでなく、現在のファイル名も表示するようにしました。
//	             fprintf(stderr, "### error at line %d : ", yylineno);	//エラーメッセージ
//	if(fp_err) { fprintf(fp_err, "### error at line %d : ", yylineno); }	//エラーログ
//↓2016/09/24変更:エラーメッセージに、現在の行番号だけでなく、現在のファイル名も表示するようにしました。
	             fprintf(stderr, "%s(%d) : ", filename, yylineno);		//エラーメッセージ
	if(fp_err) { fprintf(fp_err, "%s(%d) : ", filename, yylineno); }	//エラーログ
//}}2016/09/24変更:エラーメッセージに、現在の行番号だけでなく、現在のファイル名も表示するようにしました。
	{
		va_list ap;
		va_start(ap, fmt);
		             vfprintf(stderr, fmt, ap);		//エラーメッセージ
		if(fp_err) { vfprintf(fp_err, fmt, ap); }	//エラーログ
		va_end(ap);
	}
	             fputc('\n', stderr);	//エラーメッセージ
	if(fp_err) { fputc('\n', fp_err); }	//エラーログ
}
/*---------------------------------------------------------------------------*/
//ローカル関数宣言
__declspec(noreturn) static void usage();
static int subr(int argc, char* argv[]);
static void pass2(int bOptimize);
static void output(const char* sEnmOut, const char* sRegOut);
static void output_enm(FILE* fp);
static void output_reg(FILE* fp);
/*---------------------------------------------------------------------------*/
int main(int argc, char* argv[]) {
	int exitCode;
	SEH_init();
	exitCode = subr(argc, argv);
	return exitCode;
}
/*---------------------------------------------------------------------------*/
static int subr(int argc, char* argv[]) {
	int opt, bOptimize = 1;		//'-d'オプションが指定されなければ最適化を行う。
	const char* sEnmOut = NULL;	//'-u'オプションが指定されたら列挙定義スクリプトのファイル名,又は,"-"(標準出力)を設定する。
	const char* sRegOut = NULL;	//'-r'オプションが指定されたらレジストリスクリプトのファイル名,又は,"-"(標準出力)を設定する。
#if     (YYDEBUG!=0)
//	yydebug = 1; //nonzero means print parse trace
#endif/*(YYDEBUG!=0)*/
	//コマンドラインオプションを処理する。
	opterr = 0; //オプションエラーは当プログラム内で処理するので、getopt()内でのエラー表示は不要。
	while((opt = getopt(argc, argv, "du::r::enw::qh")) != -1) {
		switch(opt) {
		case 'd':
			bOptimize = 0;				//最適化を行わない。
			break;
		case 'u':
			sEnmOut = optarg ? optarg : "-";	//列挙定義スクリプトのファイル名,又は,"-"(標準出力)を設定する。
			break;
		case 'r':
			sRegOut = optarg ? optarg : "-";	//レジストリスクリプトのファイル名,又は,"-"(標準出力)を設定する。
			break;
		case 'e':
			{
				//エラーログファイル名を作成する。
				// - カレントフォルダに'実行ファイル名.err'という名前で生成する事にした。この動作は、'lk33.exe'の仕様を参考にした。
				char fname[_MAX_FNAME];
				_splitpath(argv[0], NULL, NULL, fname, NULL);
				_makepath(err_path, NULL, NULL, fname, ".err");
				//'-e'オプションが指定されたら、最初に確実に、既存のエラーログファイルを削除しておく。
				//前回に生成したエラーログが残っていて、今回生成したエラーログと混同する危険を避けるためである。
				//尚、'-e'オプションが指定されなかった場合は、既存のエラーログファイルを削除する処理は行わない。
				remove(err_path);
			}
			break;
		case 'n':
			fnLabCmp = strnatcmp;	//ラベル名のソートにstrnatcmp()を使用する。
			break;
		case 'w':
			if(optarg) {
				char *optionp = optarg, *valuep;
				while(*optionp) {
					switch(getsubopt(&optionp, (char* const*)warn_tokens, &valuep)) {
					case WARN_CAST:
						if(valuep) { usage(); }
						warn |= (1<<WARN_CAST);
						break;
					default:
						usage();
					}
				}
			} else {
				warn = -1;
			}
			break;
		case 'q':
			opt_q = 1;
			break;
		case 'h':
		default:
			usage();
		}
	}
	//--- 1パス目の処理 ---
	//ファイルが指定されていなければ、標準入力から読み込む。
	if(optind == argc) {
		init_location("-");	//{{2016/09/24追加:エラーメッセージに、現在の行番号だけでなく、現在のファイル名も表示するようにしました。}}
		yylex_init(stdin);
		if((yyparse() != 0) /*|| (yynerrs != 0)*/) { error(EXIT_FAILURE, 0, "エラーが発生しました。"); }	//{{2016/09/21変更:die(〜)で終了していた箇所を、error(EXIT_FAILURE,〜)で終了するように変更しました。}}	//{{2016/09/28変更:error()の文字列の最後に余計な改行が付いていたのを削除しました。}}
	//ファイルが指定されていたら、各ファイルを読み込む。
	} else {
		int i;
		for(i = optind; i < argc; i++) {
			FILE* fp = fopen(argv[i], "r");
			if(!fp) { error(EXIT_FAILURE, errno, "%s が開けません。", argv[i]); }	//{{2016/09/21変更:die(〜)で終了していた箇所を、error(EXIT_FAILURE,〜)で終了するように変更しました。}}	//{{2016/09/28変更:error()の文字列の最後に余計な改行が付いていたのを削除しました。}}
			init_location(argv[i]);	//{{2016/09/24追加:エラーメッセージに、現在の行番号だけでなく、現在のファイル名も表示するようにしました。}}
			yylex_init(fp);
//{{2017/03/16変更:複数の入力ファイルを指定した時に、最後以外のファイルでエラーが発生した場合、当ツールの終了ステータスが0になっていたバグを修正しました。
//			if((yyparse() != 0) /*|| (yynerrs != 0)*/) { error(EXIT_FAILURE, 0, "%s: エラーが発生しました。", argv[i]); }	//{{2016/09/21変更:die(〜)で終了していた箇所を、error(EXIT_FAILURE,〜)で終了するように変更しました。}}	//{{2016/09/28変更:error()の文字列の最後に余計な改行が付いていたのを削除しました。}}
//↓2017/03/16変更:複数の入力ファイルを指定した時に、最後以外のファイルでエラーが発生した場合、当ツールの終了ステータスが0になっていたバグを修正しました。
			{
				int save_yynerrs = yynerrs;	//yyparse()がyynerrsをクリアするので、その前に現在のyynerrsを保存しておく。
				if((yyparse() != 0) /*|| (yynerrs != 0)*/) { error(EXIT_FAILURE, 0, "%s: エラーが発生しました。", argv[i]); }	//{{2016/09/21変更:die(〜)で終了していた箇所を、error(EXIT_FAILURE,〜)で終了するように変更しました。}}	//{{2016/09/28変更:error()の文字列の最後に余計な改行が付いていたのを削除しました。}}
				yynerrs += save_yynerrs;	//今回のyyparse()が0から数えたであろうyynerrsに対して、先ほど保存しておいたyynerrsを足し込む。
			}
//}}2017/03/16変更:複数の入力ファイルを指定した時に、最後以外のファイルでエラーが発生した場合、当ツールの終了ステータスが0になっていたバグを修正しました。
			fclose(fp);
		}
	}
    //{{進捗表示用
	if(!opt_q) {
		newMsgLen = fprintf(stderr, "\rpass1 ok");
		if(oldMsgLen > newMsgLen) { fprintf(stderr, "%*s", oldMsgLen - newMsgLen, ""); } putc('\n', stderr); oldMsgLen = 0;
	}
    //}}進捗表示用
	//1パス目の処理でエラーが発生しても、2パス目の処理を行って、全てのセマンティクスエラーを報告する。
	//--- 2パス目の処理 ---
	//2パス目の処理を行う。
	pass2(bOptimize);
    //{{進捗表示用
	if(!opt_q) {
		newMsgLen = fprintf(stderr, "\rpass2 ok");
		if(oldMsgLen > newMsgLen) { fprintf(stderr, "%*s", oldMsgLen - newMsgLen, ""); } putc('\n', stderr); oldMsgLen = 0;
	}
    //}}進捗表示用
	if(yynerrs != 0) { error(EXIT_FAILURE, 0, "エラーが発生しました。"); }	//1パス目,又は,2パス目の処理でエラーが発生していたら、出力処理を行わない。	//{{2016/09/21変更:die(〜)で終了していた箇所を、error(EXIT_FAILURE,〜)で終了するように変更しました。}}	//{{2016/09/28変更:error()の文字列の最後に余計な改行が付いていたのを削除しました。}}
	//--- 出力処理 ---
	//出力処理を行う。
	output(sEnmOut, sRegOut);
	if(yynerrs != 0) { error(EXIT_FAILURE, 0, "エラーが発生しました。"); }	//{{2016/09/21変更:die(〜)で終了していた箇所を、error(EXIT_FAILURE,〜)で終了するように変更しました。}}	//{{2016/09/28変更:error()の文字列の最後に余計な改行が付いていたのを削除しました。}}
	return EXIT_SUCCESS;
}
/*---------------------------------------------------------------------------*/
//使い方を表示して終了する。
__declspec(noreturn) static void usage() {
	fprintf(stderr, "dMesDefC - メッシュ定義コンパイラ (%s)\n", VERSION);
	fprintf(stderr, "Copyright (C) 2018 Naoyuki Sawa\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "USAGE:\n");
	fprintf(stderr, "  dMesDefC [option ...] [filename ...] \n");
	fprintf(stderr, "  ・filenameを指定しなければ、標準入力から読み込みます。\n");
	fprintf(stderr, "  ・filenameは、ワイルドカードによる複数指定も可能です。\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "OPTIONS:\n");
	fprintf(stderr, "  -d             最適化を行いません。\n");
	fprintf(stderr, "                 このオプションを指定しなければ、最適化を行います。\n");
	fprintf(stderr, "  -u[ファイル名] 列挙定義スクリプトを、ファイルへ出力します。\n");
	fprintf(stderr, "                 ファイル名を指定しなければ、標準出力へ出力します。\n");
	fprintf(stderr, "                 このオプションを指定しなければ、列挙定義スクリプトを出力しません。\n");
	fprintf(stderr, "  -r[ファイル名] レジストリスクリプトを、ファイルへ出力します。\n");
	fprintf(stderr, "                 ファイル名を指定しなければ、標準出力へ出力します。\n");
	fprintf(stderr, "                 このオプションを指定しなければ、レジストリスクリプトを出力しません。\n");
	fprintf(stderr, "  -e             エラーログファイルを生成します。\n");
	fprintf(stderr, "                 このオプションを指定しても、エラーが発生しなければ生成されません。\n");
	fprintf(stderr, "  -n             ラベル名のソートに、strnatcmp()を使用します。\n");
	fprintf(stderr, "                 このオプションを指定しなければ、strcmp()を使用します。\n");
	fprintf(stderr, "  -w             全ての警告を有効にします。\n");
	fprintf(stderr, "                 このオプションを指定しなければ、個別に設定した警告のみが有効になります。\n");
	fprintf(stderr, "  -wcast         暗黙の型変換で誤差が生じたら、警告を表示し最終的にエラー終了します。\n");
	fprintf(stderr, "                 このオプションを指定しなければ、警告表示もエラー終了もしません。\n");
	fprintf(stderr, "  -q             進捗表示を抑制します。\n");
	fprintf(stderr, "  -h             使い方を表示します。\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "EXAMPLE:\n");
	fprintf(stderr, "  dMesDefC.exe -uEnmMesDef.txt -rRegMesDef.txt MesDef.txt\n");
	fprintf(stderr, "  MesDef.txtをコンパイルします。\n");
	fprintf(stderr, "  列挙定義スクリプトを、EnmMesDef.txtへ出力します。\n");
	fprintf(stderr, "  レジストリスクリプトを、RegMesDef.txtへ出力します。\n");
	exit(EXIT_FAILURE);
}
/*---------------------------------------------------------------------------*/
//1パス目の処理
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
int cast_dbl_to_int(double d) {
	int i = d;
	if(i != d) {
		if(warn & (1<<WARN_CAST)) {
			yyerror("切り捨て誤差が発生しました: %f → %d", d, i);
			yynerrs++;	//呼び出し元(main)に知らせるために。
			//全てのセマンティクスエラーを報告するために継続する。
		}
	}
	return i;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
static int Mesh_compar(const void* a, const void* b) {
	const ST_Mesh* pMesh1 = a;
	const ST_Mesh* pMesh2 = b;
	return (*fnLabCmp)(pMesh1->pMeshHdr->pMeshLabel, pMesh2->pMeshHdr->pMeshLabel);
}
void addMesh(ST_Mesh* pMesh) {
	char* pMeshLabel = pMesh->pMeshHdr->pMeshLabel;
    //{{進捗表示用
	if(!opt_q) {
		newMsgLen = fprintf(stderr, "\rpass1 %s", pMeshLabel);
		if(oldMsgLen > newMsgLen) { fprintf(stderr, "%*s", oldMsgLen - newMsgLen, ""); } oldMsgLen = newMsgLen;
	}
    //}}進捗表示用
	//メッシュラベルが重複していない事を確認する。
	{
		GSList* list = pMeshList;
		while(list) {
			ST_Mesh* pMesh2 = list->data;
			if(!strcmp(pMesh2->pMeshHdr->pMeshLabel, pMeshLabel)) {		//ここではfnLabCmpを使用してはいけない。文字列が厳密に一致しているかを判断する目的だから。
				yyerror("メッシュラベルが重複しています。(%s)", pMeshLabel);
				yynerrs++;	//呼び出し元(main)に知らせるために。
				return;		//全てのセマンティクスエラーを報告するために継続する。
			}
			list = list->next;
		}
	}
	//メッシュラベルの昇順に登録する。
	pMeshList = g_slist_insert_sorted(pMeshList, pMesh, Mesh_compar);
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_Mesh* Mesh_New(ST_MeshHdr* pMeshHdr, ST_MeshBody* pMeshBody) {
	ST_Mesh* pMesh = calloc(1, sizeof(ST_Mesh));
	if(!pMesh) { DIE(); }	//メモリ不足
	if(!pMeshHdr || !pMeshBody) { DIE(); }	//バグ
	//データ生成
	{
		GSList/*<ST_VectorRow*>*/* pVectorRowList = NULL;
		GSList/*<ST_TcoordRow*>*/* pTcoordRowList = NULL;
		if(!pMeshBody->pVectors) { pMeshBody->pVectors = Vectors_New(VectorsHdr_New(), VectorsBody_New()); }
		if(!pMeshBody->pTcoords) { pMeshBody->pTcoords = Tcoords_New(TcoordsHdr_New(), TcoordsBody_New()); }
		//各フェイスについて…
		{
			GSList* list = pMeshBody->pFaceList;
			while(list) {
				ST_Face* pFace = list->data;
				ST_FaceBody* pFaceBody = pFace->pFaceBody;
				//各フェイス頂点について…
				{
					GSList* list = pFaceBody->pFaceVertexRowList;
					while(list) {
						ST_FaceVertexRow* pFaceVertexRow = list->data;
						ST_FaceVertex* pFaceVertex = pFaceVertexRow->pFaceVertex;
						//頂点座標参照を、(type=VectorRef_type_iVectorIndex)に統一する。
						{
							ST_VectorRef* pVectorRef = pFaceVertex->pVectorRef;
							ST_Vector* pVector = NULL;
							switch(pVectorRef->type) {
							default:DIE();
							case VectorRef_type_pVector:
								{
									pVector = pVectorRef->data.pVector;
								}
								break;
							case VectorRef_type_iVectorIndex:
								{
									ST_VectorRow* pVectorRow = g_slist_nth_data(pMeshBody->pVectors->pVectorsBody->pVectorRowList, pVectorRef->data.iVectorIndex);
									if(!pVectorRow) {
										yyerror("頂点座標参照のインデクスが不正です。(%s,%d)", pMeshHdr->pMeshLabel, pVectorRef->data.iVectorIndex);
										yynerrs++;	//呼び出し元(main)に知らせるために	//必要。YYERRORマクロ呼び出しでyynerrsは増やされないようだ。	←←←←←←←←←←■■■■重要■■■■
										return NULL;	//y.tab.yの処理でYYERRORを行う。
									}
									pVector = pVectorRow->pVector;
								}
								break;
							case VectorRef_type_pLabelOffset:
								{
									GSList* list = pMeshBody->pVectors->pVectorsBody->pVectorRowList;
									while(list) {
										ST_VectorRow* pVectorRow = list->data;
										if(pVectorRow->pVectorLabel && !strcmp(pVectorRow->pVectorLabel, pVectorRef->data.pLabelOffset->pLabel)) {	//ここではfnLabCmpを使用してはいけない。文字列が厳密に一致しているかを判断する目的だから。
											if(pVector) {
												yyerror("頂点座標参照のラベルが重複しています。(%s,%s)", pMeshHdr->pMeshLabel, pVectorRef->data.pLabelOffset->pLabel);
												yynerrs++;	//呼び出し元(main)に知らせるために	//必要。YYERRORマクロ呼び出しでyynerrsは増やされないようだ。	←←←←←←←←←←■■■■重要■■■■
												return NULL;	//y.tab.yの処理でYYERRORを行う。
											}
											pVectorRow = g_slist_nth_data(pMeshBody->pVectors->pVectorsBody->pVectorRowList,
											             g_slist_position(pMeshBody->pVectors->pVectorsBody->pVectorRowList, list) + pVectorRef->data.pLabelOffset->iOffset);
											if(!pVectorRow) {
												yyerror("頂点座標参照のオフセットが不正です。(%s,%s%+d)", pMeshHdr->pMeshLabel, pVectorRef->data.pLabelOffset->pLabel, pVectorRef->data.pLabelOffset->iOffset);
												yynerrs++;	//呼び出し元(main)に知らせるために	//必要。YYERRORマクロ呼び出しでyynerrsは増やされないようだ。	←←←←←←←←←←■■■■重要■■■■
												return NULL;	//y.tab.yの処理でYYERRORを行う。
											}
											pVector = pVectorRow->pVector;
										}
										list = list->next;
									}
									if(!pVector) {
										yyerror("頂点座標参照のラベルが不正です。(%s,%s)", pMeshHdr->pMeshLabel, pVectorRef->data.pLabelOffset->pLabel);
										yynerrs++;	//呼び出し元(main)に知らせるために	//必要。YYERRORマクロ呼び出しでyynerrsは増やされないようだ。	←←←←←←←←←←■■■■重要■■■■
										return NULL;	//y.tab.yの処理でYYERRORを行う。
									}
								}
								break;
							}
							if(!pVector) { DIE(); }	//バグ
							{
								GSList* list = pVectorRowList;
								int iVectorIndex = 0;
								while(list) {
									ST_VectorRow* pVectorRow = list->data;
									if((pVectorRow->pVector->x == pVector->x) &&
									   (pVectorRow->pVector->y == pVector->y) &&
									   (pVectorRow->pVector->z == pVector->z)) { break; }
									iVectorIndex++;
									list = list->next;
								}
								if(!list) {
									ST_VectorRow* pVectorRow = VectorRow_New(pVector, NULL);
									if(!pVectorRow) { DIE(); }	//バグ
									pVectorRowList = g_slist_append(pVectorRowList, pVectorRow);
								}
								pVectorRef->type		= VectorRef_type_iVectorIndex;
								pVectorRef->data.iVectorIndex	= iVectorIndex;
							}
						}
						//テクスチャ座標参照を、(type=TcoordRef_type_iTcoordIndex)に統一する。
						if(pFaceVertex->pTcoordRef) {	//NULL可
							ST_TcoordRef* pTcoordRef = pFaceVertex->pTcoordRef;
							ST_Tcoord* pTcoord = NULL;
							switch(pTcoordRef->type) {
							default:DIE();
							case TcoordRef_type_pTcoord:
								{
									pTcoord = pTcoordRef->data.pTcoord;
								}
								break;
							case TcoordRef_type_iTcoordIndex:
								{
									ST_TcoordRow* pTcoordRow = g_slist_nth_data(pMeshBody->pTcoords->pTcoordsBody->pTcoordRowList, pTcoordRef->data.iTcoordIndex);
									if(!pTcoordRow) {
										yyerror("テクスチャ座標参照のインデクスが不正です。(%s,%d)", pMeshHdr->pMeshLabel, pTcoordRef->data.iTcoordIndex);
										yynerrs++;	//呼び出し元(main)に知らせるために	//必要。YYERRORマクロ呼び出しでyynerrsは増やされないようだ。	←←←←←←←←←←■■■■重要■■■■
										return NULL;	//y.tab.yの処理でYYERRORを行う。
									}
									pTcoord = pTcoordRow->pTcoord;
								}
								break;
							case TcoordRef_type_pLabelOffset:
								{
									GSList* list = pMeshBody->pTcoords->pTcoordsBody->pTcoordRowList;
									while(list) {
										ST_TcoordRow* pTcoordRow = list->data;
										if(pTcoordRow->pTcoordLabel && !strcmp(pTcoordRow->pTcoordLabel, pTcoordRef->data.pLabelOffset->pLabel)) {	//ここではfnLabCmpを使用してはいけない。文字列が厳密に一致しているかを判断する目的だから。
											if(pTcoord) {
												yyerror("テクスチャ座標参照のラベルが重複しています。(%s,%s)", pMeshHdr->pMeshLabel, pTcoordRef->data.pLabelOffset->pLabel);
												yynerrs++;	//呼び出し元(main)に知らせるために	//必要。YYERRORマクロ呼び出しでyynerrsは増やされないようだ。	←←←←←←←←←←■■■■重要■■■■
												return NULL;	//y.tab.yの処理でYYERRORを行う。
											}
											pTcoordRow = g_slist_nth_data(pMeshBody->pTcoords->pTcoordsBody->pTcoordRowList,
											             g_slist_position(pMeshBody->pTcoords->pTcoordsBody->pTcoordRowList, list) + pTcoordRef->data.pLabelOffset->iOffset);
											if(!pTcoordRow) {
												yyerror("テクスチャ座標参照のオフセットが不正です。(%s,%s%+d)", pMeshHdr->pMeshLabel, pTcoordRef->data.pLabelOffset->pLabel, pTcoordRef->data.pLabelOffset->iOffset);
												yynerrs++;	//呼び出し元(main)に知らせるために	//必要。YYERRORマクロ呼び出しでyynerrsは増やされないようだ。	←←←←←←←←←←■■■■重要■■■■
												return NULL;	//y.tab.yの処理でYYERRORを行う。
											}
											pTcoord = pTcoordRow->pTcoord;
										}
										list = list->next;
									}
									if(!pTcoord) {
										yyerror("テクスチャ座標参照のラベルが不正です。(%s,%s)", pMeshHdr->pMeshLabel, pTcoordRef->data.pLabelOffset->pLabel);
										yynerrs++;	//呼び出し元(main)に知らせるために	//必要。YYERRORマクロ呼び出しでyynerrsは増やされないようだ。	←←←←←←←←←←■■■■重要■■■■
										return NULL;	//y.tab.yの処理でYYERRORを行う。
									}
								}
								break;
							}
							if(!pTcoord) { DIE(); }	//バグ
							{
								GSList* list = pTcoordRowList;
								int iTcoordIndex = 0;
								while(list) {
									ST_TcoordRow* pTcoordRow = list->data;
									if((pTcoordRow->pTcoord->s == pTcoord->s) &&
									   (pTcoordRow->pTcoord->t == pTcoord->t)) { break; }
									iTcoordIndex++;
									list = list->next;
								}
								if(!list) {
									ST_TcoordRow* pTcoordRow = TcoordRow_New(pTcoord, NULL);
									if(!pTcoordRow) { DIE(); }	//バグ
									pTcoordRowList = g_slist_append(pTcoordRowList, pTcoordRow);
								}
								pTcoordRef->type		= TcoordRef_type_iTcoordIndex;
								pTcoordRef->data.iTcoordIndex	= iTcoordIndex;
							}
						}
						list = list->next;
					}
				}
				list = list->next;
			}
		}
		pMeshBody->pVectors->pVectorsBody->pVectorRowList = pVectorRowList;
		pMeshBody->pTcoords->pTcoordsBody->pTcoordRowList = pTcoordRowList;
	}
	//エラー検出
	{
		{
			int nv = g_slist_length(pMeshBody->pVectors->pVectorsBody->pVectorRowList);
			if(nv > UCHAR_MAX) {
				yyerror("頂点座標リストの要素数が超過しました。(%s,%d)", pMeshHdr->pMeshLabel, nv);
				yynerrs++;	//呼び出し元(main)に知らせるために	//必要。YYERRORマクロ呼び出しでyynerrsは増やされないようだ。	←←←←←←←←←←■■■■重要■■■■
				return NULL;	//y.tab.yの処理でYYERRORを行う。
			}
		}
		{
			int nc = g_slist_length(pMeshBody->pTcoords->pTcoordsBody->pTcoordRowList);
			if(nc > UCHAR_MAX) {
				yyerror("テクスチャ座標リストの要素数が超過しました。(%s,%d)", pMeshHdr->pMeshLabel, nc);
				yynerrs++;	//呼び出し元(main)に知らせるために	//必要。YYERRORマクロ呼び出しでyynerrsは増やされないようだ。	←←←←←←←←←←■■■■重要■■■■
				return NULL;	//y.tab.yの処理でYYERRORを行う。
			}
		}
		{
			int nf = g_slist_length(pMeshBody->pFaceList);
			if(nf > UCHAR_MAX) {
				yyerror("フェイスリストの要素数が超過しました。(%s,%d)", pMeshHdr->pMeshLabel, nf);
				yynerrs++;	//呼び出し元(main)に知らせるために	//必要。YYERRORマクロ呼び出しでyynerrsは増やされないようだ。	←←←←←←←←←←■■■■重要■■■■
				return NULL;	//y.tab.yの処理でYYERRORを行う。
			}
		}
		{
			GSList* list = pMeshBody->pFaceList;
			while(list) {
				ST_Face* pFace = list->data;
				int nfv = g_slist_length(pFace->pFaceBody->pFaceVertexRowList);
				if(nfv > UCHAR_MAX) {
					yyerror("フェイス頂点リストの要素数が超過しました。(%s,%d)", pMeshHdr->pMeshLabel, nfv);
					yynerrs++;	//呼び出し元(main)に知らせるために	//必要。YYERRORマクロ呼び出しでyynerrsは増やされないようだ。	←←←←←←←←←←■■■■重要■■■■
					return NULL;	//y.tab.yの処理でYYERRORを行う。
				}
				list = list->next;
			}
		}
	}
	pMesh->pMeshHdr		= pMeshHdr;
	pMesh->pMeshBody	= pMeshBody;
	return pMesh;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_MeshHdr* MeshHdr_New(char* pMeshLabel, char* pTextureName/*NULL可*/) {
	ST_MeshHdr* pMeshHdr = calloc(1, sizeof(ST_MeshHdr));
	if(!pMeshHdr) { DIE(); }	//メモリ不足
	if(!pMeshLabel) { DIE(); }	//バグ
	pMeshHdr->pMeshLabel	= pMeshLabel;
	pMeshHdr->pTextureName	= pTextureName/*NULL可*/;
	return pMeshHdr;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_MeshBody* MeshBody_New() {
	ST_MeshBody* pMeshBody = calloc(1, sizeof(ST_MeshBody));
	if(!pMeshBody) { DIE(); }	//メモリ不足
	return pMeshBody;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_MeshBody* MeshBody_AddVectors(ST_MeshBody* pMeshBody, ST_Vectors* pVectors) {
	if(!pMeshBody || !pVectors) { DIE(); }	//バグ
	if(pMeshBody->pVectors) {
		yyerror("頂点座標リストが重複しています。");
		yynerrs++;	//呼び出し元(main)に知らせるために	//必要。YYERRORマクロ呼び出しでyynerrsは増やされないようだ。	←←←←←←←←←←■■■■重要■■■■
		return NULL;	//y.tab.yの処理でYYERRORを行う。
	}
	pMeshBody->pVectors	= pVectors;
	return pMeshBody;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_MeshBody* MeshBody_AddTcoords(ST_MeshBody* pMeshBody, ST_Tcoords* pTcoords) {
	if(!pMeshBody || !pTcoords) { DIE(); }	//バグ
	if(pMeshBody->pTcoords) {
		yyerror("テクスチャ座標リストが重複しています。");
		yynerrs++;	//呼び出し元(main)に知らせるために	//必要。YYERRORマクロ呼び出しでyynerrsは増やされないようだ。	←←←←←←←←←←■■■■重要■■■■
		return NULL;	//y.tab.yの処理でYYERRORを行う。
	}
	pMeshBody->pTcoords	= pTcoords;
	return pMeshBody;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_MeshBody* MeshBody_AddFace(ST_MeshBody* pMeshBody, ST_Face* pFace) {
	if(!pMeshBody || !pFace) { DIE(); }	//バグ
	pMeshBody->pFaceList	= g_slist_append(pMeshBody->pFaceList, pFace);
	return pMeshBody;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_Vectors* Vectors_New(ST_VectorsHdr* pVectorsHdr, ST_VectorsBody* pVectorsBody) {
	ST_Vectors* pVectors = calloc(1, sizeof(ST_Vectors));
	if(!pVectors) { DIE(); }	//メモリ不足
	if(!pVectorsHdr || !pVectorsBody) { DIE(); }	//バグ
	pVectors->pVectorsHdr	= pVectorsHdr;
	pVectors->pVectorsBody	= pVectorsBody;
	return pVectors;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_VectorsHdr* VectorsHdr_New() {
	ST_VectorsHdr* pVectorsHdr = calloc(1, sizeof(ST_VectorsHdr));
	if(!pVectorsHdr) { DIE(); }	//メモリ不足
	return pVectorsHdr;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_VectorsBody* VectorsBody_New() {
	ST_VectorsBody* pVectorsBody = calloc(1, sizeof(ST_VectorsBody));
	if(!pVectorsBody) { DIE(); }	//メモリ不足
	return pVectorsBody;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_VectorsBody* VectorsBody_AddVectorRow(ST_VectorsBody* pVectorsBody, ST_VectorRow* pVectorRow) {
	if(!pVectorsBody || !pVectorRow) { DIE(); }	//バグ
	pVectorsBody->pVectorRowList	= g_slist_append(pVectorsBody->pVectorRowList, pVectorRow);
	return pVectorsBody;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_VectorRow* VectorRow_New(ST_Vector* pVector, char* pVectorLabel/*NULL可*/) {
	ST_VectorRow* pVectorRow = calloc(1, sizeof(ST_VectorRow));
	if(!pVectorRow) { DIE(); }	//メモリ不足
	if(!pVector) { DIE(); }	//バグ
	pVectorRow->pVector		= pVector;
	pVectorRow->pVectorLabel	= pVectorLabel/*NULL可*/;
	return pVectorRow;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_Vector* Vector_New(double x, double y, double z) {
	ST_Vector* pVector = calloc(1, sizeof(ST_Vector));
	if(!pVector) { DIE(); }	//メモリ不足
	pVector->x	= x;
	pVector->y	= y;
	pVector->z	= z;
	return pVector;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_VectorRef* VectorRef_NewVector(ST_Vector* pVector) {
	ST_VectorRef* pVectorRef = calloc(1, sizeof(ST_VectorRef));
	if(!pVectorRef) { DIE(); }	//メモリ不足
	if(!pVector) { DIE(); }	//バグ
	pVectorRef->type		= VectorRef_type_pVector;
	pVectorRef->data.pVector	= pVector;
	return pVectorRef;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_VectorRef* VectorRef_NewIndex(int iVectorIndex) {
	ST_VectorRef* pVectorRef = calloc(1, sizeof(ST_VectorRef));
	if(!pVectorRef) { DIE(); }	//メモリ不足
	pVectorRef->type		= VectorRef_type_iVectorIndex;
	pVectorRef->data.iVectorIndex	= iVectorIndex;
	return pVectorRef;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_VectorRef* VectorRef_NewLabelOffset(char* pVectorLabel, int iOffset) {
	ST_VectorRef* pVectorRef = calloc(1, sizeof(ST_VectorRef));
	if(!pVectorRef) { DIE(); }	//メモリ不足
	if(!pVectorLabel) { DIE(); }	//バグ
	pVectorRef->type		= VectorRef_type_pLabelOffset;
	pVectorRef->data.pLabelOffset	= LabelOffset_New(pVectorLabel, iOffset);
	return pVectorRef;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_Tcoords* Tcoords_New(ST_TcoordsHdr* pTcoordsHdr, ST_TcoordsBody* pTcoordsBody) {
	ST_Tcoords* pTcoords = calloc(1, sizeof(ST_Tcoords));
	if(!pTcoords) { DIE(); }	//メモリ不足
	if(!pTcoordsHdr || !pTcoordsBody) { DIE(); }	//バグ
	pTcoords->pTcoordsHdr	= pTcoordsHdr;
	pTcoords->pTcoordsBody	= pTcoordsBody;
	return pTcoords;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_TcoordsHdr* TcoordsHdr_New() {
	ST_TcoordsHdr* pTcoordsHdr = calloc(1, sizeof(ST_TcoordsHdr));
	if(!pTcoordsHdr) { DIE(); }	//メモリ不足
	return pTcoordsHdr;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_TcoordsBody* TcoordsBody_New() {
	ST_TcoordsBody* pTcoordsBody = calloc(1, sizeof(ST_TcoordsBody));
	if(!pTcoordsBody) { DIE(); }	//メモリ不足
	return pTcoordsBody;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_TcoordsBody* TcoordsBody_AddTcoordRow(ST_TcoordsBody* pTcoordsBody, ST_TcoordRow* pTcoordRow) {
	if(!pTcoordsBody || !pTcoordRow) { DIE(); }	//バグ
	pTcoordsBody->pTcoordRowList = g_slist_append(pTcoordsBody->pTcoordRowList, pTcoordRow);
	return pTcoordsBody;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_TcoordRow* TcoordRow_New(ST_Tcoord* pTcoord, char* pTcoordLabel/*NULL可*/) {
	ST_TcoordRow* pTcoordRow = calloc(1, sizeof(ST_TcoordRow));
	if(!pTcoordRow) { DIE(); }	//メモリ不足
	if(!pTcoord) { DIE(); }	//バグ
	pTcoordRow->pTcoord		= pTcoord;
	pTcoordRow->pTcoordLabel	= pTcoordLabel/*NULL可*/;
	return pTcoordRow;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_Tcoord* Tcoord_New(int s, int t) {
	ST_Tcoord* pTcoord = calloc(1, sizeof(ST_Tcoord));
	if(!pTcoord) { DIE(); }	//メモリ不足
	pTcoord->s	= s;
	pTcoord->t	= t;
	return pTcoord;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_TcoordRef* TcoordRef_NewTcoord(ST_Tcoord* pTcoord) {
	ST_TcoordRef* pTcoordRef = calloc(1, sizeof(ST_TcoordRef));
	if(!pTcoordRef) { DIE(); }	//メモリ不足
	if(!pTcoord) { DIE(); }	//バグ
	pTcoordRef->type		= TcoordRef_type_pTcoord;
	pTcoordRef->data.pTcoord	= pTcoord;
	return pTcoordRef;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_TcoordRef* TcoordRef_NewIndex(int iTcoordIndex) {
	ST_TcoordRef* pTcoordRef = calloc(1, sizeof(ST_TcoordRef));
	if(!pTcoordRef) { DIE(); }	//メモリ不足
	pTcoordRef->type		= TcoordRef_type_iTcoordIndex;
	pTcoordRef->data.iTcoordIndex	= iTcoordIndex;
	return pTcoordRef;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_TcoordRef* TcoordRef_NewLabelOffset(char* pTcoordLabel, int iOffset) {
	ST_TcoordRef* pTcoordRef = calloc(1, sizeof(ST_TcoordRef));
	if(!pTcoordRef) { DIE(); }	//メモリ不足
	if(!pTcoordLabel) { DIE(); }	//バグ
	pTcoordRef->type		= TcoordRef_type_pLabelOffset;
	pTcoordRef->data.pLabelOffset	= LabelOffset_New(pTcoordLabel, iOffset);
	return pTcoordRef;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_Face* Face_New(ST_FaceHdr* pFaceHdr, ST_FaceBody* pFaceBody) {
	ST_Face* pFace = calloc(1, sizeof(ST_Face));
	if(!pFace) { DIE(); }	//メモリ不足
	if(!pFaceHdr || !pFaceBody) { DIE(); }	//バグ
	pFace->pFaceHdr		= pFaceHdr;
	pFace->pFaceBody	= pFaceBody;
	return pFace;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_FaceHdr* FaceHdr_New(int iFaceColor) {
	ST_FaceHdr* pFaceHdr = calloc(1, sizeof(ST_FaceHdr));
	if(!pFaceHdr) { DIE(); }	//メモリ不足
	pFaceHdr->iFaceColor	= iFaceColor;
	return pFaceHdr;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_FaceBody* FaceBody_New() {
	ST_FaceBody* pFaceBody = calloc(1, sizeof(ST_FaceBody));
	if(!pFaceBody) { DIE(); }	//メモリ不足
	return pFaceBody;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_FaceBody* FaceBody_AddFaceVertexRow(ST_FaceBody* pFaceBody, ST_FaceVertexRow* pFaceVertexRow) {
	if(!pFaceBody || !pFaceVertexRow) { DIE(); }	//バグ
	pFaceBody->pFaceVertexRowList = g_slist_append(pFaceBody->pFaceVertexRowList, pFaceVertexRow);
	return pFaceBody;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_FaceVertexRow* FaceVertexRow_New(ST_FaceVertex* pFaceVertex) {
	ST_FaceVertexRow* pFaceVertexRow = calloc(1, sizeof(ST_FaceVertexRow));
	if(!pFaceVertexRow) { DIE(); }	//メモリ不足
	if(!pFaceVertex) { DIE(); }	//バグ
	pFaceVertexRow->pFaceVertex	= pFaceVertex;
	return pFaceVertexRow;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_FaceVertex* FaceVertex_New(ST_VectorRef* pVectorRef, ST_TcoordRef* pTcoordRef/*NULL可*/) {
	ST_FaceVertex* pFaceVertex = calloc(1, sizeof(ST_FaceVertex));
	if(!pFaceVertex) { DIE(); }	//メモリ不足
	if(!pVectorRef) { DIE(); }	//バグ
	pFaceVertex->pVectorRef	= pVectorRef;
	pFaceVertex->pTcoordRef	= pTcoordRef/*NULL可*/;
	return pFaceVertex;
}
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ST_LabelOffset* LabelOffset_New(char* pLabel, int iOffset) {
	ST_LabelOffset* pLabelOffset = calloc(1, sizeof(ST_LabelOffset));
	if(!pLabelOffset) { DIE(); }	//メモリ不足
	if(!pLabel) { DIE(); }	//バグ
	pLabelOffset->pLabel	= pLabel;
	pLabelOffset->iOffset	= iOffset;
	return pLabelOffset;
}
/*---------------------------------------------------------------------------*/
//2パス目の処理
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
static void pass2(int bOptimize) {
	//2018/05/08現在、最適化処理は有りません。
	//今後、最適化機能を追加する場合のためのプレースホルダとして、関数のみ用意して有ります。
	//現在のところは、コマンドラインオプションに'-d'を指定してもしなくても違いは有りません。
	if(bOptimize) { /** no job **/ }
}
/*---------------------------------------------------------------------------*/
//出力処理
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
static void output(const char* sEnmOut, const char* sRegOut) {
	int nOut = 0;
	//列挙定義スクリプトのファイル名,又は,"-"(標準出力)を指定されていたら…
	if(sEnmOut) {
		FILE* fp = strcmp(sEnmOut, "-") ? fopen(sEnmOut, "w") : stdout;
		if(!fp) { error(EXIT_FAILURE, errno, "%s が作成出来ません。", sEnmOut); }	//{{2016/09/21変更:die(〜)で終了していた箇所を、error(EXIT_FAILURE,〜)で終了するように変更しました。}}	//{{2016/09/28変更:error()の文字列の最後に余計な改行が付いていたのを削除しました。}}
		output_enm(fp);
		if(fp != stdout) { fclose(fp); }
		nOut++;
	}
	//レジストリスクリプトのファイル名,又は,"-"(標準出力)が指定されていたら…
	if(sRegOut) {
		FILE* fp = strcmp(sRegOut, "-") ? fopen(sRegOut, "w") : stdout;
		if(!fp) { error(EXIT_FAILURE, errno, "%s が作成出来ません。", sRegOut); }	//{{2016/09/21変更:die(〜)で終了していた箇所を、error(EXIT_FAILURE,〜)で終了するように変更しました。}}	//{{2016/09/28変更:error()の文字列の最後に余計な改行が付いていたのを削除しました。}}
		output_reg(fp);
		if(fp != stdout) { fclose(fp); }
		nOut++;
	}
	if(!nOut) {
		fprintf(stderr, "-u/-rオプションが指定されなかったので、出力を行いませんでした。\n");
	}
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
//列挙定義スクリプトを出力する。
static void output_enm(FILE* fp) {
	//各メッシュについて…
	GSList* list = pMeshList;
	int iMeshNo = 0;
	fprintf(fp, "%s\n", "MeshNo");
	while(list) {
		ST_Mesh* pMesh = list->data;
		iMeshNo++;	//メッシュ番号は1ベースとする事にした。
		//ラベルの一文字目がCシンボルの一文字目として有効な文字ならば…
		if(iscsymf(*pMesh->pMeshHdr->pMeshLabel)) {
			fprintf(fp, "\t%s", pMesh->pMeshHdr->pMeshLabel);
		//ラベルの一文字目がCシンボルの一文字目として無効な文字(多分数字)ならば…
		} else {
			fprintf(fp, "\t`%s", pMesh->pMeshHdr->pMeshLabel);	//ラベルの先頭に「`」を付与する。dEnmDefC.exeのためです。
		}
		//一行目ならば…
		if(iMeshNo == 1) {
			fprintf(fp, "\t%d", iMeshNo);
		}
		fputc('\n', fp);
		list = list->next;
	}
	fprintf(fp, "%s\n", "end");
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
//レジストリスクリプトを出力する。
static void output_reg(FILE* fp) {
	ST_TcoordRef* pTcoordRef_dummy = TcoordRef_NewIndex(0);
	//各メッシュについて…
	GSList* list = pMeshList;
	int iMeshNo = 0;
	fprintf(fp, "%s\t\t\t#//%s\n", "MesDef", "MesDef");
	while(list) {
		ST_Mesh* pMesh = list->data;
		iMeshNo++;	//メッシュ番号は1ベースとする事にした。
		if(pMesh->pMeshHdr->pTextureName) {	//NULL可
			fprintf(fp, "\t%d\t= \"%s\"\t#//\t%s\t= \"%s\"\n", iMeshNo, pMesh->pMeshHdr->pTextureName, pMesh->pMeshHdr->pMeshLabel, pMesh->pMeshHdr->pTextureName);
		}
		fprintf(fp, "\t%d\t= {\t#//\t%s\t= {\n", iMeshNo, pMesh->pMeshHdr->pMeshLabel);
		{
			ST_MeshBody* pMeshBody = pMesh->pMeshBody;
			ST_Vectors* pVectors = pMeshBody->pVectors;
			ST_Tcoords* pTcoords = pMeshBody->pTcoords;
			ST_VectorsBody* pVectorsBody = pVectors->pVectorsBody;
			ST_TcoordsBody* pTcoordsBody = pTcoords->pTcoordsBody;
			GSList/*<ST_VectorRow*>*/* pVectorRowList = pVectorsBody->pVectorRowList;
			GSList/*<ST_TcoordRow*>*/* pTcoordRowList = pTcoordsBody->pTcoordRowList;
			GSList/*<ST_Face*>*/* pFaceList = pMeshBody->pFaceList;
			int nv = g_slist_length(pVectorRowList);
			int nc = g_slist_length(pTcoordRowList);
			int nf = g_slist_length(pFaceList);
			const char* sep = (nv || nc || nf) ? "," : "";
			fprintf(fp, "\t\t  %s{%d,%d,%d,%d}%s\t#//\t\t  %s{%s=%d,%s=%d,%s=%d,%s=%d}%s\n", "byte", nv, nc, nf, 0, sep, "byte", "nv", nv, "nc", nc, "nf", nf, "reserved", 0, sep);
			{
				GSList* list = pVectorRowList;
				while(list) {
					ST_VectorRow* pVectorRow = list->data;
					ST_Vector* pVector = pVectorRow->pVector;
					const char* sep = (list->next || nc || nf) ? "," : "";
					fprintf(fp, "\t\t  %s{%f,%f,%f}%s\t#//\t\t  %s{%s=%f,%s=%f,%s=%f}%s\n", "fp32", pVector->x, pVector->y, pVector->z, sep, "fp32", "x", pVector->x, "y", pVector->y, "z", pVector->z, sep);
					list = list->next;
				}
			}
			{
				GSList* list = pTcoordRowList;
				while(list) {
					ST_TcoordRow* pTcoordRow = list->data;
					ST_Tcoord* pTcoord = pTcoordRow->pTcoord;
					const char* sep = (list->next || nf) ? "," : "";
					fprintf(fp, "\t\t  %s{%d,%d}%s\t#//\t\t  %s{%s=%d,%s=%d}%s\n", "byte", pTcoord->s, pTcoord->t, sep, "byte", "s", pTcoord->s, "t", pTcoord->t, sep);
					list = list->next;
				}
			}
			{
				GSList* list1 = pFaceList;
				while(list1) {
					ST_Face* pFace = list1->data;
					ST_FaceHdr* pFaceHdr = pFace->pFaceHdr;
					ST_FaceBody* pFaceBody = pFace->pFaceBody;
					GSList/*<ST_FaceVertexRow*>*/* pFaceVertexRowList = pFaceBody->pFaceVertexRowList;
					int nfv = g_slist_length(pFaceVertexRowList);
					const char* sep = (list1->next || nfv) ? "," : "";
					fprintf(fp, "\t\t  %s{%d,%d}%s\t#//\t\t  %s{%s=%d,%s=%d}%s\n", "byte", nfv, pFaceHdr->iFaceColor, sep, "byte", "nfv", nfv, "c", pFaceHdr->iFaceColor, sep);
					{
						GSList* list2 = pFaceVertexRowList;
						while(list2) {
							ST_FaceVertexRow* pFaceVertexRow = list2->data;
							ST_FaceVertex* pFaceVertex = pFaceVertexRow->pFaceVertex;
							ST_VectorRef* pVectorRef = pFaceVertex->pVectorRef;
							ST_TcoordRef* pTcoordRef = pFaceVertex->pTcoordRef/*NULL可*/ ? pFaceVertex->pTcoordRef : pTcoordRef_dummy;
							const char* sep = (list1->next || list2->next) ? "," : "";
							if(pVectorRef->type != VectorRef_type_iVectorIndex) { DIE(); }	//バグ	Mesh_New()にて、(type=VectorRef_type_iVectorIndex)に統一されているはず。
							if(pTcoordRef->type != TcoordRef_type_iTcoordIndex) { DIE(); }	//バグ	Mesh_New()にて、(type=TcoordRef_type_iTcoordIndex)に統一されているはず。
							fprintf(fp, "\t\t  %s{%d,%d}%s\t#//\t\t  %s{%s=%d,%s=%d}%s\n", "byte", pVectorRef->data.iVectorIndex, pTcoordRef->data.iTcoordIndex, sep, "byte", "iv", pVectorRef->data.iVectorIndex, "ic", pTcoordRef->data.iTcoordIndex, sep);
							list2 = list2->next;
						}
					}
					list1 = list1->next;
				}
			}
		}
		fprintf(fp, "\t\t  }\t#//\t\t  }\n");
		list = list->next;
	}
	fprintf(fp, "%s\t\t\t#//%s\n", "end", "end");
}
