水無瀬の部屋 > Programming > sample > tools > argcargv.cpp |
---|
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:
参照:
水無瀬の部屋 > sample > tools > argcargv.cpp |
---|
このページは cpp2web が出力しました。
水無瀬 優 postmaster@katsura-kotonoha.sakura.ne.jp
http://katsura-kotonoha.sakura.ne.jp/prog/code/tools/argcargv_cpp.shtml