/*
 *	app.c
 *
 *	dpcsvcc.exe - スプライトシート作成ツール
 *	Copyright (C) 2013-2016 Naoyuki Sawa
 *
 *	* Mon Oct 07 00:00:00 JST 2013 Naoyuki Sawa
 *	- 1st リリース。
 *	  1st リリース時のコメントを残していなかったので、1st リリース日時はファイルの履歴からの推測です。
 *	* Tue Mar 01 21:34:55 JST 2016 Naoyuki Sawa
 *	- プロジェクトの構成を、大幅に変更しました。
 *	  当ツールは、これまで、Makefileでビルドしていました。
 *	  今回、VC++6.0 のプロジェクトに構成し直しました。
 *	- ファイルとファイルの間に余計な1Eが出力されていたバグを修正しました。
 *	  前verまで、下記のバグを内包していました。
 *	  以下なような入力ファイルに対して…
 *	  □'1.txt'
 *	  │1,2,3
 *	  │4,5,6
 *	  □'2.txt'
 *	  │7,8,9
 *	  │A,B,C
 *	  以下のコマンドを実行すると…
 *	  │dpcsvcc.exe 1.txt 2.txt > out.bin
 *	  前verまでは、以下の出力を行ってしまっていました。
 *	  □out.bin
 *	  │31 1F 32 1F 33 1E
 *	  │34 1F 35 1F 36 1D 1E	←この1Eが余計だった。
 *	  │37 1F 38 1F 39 1E
 *	  │41 1F 42 1F 43
 *	  本来、ファイルとファイルの間は一つの1Dで区切られるべきです。
 *	  しかし、前verまでは、1Dの後に余計な1Eが出力されてしまっていました。
 *	  当ツールの出力を使用する次段のツールは、大抵、空レコードを無視するので、このバグは大きな問題にはなっていませんでしたが、バグである事に違いはありません。
 *	  バグの原因は、変数'f_rs'がRSが予約したフラグを、ファイルとファイルの間でクリアするのを忘れていたためです。
 *	  本日、上記の点を修正し、以下の正しい出力が得られるようになりました。
 *	  □out.bin
 *	  │31 1F 32 1F 33 1E
 *	  │34 1F 35 1F 36 1D		←余計な1Eが出力されなくなった。
 *	  │37 1F 38 1F 39 1E
 *	  │41 1F 42 1F 43
 */
#include "app.h"
#define VERSION		"20160301"	//最終更新日
/****************************************************************************
 *	main
 ****************************************************************************/
int main(int argc, char* argv[]) {
	int exitCode = EXIT_SUCCESS;
#ifdef  _DEBUG
//	remove("syslog.out");	//毎回ログを削除する事にした。
	openlog(NULL, LOG_PERROR, LOG_USER);
#endif//_DEBUG
#if     (defined(GC_H) && !defined(USE_BISON_FLEX))
//	putenv("GC_LOG_FILE=CON");//ログ出力先を指定する。
//	GC_set_find_leak(1);//メモリリーク検出を開始する。
#endif//(defined(GC_H) && !defined(USE_BISON_FLEX))
#if     (defined(GC_H) && defined(PTHREAD_H))
	GC_init();//この中でGCスレッドが起動する。メインスレッドをpthread_exit()等で終了するとGCスレッドが残ってプロセスが終了しないので注意せよ。
	GC_allow_register_threads();
#endif//(defined(GC_H) && defined(PTHREAD_H))
#ifdef  __CLIP_SEH_H__
	SEH_init();
#endif//__CLIP_SEH_H__
	app_init(argc, argv);
	exitCode = app_main(argc, argv);
	app_exit();
#if     (defined(GC_H) && !defined(USE_BISON_FLEX))
//	CHECK_LEAKS();//メモリリークを検出する。
#endif//(defined(GC_H) && !defined(USE_BISON_FLEX))
	return exitCode;
}
/****************************************************************************
 *	usage
 ****************************************************************************/
