/*
 *	app.c
 *
 *	dsetargv - ワイルドカード展開ツール
 *	Copyright (C) 2014 Naoyuki Sawa
 *
 *	* Sun Feb 02 23:15:51 JST 2014 Naoyuki Sawa
 *	- 1st リリース。
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <process.h>	/* _spawnvp() */

/* ■重要■
 * ┃コマンドライン引数のワイルドカードを展開するために、
 * ┃[プロジェクトの設定]->[リンク]->[オブジェクト/ライブラリモジュール]に「setargv.obj」を追加しました。
 */

/****************************************************************************
 *	
 ****************************************************************************/

#define VERSION "20140202"

/* オプション */
int opt_Verbose;	/* 1ならば、展開後のコマンドラインを表示する。 */
int opt_Debug;		/* 1ならば、展開後のコマンドラインを表示し、コマンドを実行しない。 */

/*--------------------------------------------------------------------------*/
__declspec(noreturn) void usage();
__declspec(noreturn) void die(const char* fmt, ...);
#define DIE() die(__FILE__, __LINE__)

#define __CLIP_H__
/* getopt */
#include "../../include/getopt.h"
#include "../../getopt.c"
#undef  __CLIP_H__

/****************************************************************************
 *	
 ****************************************************************************/

int main(int argc, char* argv[]) {
	int opt, i;
	/* コマンドラインオプションを処理する。 */
	opterr = 0; /* オプションエラーは当プログラム内で処理するので、getopt()内でのエラー表示は不要。 */
	while((opt = getopt(argc, argv, "hvd")) != -1) {
		switch(opt) {
		default:
		case 'h': usage();
		case 'v': opt_Verbose = 1; break;
		case 'd': opt_Debug   = 1; break;
		}
	}
	if(optind >= argc) { usage(); }
	/* 'v'又は'd'オプションが指定されていたら、展開後のコマンドラインを表示する。 */
	if(opt_Verbose || opt_Debug) {
		for(i = optind; i < argc; i++) {
			if(i != optind) { fprintf(stderr, " "); }
			fprintf(stderr, "%s", argv[i]);
		}
	}
	fprintf(stderr, "\n");
	/* 'd'オプションが指定されていたら、ここまで。 */
	if(opt_Debug) { return EXIT_SUCCESS; }
	/* コマンドを実行する。 */
	//■MSDN ライブラリ Microsoft Visual Studio 6.0 リリース「_spawnvp、_wspawnvp」より引用:
	//┃同期_spawnvpまたは_wspawnvp関数(modeに_P_WAITを指定)からの戻り値は、子プロセスの終了コードです。
	//┃非同期_spawnvpまたは_wspawnvp関数(modeに_P_NOWAITまたは_P_NOWAITOを指定)からの戻り値は、プロセスハンドルです。
	//┃プロセスが正常終了すると、終了ステータスが0になります。
	//┃子プロセスが0以外の引数で明示的にexitルーチンを呼び出すと、終了状態が0以外の値に設定されます。
	//┃子プロセスが明示的に設定した正の終了ステータス以外の正の終了ステータスは、処理の打ち切り、または割り込みによる異常終了を意味します。
	//┃戻り値が-1の場合にはエラー(子プロセスが起動していない)を示します。
	//┃この場合、グローバル変数errnoには以下のいずれかの値が設定されます。
	//┃E2BIG  引数リストが1024バイトを超えている。
	//┃EINVAL modeが無効。
	//┃ENOENT ファイル名またはパス名が見つからない。指定されたファイルが実行可能ファイルでないか、実行可能ファイルの形式が不正である。
	//┃ENOMEM メモリ不足のため子プロセスを実行できない。
	i = _spawnvp(_P_WAIT, argv[optind], &argv[optind]);
	//                                  ~~~~~~~~~~~~~コマンド名も引数として渡す必要があることに注意
	if(i == -1) { die("%sを実行できません。(%s)", argv[optind], strerror(errno)); }
	return i;
}

/*--------------------------------------------------------------------------*/
/* 使い方を表示し、エラー終了する。 */
void usage() {
	fprintf(stderr, "dsetargv - ワイルドカード展開ツール (%s)\n", VERSION);
	fprintf(stderr, "Copyright (C) 2014 Naoyuki Sawa All Rights Reserved.\n");
	fprintf(stderr, "Usage:\n");
	fprintf(stderr, "    dsetargv [-h] [-v] [-d] cmdname [args ...]\n");
	fprintf(stderr, "Options:\n");
	fprintf(stderr, "    -h            使い方を表示します。\n");
	fprintf(stderr, "    -v            コマンドを実行する前に、展開後のコマンドラインを表示します。\n");
	fprintf(stderr, "    -d            展開後のコマンドラインを表示するだけで、実行せず終了します。\n");
	fprintf(stderr, "Example:\n");
	fprintf(stderr, "    ECHOコマンドはそれ自身では引数をワイルドカード展開しませんが、\n");
	fprintf(stderr, "    dsetargvと組み合わせて、ワイルドカード展開することができます。\n");
	fprintf(stderr, "                    ECHO sample*.txt ⇒ sample*.txt\n");
	fprintf(stderr, "    dsetargv CMD /C ECHO sample*.txt ⇒ sample1.txt sample2.txt sample3.txt\n");
	exit(EXIT_FAILURE);
}

/*--------------------------------------------------------------------------*/
/* メッセージを表示し、エラー終了する。 */
void die(const char* fmt, ...) {
	va_list ap;
	va_start(ap, fmt);
	 fprintf(stderr, "\n### ");
	vfprintf(stderr, fmt, ap);
	 fprintf(stderr, "\n");
	va_end(ap);
#ifdef  _DEBUG
	__asm int 3; /* デバッグし易いように、デバッグ時はデバッガで止める */
#endif/*_DEBUG*/
	exit(EXIT_FAILURE);
}

