[PR]

水無瀬の部屋 > Programming > sample > tools > argcargv.cpp
最終更新日: 2007/03/30

   1: //*********************************************************
   2: // プロジェクト: TOOLS::ARGCARGV
   3: //   ファイル名: argcargv.cpp
   4: //*********************************************************
   5: #include <header/argcargv.h> //
   6: #include <header/tooldbg.h>  // VALID_TEST(), ASSERT(), 
   7: #include <header/toolbase.h> // 
   8: #include <mbstring.h>        // _ismbblead(), 
   9: 
  10: 
  11: //---------------------------------------------------------
  12: // テスト関数 の 宣言
  13: //---------------------------------------------------------
  14: DECLARE_TESTPROC( test_argcargv );
  15: 
  16: 
  17: //---------------------------------------------------------
  18: // 定数型マクロ の 定義
  19: //---------------------------------------------------------
  20: #define DBG_ALLOCNAME  "argcargv"
  21: 
  22: 
  23: //---------------------------------------------------------
  24: // ファイルスコープ関数 の 宣言
  25: //---------------------------------------------------------
  26: static size_t parse_cmdline( const char *p, char **argv, int *argc, char *buf, DWORD flag );
  27: 
  28: 
  29: //*********************************************************
  30: // argcargv()
  31: //  コマンドライン文字列 cmdline を 引数配列 argv[ argc ] に分割する。
  32: //  使用した引数配列 argv[ argc ] は free_argcargv() で解放せよ。
  33: //
  34: // int *argc
  35: //   配列 argv の 要素数 を受け取る 変数
  36: //
  37: // const char *cmdline
  38: //   引数配列 に分割する コマンドライン文字列
  39: //
  40: // const bool bRemoveQuote
  41: //   真 を指定すると 二重引用符 " を取り除く
  42: //
  43: //*********************************************************
  44: char ** // 配列
  45: argcargv
  46: 	(
  47: 		      int   *argc,     // 分割後の配列数を返す
  48: 		const char  *cmdline,  // コマンドライン文字列
  49: 		      DWORD  flag      // 分割方法
  50: 	)
  51: {
  52: 	CALLONCE_TESTPROC( test_argcargv ); // [テスト]
  53: 
  54: 	// パラメタの仮定
  55: 	ASSERT( IsValidStringPtr( cmdline ) );
  56: 	ASSERT( IsValidPtr( argc, sizeof( *argc ) ) );
  57: 
  58: 	// 必要な バッファサイズ を計算する
  59: 	const size_t bufsize = parse_cmdline( cmdline, null, argc, null, flag );
  60: 	if ( bufsize <= 0 )
  61: 		return null;
  62: 	
  63: 	//
  64: 	// バッファを確保する
  65: 	// バッファサイズ bufsize は既に バイト数 である。
  66: 	//
  67: 	char *buffer = (char *)malloc( bufsize ); // sizeof( *buffer ) 不要!
  68: 	if ( !buffer )
  69: 		return null;
  70: 
  71: 	// 分割
  72: 	char **argv = static_cast<char **>( static_cast<void *>(buffer) );
  73: 	VERIFY( bufsize == parse_cmdline
  74: 		(
  75: 			cmdline,                                  //
  76: 			argv,                                     //
  77: 			argc,                                     //
  78: 			buffer + ((1 + *argc) * sizeof( *argv )), //
  79: 			flag                              //
  80: 		) );
  81: 	ASSERT( IsValidArgcArgv( *argc, argv ) );
  82: 
  83: 	//
  84: 	DBG_LOCK_ALLOCED_MEMORY( argv, DBG_ALLOCNAME ); // [DBG]
  85: 	return argv;
  86: }//argcargv
  87: 
  88: //*********************************************************
  89: // free_argcargv()
  90: //*********************************************************
  91: bool
  92: free_argcargv
  93: 	(
  94: 		int    _unuse( argc ),
  95: 		char **argv
  96: 	)
  97: {
  98: 	CALLONCE_TESTPROC( test_argcargv ); // [テスト]
  99: 
 100: 	// パラメタの仮定
 101: 	ASSERT( IsValidArgcArgv( argc, argv ) );
 102: 
 103: 
 104: 	DBG_UNLOCK_ALLOCED_MEMORY( argv, DBG_ALLOCNAME ); // [DBG]
 105: 	free( argv );
 106: 
 107: 	return true;
 108: }//free_argcargv
 109: 
 110: 
 111: //******************************************************************************************************************
 112: // private
 113: //******************************************************************************************************************
 114: static const char *eat_pgname( const char *p, char *buf, size_t *pos, DWORD flag );
 115: static const char *eat_param( const char *p, char *buf, size_t *pos, DWORD flag );
 116: static const char *skip_space( const char *p );
 117: static void set_argv( char **argv, int argc, char *p ){ if ( argv ){ argv[ argc ] = p; } }
 118: 
 119: 
 120: //*********************************************************
 121: // parse_cmdline()
 122: //  コマンドライン文字列 cmdline を 引数配列 argv[ argc ] に分割する。
 123: //
 124: // const char *p
 125: //   引数配列 に分割する コマンドライン文字列
 126: //
 127: // char **argv
 128: //   分割後の引数文字列の配列 を受け取る 変数
 129: //
 130: // int *argc
 131: //   配列 argv の 要素数 を受け取る 変数
 132: //
 133: // char *buf
 134: //   分割した引数配列の格納場所
 135: //
 136: // const bool bRemoveQuote
 137: //   真 を指定すると 二重引用符 " を取り除く
 138: //
 139: //*********************************************************
 140: static
 141: size_t // バイト数
 142: parse_cmdline
 143: 	(
 144: 		const char   *p,    // コマンドライン文字列
 145: 		      char  **argv, // 引数文字列の配列
 146: 		      int    *argc, // 引数文字列の数
 147: 		      char   *buf,  // 
 148: 		      DWORD   flag  // 分割方法
 149: 	)
 150: {
 151: 	// パラメタの仮定
 152: 	ASSERT( IsValidStringPtr( p ) );
 153: 	ASSERT( (!argv && !buf) || (argv && buf) );
 154: 	ASSERT( IsValidPtr( argc, sizeof( *argc ) ) );
 155: //	ASSERT( !buffer || (DESTROY_TEXT_BUFFER( buffer, bufsize ), true) ); // [破壊]
 156: 
 157: 	//
 158: 	size_t pos = 0;
 159: 
 160: 	// プログラム名で区切る
 161: 	*argc = 0;
 162: 	set_argv( argv, *argc, buf + pos );
 163: 	p = eat_pgname( p, buf, &pos, flag );
 164: 	++(*argc);
 165: 
 166: 	// 最初の引数へ移動
 167: 	p = skip_space( p );
 168: 
 169: 	// 引数の並びを分割する
 170: 	while( '\0' != *p )
 171: 	{
 172: 		//
 173: 		set_argv( argv, *argc, buf + pos );
 174: 		p = eat_param( p, buf, &pos, flag );
 175: 		++(*argc);
 176: 
 177: 		// 次の引数へ移動
 178: 		p = skip_space( p );
 179: 	}
 180: 
 181: 	// 配列の最後 argv[ argc ] に null を付加する
 182: 	set_argv( argv, *argc, null ); 
 183: 	
 184: 	// 出力バイト数
 185: 	return (pos * sizeof( *buf )) + ((1 + *argc) * sizeof( *argv ));
 186: }//parse_cmdline
 187: 
 188: 
 189: //******************************************************************************************************************
 190: // private
 191: //******************************************************************************************************************
 192: static const char *skip_quote( const char *p, char *buf, size_t *pos, DWORD flag );
 193: static const char *copy_char( const char *p, char *buf, size_t *pos );
 194: static void put_char( char *buf, size_t *pos, char c );
 195: 
 196: 
 197: //*********************************************************
 198: // eat_pgname
 199: // プログラム名を読み込む
 200: //*********************************************************
 201: static
 202: const char *
 203: eat_pgname
 204: 	(
 205: 		const char   *p,   // コマンドライン文字列
 206: 		      char   *buf, // 書き込み位置
 207: 		      size_t *pos, // 総文字数
 208: 		      DWORD   flag // 分割方法
 209: 	)
 210: {
 211: 	// パラメタの仮定
 212: 	ASSERT( IsValidStringPtr( p ) );
 213: 
 214: 	if ( '\"' != *p )
 215: 	{
 216: 		// 次の空白類文字までがプログラム名
 217: 		const size_t len = jmscspn( p, " \t" );
 218: 		if ( buf ){ memmove( buf + *pos, p, len ); }
 219: 		*pos += len;
 220: 		p += len;
 221: 	}
 222: 	else // 二重引用符 " で囲まれている場合
 223: 	{
 224: 		// 二重引用符 " を読み飛ばす
 225: 		p = skip_quote( p, buf, pos, flag );
 226: 
 227: 		// 次の二重引用符 " までがプログラム名
 228: 		const size_t len = jmscspn( p, "\"" );
 229: 		if ( buf ){ memmove( buf + *pos, p, len ); }
 230: 		*pos += len;
 231: 		p += len;
 232: 
 233: 		// 二重引用符 " を読み飛ばす
 234: 		if ( '\"' == *p )
 235: 		{
 236: 			p = skip_quote( p, buf, pos, flag );
 237: 		}
 238: 	}
 239: 
 240: 	// 文字列を完結する
 241: 	put_char( buf, pos, '\0' );
 242: 
 243: 	return p;
 244: }//eat_pgname
 245: 
 246: //*********************************************************
 247: // eat_param
 248: // 引数を読み込む
 249: //*********************************************************
 250: static
 251: const char *
 252: eat_param
 253: 	(
 254: 		const char   *p,   // コマンドライン文字列
 255: 		      char   *buf, // 書き込み位置
 256: 		      size_t *pos, // 総文字数
 257: 		      DWORD   flag // 分割方法
 258: 	)
 259: {
 260: 	// パラメタの仮定
 261: 	ASSERT( IsValidStringPtr( p ) );
 262: 
 263: 	bool bInQuote = false;
 264: 
 265: 	{for( ; ; )
 266: 	{
 267: 		const size_t numslash = jmsspn( p, "\\" );
 268: 		p += numslash;
 269: 
 270: 		if ( '\"' != *p ) // \x
 271: 		{
 272: 			// 文字 '\\\\' はそのまま複写
 273: 			{for( int i = 0; i < (int)numslash; ++i )
 274: 			{
 275: 				put_char( buf, pos, '\\' );
 276: 			}}
 277: 		
 278: 			if ( ('\0' == *p) || ( !bInQuote && ((' ' == *p) || ('\t' == *p)) ) )
 279: 			{
 280: 				goto for_out; // break for;
 281: 			}
 282: 		
 283: 			p = copy_char( p, buf, pos );
 284: 		}
 285: 		else // \"
 286: 		{
 287: 			// 文字 '\\\\' は半分複写
 288: 			// '\\' => '\'
 289: 			{for( int i = 0; i < (int)(FLG_ARGCARGV_REMOVEQUOTE == (FLG_ARGCARGV_REMOVEQUOTE & flag) ? (numslash / 2) : numslash); ++i )
 290: 			{
 291: 				put_char( buf, pos, '\\' );
 292: 			}}
 293: 
 294: 			if ( 0 != (numslash % 2) ) // \"
 295: 			{
 296: 				// 二重引用符 " の効果無効
 297: 				p = copy_char( p, buf, pos ); // 二重引用符 " を書き出す
 298: 			}
 299: 			else // "
 300: 			{
 301: 				p = skip_quote( p, buf, pos, flag ); // 二重引用符 " を読み飛ばす
 302: 
 303: 				if ( bInQuote && ('\"' == *p) ) // ""
 304: 				{
 305: 					p = copy_char( p, buf, pos ); // 2つ目の二重引用符 " は書き出す
 306: 				}
 307: 
 308: 				// 内外反転
 309: 				bInQuote = !bInQuote;
 310: 			}
 311: 		}
 312: 	}}
 313: for_out:
 314: 
 315: 	// 文字列を完結する
 316: 	put_char( buf, pos, '\0' );
 317: 
 318: 	return p;
 319: }//eat_param
 320: 
 321: 
 322: //******************************************************************************************************************
 323: //
 324: //******************************************************************************************************************
 325: //*********************************************************
 326: // skip_space
 327: // 空白を読み飛ばす
 328: //*********************************************************
 329: static
 330: const char *
 331: skip_space
 332: 	(
 333: 		const char *string
 334: 	)
 335: {
 336: 	// パラメタの仮定
 337: 	ASSERT( IsValidStringPtr( string ) );
 338: 
 339: 	return strskip( string, " \t" );
 340: }//skip_space
 341: 
 342: //*********************************************************
 343: // skip_quote
 344: // '\"' を読み飛ばす
 345: //   bRemoveQuote …… 二重引用符 " を取り除く
 346: //*********************************************************
 347: static
 348: const char *
 349: skip_quote
 350: 	(
 351: 		const char   *p,
 352: 		      char   *buf,
 353: 		      size_t *pos,
 354: 		      DWORD   flag // 分割方法
 355: 	)
 356: {
 357: 	// パラメタの仮定
 358: 	ASSERT( IsValidStringPtr( p ) );
 359: 	ASSERT( '\"' == *p );
 360: 
 361: 	if ( FLG_ARGCARGV_REMOVEQUOTE == (FLG_ARGCARGV_REMOVEQUOTE & flag) )
 362: 	{
 363: 		++p; // 二重引用符 " を読み飛ばす
 364: 	}
 365: 	else
 366: 	{
 367: 		// そのまま複写
 368: 		p = copy_char( p, buf, pos );
 369: 	}
 370: 
 371: 	return p;
 372: }//skip_quote
 373: 
 374: //*********************************************************
 375: // copy_char
 376: // バッファに1文字複写する
 377: //*********************************************************
 378: static
 379: const char *
 380: copy_char
 381: 	(
 382: 		const char   *p,
 383: 		      char   *buf,
 384: 		      size_t *pos
 385: 	)
 386: {
 387: 	// パラメタの仮定
 388: 	ASSERT( IsValidStringPtr( p ) );
 389: 
 390: 	if ( _ismbblead( *p ) )
 391: 	{
 392: 		put_char( buf, pos, *p );
 393: 		++p;
 394: 	}
 395: 
 396: 	put_char( buf, pos, *p );
 397: 	++p;
 398: 
 399: 	return p;
 400: }//copy_char
 401: 
 402: //*********************************************************
 403: // put_char
 404: // バッファに1バイト複写する
 405: //*********************************************************
 406: static
 407: void
 408: put_char
 409: 	(
 410: 		char   *buf, // 
 411: 		size_t *pos, //
 412: 		char    c    // 
 413: 	)
 414: {
 415: 	if ( buf )
 416: 	{
 417: 		buf[ *pos ] = c;
 418: 	}
 419: 
 420: 	++*pos;
 421: }//put_char
 422: 
 423: 
 424: //******************************************************************************************************************
 425: // TEST
 426: //******************************************************************************************************************
 427: 
 428: 
 429: #ifdef _DEBUG // デバッグ時のみ
 430: 
 431: 
 432: //*********************************************************
 433: // test_argcargv
 434: //*********************************************************
 435: DEFINE_TESTPROC( test_argcargv )
 436: {
 437: 	//---------------------------------------------------------
 438: 	// 定数 の テスト
 439: 	//---------------------------------------------------------
 440: 
 441: 	//---------------------------------------------------------
 442: 	// ファイルスコープ関数 の テスト
 443: 	//---------------------------------------------------------
 444: 
 445: 	//---------------------------------------------------------
 446: 	// 公開関数 の テスト
 447: 	//---------------------------------------------------------
 448: 	//
 449: 	{
 450: 		//
 451: 		int argc;
 452: 		char **argv = argcargv( &argc, GetCommandLine(), FLG_ARGCARGV_MSDEFAULT );
 453: 		VERIFY( IsValidArgcArgv( argc, argv ) );
 454: 		VERIFY( argc == __argc );
 455: 		{for( int i = 0; i < argc; ++i )
 456: 		{
 457: 			VERIFY( streql( argv[ i ], __argv[ i ] ) );
 458: 		}}
 459: 		free_argcargv( argc, argv );
 460: 	}
 461: 
 462: 	//
 463: 	{
 464: 		const struct 
 465: 			{
 466: 				      int   argc;
 467: 				const char *cmdline;
 468: 				const char *argv1a;  // bRemoveQuote = true
 469: 				const char *argv2a;  //
 470: 				const char *argv3a;  //
 471: 				const char *argv1b;  // bRemoveQuote = false
 472: 				const char *argv2b;  //
 473: 				const char *argv3b;  //
 474: 			}
 475: 		testcase[] =
 476: 			{
 477: #define MAKE_TESTCASE( argc, cmdline, argv1a, argv2a, argv3a, argv1b, argv2b, argv3b ) { argc, cmdline, argv1a, argv2a, argv3a, argv1b, argv2b, argv3b }
 478: 				MAKE_TESTCASE( 2, "argv[0] \"a\"\"b\"\"c\"", "argv[0]", "a\"bc", null, "argv[0]", "\"a\"\"b\"\"c\"", null ),
 479: //				MAKE_TESTCASE( 2, "argv[0] \"a\"\"b\"\"c\"", "argv[0]", "a\"\"b\"\"c", null, "argv[0]", "\"a\"\"b\"\"c\"", null ),
 480: 				MAKE_TESTCASE( 2, "argv[0] /a:\"b c\"", "argv[0]", "/a:b c", null, "argv[0]", "/a:\"b c\"", null ),
 481: 				MAKE_TESTCASE( 3, "a b c", "a", "b", "c", "a", "b", "c" ),
 482: 				MAKE_TESTCASE( 3, "a b \"c\"", "a", "b", "c", "a",     "b",     "\"c\"" ),
 483: 				MAKE_TESTCASE( 3, "a \"b\" c", "a", "b", "c", "a",     "\"b\"", "c"     ),
 484: 				MAKE_TESTCASE( 3, "\"a\" b c", "a", "b", "c", "\"a\"", "b",     "c"     ),
 485: 				MAKE_TESTCASE( 3, "a \"b\" \"c\"", "a", "b", "c", "a",     "\"b\"", "\"c\"" ),
 486: 				MAKE_TESTCASE( 3, "\"a\" b \"c\"", "a", "b", "c", "\"a\"", "b",     "\"c\"" ),
 487: 				MAKE_TESTCASE( 3, "\"a\" \"b\" c", "a", "b", "c", "\"a\"", "\"b\"", "c"     ),
 488: 				MAKE_TESTCASE( 3, "\"a\" \"b\" \"c\"", "a", "b", "c", "\"a\"", "\"b\"", "\"c\"" ),
 489: 				MAKE_TESTCASE( 3, "aa bb cc", "aa", "bb", "cc", "aa", "bb", "cc" ),
 490: 				MAKE_TESTCASE( 3, "aa bb \"cc\"", "aa", "bb", "cc", "aa",     "bb",     "\"cc\"" ),
 491: 				MAKE_TESTCASE( 3, "aa \"bb\" cc", "aa", "bb", "cc", "aa",     "\"bb\"", "cc"     ),
 492: 				MAKE_TESTCASE( 3, "\"aa\" bb cc", "aa", "bb", "cc", "\"aa\"", "bb",     "cc"     ),
 493: 				MAKE_TESTCASE( 3, "aa \"bb\" \"cc\"", "aa", "bb", "cc", "aa",     "\"bb\"", "\"cc\"" ),
 494: 				MAKE_TESTCASE( 3, "\"aa\" bb \"cc\"", "aa", "bb", "cc", "\"aa\"", "bb",     "\"cc\"" ),
 495: 				MAKE_TESTCASE( 3, "\"aa\" \"bb\" cc", "aa", "bb", "cc", "\"aa\"", "\"bb\"", "cc"     ),
 496: 				MAKE_TESTCASE( 3, "\"aa\" \"bb\" \"cc\"", "aa", "bb", "cc", "\"aa\"", "\"bb\"", "\"cc\"" ),
 497: 				MAKE_TESTCASE( 3, "\"a a\" \"b b\" \"c c\"", "a a", "b b", "c c", "\"a a\"", "\"b b\"", "\"c c\"" ),
 498: 				MAKE_TESTCASE( 3, "\" \" \" \" \" \"", " ", " ", " ", "\" \"", "\" \"", "\" \"" ),
 499: 				MAKE_TESTCASE( 3, "\"\" \"\" \"\"", "", "", "", "\"\"", "\"\"", "\"\"" ),
 500: #undef MAKE_TESTCASE
 501: 			};
 502: 		{for( int i = 0; i < numof( testcase ); ++i )
 503: 		{
 504: 			//
 505: 			{
 506: 				int argc;
 507: 				char **argv = argcargv( &argc, testcase[ i ].cmdline, FLG_ARGCARGV_REMOVEQUOTE );
 508: 				VERIFY( IsValidArgcArgv( argc, argv ) );
 509: 				VERIFY( argc == testcase[ i ].argc );
 510: 				VERIFY( (argc <= 0) || streql( argv[ 0 ], testcase[ i ].argv1a ) );
 511: 				VERIFY( (argc <= 1) || streql( argv[ 1 ], testcase[ i ].argv2a ) );
 512: 				VERIFY( (argc <= 2) || streql( argv[ 2 ], testcase[ i ].argv3a ) );
 513: 				free_argcargv( argc, argv );
 514: 			}
 515: 
 516: 			//			
 517: 			{
 518: 				int argc;
 519: 				char **argv = argcargv( &argc, testcase[ i ].cmdline, 0 );
 520: 				VERIFY( IsValidArgcArgv( argc, argv ) );
 521: 				VERIFY( argc == testcase[ i ].argc );
 522: 				VERIFY( (argc <= 0) || streql( argv[ 0 ], testcase[ i ].argv1b ) );
 523: 				VERIFY( (argc <= 1) || streql( argv[ 1 ], testcase[ i ].argv2b ) );
 524: 				VERIFY( (argc <= 2) || streql( argv[ 2 ], testcase[ i ].argv3b ) );
 525: 				free_argcargv( argc, argv );
 526: 			}
 527: 		}}
 528: 	}
 529: }//test_argcargv
 530: 
 531: 
 532: #endif // #ifdef _DEBUG
 533: 
 534: 
 535: //** end **
 536: 

参照:


Google
ご意見・ご感想をお聞かせ下さい。匿名で送信できます。

 * 返信が必要な場合には postmaster@katsura-kotonoha.sakura.ne.jp へ直接メールしてください。

水無瀬の部屋 > sample > tools > argcargv.cpp

このページは cpp2web が出力しました。
水無瀬 優 postmaster@katsura-kotonoha.sakura.ne.jp
http://katsura-kotonoha.sakura.ne.jp/prog/code/tools/argcargv_cpp.shtml
>> Amazon.co.jp 『たまゆら童子』 へ
>> 楽天ブックス 『たまゆら童子』 へ