__declspec(noreturn) static void usage() {
	fprintf(stderr, "dpcsvcc.exe - CSV⇒ASCII制御文字分割 変換ユーティリティ (%s)\n", VERSION);
	fprintf(stderr, "Copyright (C) 2013-2016 Naoyuki Sawa\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "USAGE:\n");
	fprintf(stderr, "  dpcsvcc [filename ...] \n");
	fprintf(stderr, "  ・filenameを指定しなければ、標準入力から読み込みます。\n");
	fprintf(stderr, "  ・filenameは、ワイルドカードによる複数指定も可能です。\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "OPTIONS:\n");
	fprintf(stderr, "  -c 入力書式をカンマ区切りとします。(*初期値)\n");
	fprintf(stderr, "  -t 入力書式をタブ区切りとします。\n");
	fprintf(stderr, "     -cと-tを同時に指定してはいけません。\n");
	fprintf(stderr, "  -h 使い方を表示します。\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "DESCRIPTION:\n");
	fprintf(stderr, "  CSVの区切り文字を、ASCII制御文字に変換します。\n");
	fprintf(stderr, "  ・カンマ⇒US(1F)に変換します。\n");
	fprintf(stderr, "  ・改行  ⇒RS(1E)に変換します。ただし、最後のRSは出力しません。\n");
	fprintf(stderr, "  ・filenameを複数指定した場合、ファイル間をGS(1D)で区切ります。\n");
	fprintf(stderr, "  ・空ユニット、及び、空レコードも有効です。\n");
	fprintf(stderr, "  ・ユニット文字列を「\"」で囲むと、「,」及び改行を含められます。\n");
	fprintf(stderr, "  ・「\"」で囲んだユニット文字列の中で、「\"\"」は「\"」を表します。\n");
	exit(EXIT_FAILURE);
}
/****************************************************************************
 *	
 ****************************************************************************/
void app_init(int argc, char* argv[]) {
	/** no job **/
}
/*--------------------------------------------------------------------------*/
void app_exit() {
	/** no job **/
}
/*--------------------------------------------------------------------------*/
int app_main(int argc, char* argv[]) {
	int opt;
#if     (YYDEBUG!=0)
//	yydebug = 1; /* nonzero means print parse trace */
#endif/*(YYDEBUG!=0)*/
	//コマンドラインオプションを処理する。
	opterr = 0; //オプションエラーは当プログラム内で処理するので、getopt()内でのエラー表示は不要。
	while((opt = getopt(argc, argv, "hct")) != -1) {
		switch(opt) {
		case 'c':
		case 't':
			if(opt_FS) { usage(); }
			opt_FS = opt;
			break;
		case 'h':
		default:
			usage();
		}
	}
	//セパレータが指定されていなければ、カンマ区切りとする。
	if(!opt_FS) { opt_FS = 'c'; }
	//ファイルが指定されていなければ、標準入力から読み込む。
	if(optind == argc) {
		yylex_init(stdin);
		if((yyparse() != 0) || (yynerrs != 0)) { error(EXIT_FAILURE, 0, "文法エラーが発生しました。\n"); }
	//ファイルが指定されていたら、各ファイルを読み込む。
	} else {
		int i;
		for(i = optind; i < argc; i++) {
			FILE* fp = fopen(argv[i], "r");
			if(!fp) { error(EXIT_FAILURE, errno, "%s が開けません。\n", argv[i]); }
			if(i != optind) { printf("\x1D"); }	//1D = ASCII制御文字 GS (Group Separator)
			yylex_init(fp);
			if((yyparse() != 0) || (yynerrs != 0)) { error(EXIT_FAILURE, 0, "%s: 文法エラーが発生しました。\n", argv[i]); }
			fclose(fp);
//{{2016/03/01追加:ファイルとファイルの間に余計な1Eが出力されていたバグを修正しました。
			f_rs = 0;	//各ファイルの最後に予約したRSの予約をクリアする。
//}}2016/03/01追加:ファイルとファイルの間に余計な1Eが出力されていたバグを修正しました。
		}
	}
	return EXIT_SUCCESS;
}
