分解复杂的命令行参数
当我们的程序需要运行在命令行环境下的时候,分解复杂的命令行参数往往成为一件不难但又麻烦的事情。我们经常发现.net的开发工具的命令行格式都是"/parameterA:valueA /parameterB:valueB"。如果我们希望使用这种格式的命令行参数的话,如何分析就成为我们需要解决的一个问题。
我们可以通过WinMain或者GetCommandLine()来获得一个unicode格式的命令行参数。这个命令行参数是没有被分析过的,一个完整的字符串。首先,我们使用空格分解字符串,不过在遇到双引号的时候,我们忽略空格一直到遇到另一个双引号为止。所以下面的命令行参数:
"
e:\Coding\VL++\Tools\KfpCompiler\Debug\KfpCompiler.exe
"
/
library:
"
C:\Kernel FP\Library\
"
/
output:
"
C:\Kernel FP\Output\
"
/
code:
"
C:\Kernel FP\Game\Project.kproj
"
/
print
-
error
/
print
-
report
将会被分解成6行:
1
"
e:\Coding\VL++\Tools\KfpCompiler\Debug\KfpCompiler.exe
"
2 / library: " C:\Kernel FP\Library\ "
3 / output: " C:\Kernel FP\Output\ "
4 / code: " C:\Kernel FP\Game\Project.kproj "
5 / print - error
6 / print - report
2 / library: " C:\Kernel FP\Library\ "
3 / output: " C:\Kernel FP\Output\ "
4 / code: " C:\Kernel FP\Game\Project.kproj "
5 / print - error
6 / print - report
对于每一行的命令,我们可以总结出以下几种格式:
1、值
2、/参数
3、/参数:值
我们可以规定,如果值的第一个字符和最后一个字符都是双引号的话,那么忽略这两个双引号。我使用Vczh GUI写了一个win32程序显示命令行分析的结果,代码和截图如下:
首先是程序的代码。这个程序阅读命令行参数之后,将分析结果显示在一个文本框上:
1
#include
"
..\..\..\Library\Windows\VL_WinGUI.h
"
2
3 using namespace vl;
4 using namespace vl::windows;
5 using namespace vl::windows::placement;
6
7 class MainForm : public VL_WinForm
8 {
9 protected :
10 VL_WinEdit * edtCommandLines;
11
12 void InitControls()
13 {
14 edtCommandLines = new VL_WinEdit( this , true );
15 edtCommandLines -> SetVScroll( true );
16 edtCommandLines -> SetHScroll( true );
17
18 ApplyPlacement(
19 pControl(edtCommandLines, 10 )
20 );
21
22 this -> OnShow.Bind( this , & MainForm::MainForm_OnShow);
23 }
24
25 void MainForm_OnShow(VL_Base * Sender)
26 {
27 VL_WinParameters * Parameters = GetApplication() -> GetParameters();
28 Parameters -> Parse(L ' / ' ,L ' : ' );
29 VUnicodeString Output;
30
31 Output += L " Command : [ " + Parameters -> GetCommandLineString() + L " ]\r\n " ;
32 for (VInt i = 0 ;i < Parameters -> GetCount();i ++ )
33 {
34 Output += L " Parameter : [ " + Parameters -> GetParameter(i) + L " ]\r\n " ;
35 Output += L " Value : [ " + Parameters -> GetValue(i) + L " ]\r\n " ;
36 }
37 edtCommandLines -> SetText(Output);
38 }
39
40 public :
41 MainForm():VL_WinForm( true )
42 {
43 SetClientWidth( 400 );
44 SetClientHeight( 300 );
45 SetBorder(vwfbSingle);
46 SetText(L " Command Lines " );
47 InitControls();
48 MoveCenter();
49 }
50 };
51
52 void main()
53 {
54 ( new MainForm) -> Show();
55 GetApplication() -> Run();
56 }
2
3 using namespace vl;
4 using namespace vl::windows;
5 using namespace vl::windows::placement;
6
7 class MainForm : public VL_WinForm
8 {
9 protected :
10 VL_WinEdit * edtCommandLines;
11
12 void InitControls()
13 {
14 edtCommandLines = new VL_WinEdit( this , true );
15 edtCommandLines -> SetVScroll( true );
16 edtCommandLines -> SetHScroll( true );
17
18 ApplyPlacement(
19 pControl(edtCommandLines, 10 )
20 );
21
22 this -> OnShow.Bind( this , & MainForm::MainForm_OnShow);
23 }
24
25 void MainForm_OnShow(VL_Base * Sender)
26 {
27 VL_WinParameters * Parameters = GetApplication() -> GetParameters();
28 Parameters -> Parse(L ' / ' ,L ' : ' );
29 VUnicodeString Output;
30
31 Output += L " Command : [ " + Parameters -> GetCommandLineString() + L " ]\r\n " ;
32 for (VInt i = 0 ;i < Parameters -> GetCount();i ++ )
33 {
34 Output += L " Parameter : [ " + Parameters -> GetParameter(i) + L " ]\r\n " ;
35 Output += L " Value : [ " + Parameters -> GetValue(i) + L " ]\r\n " ;
36 }
37 edtCommandLines -> SetText(Output);
38 }
39
40 public :
41 MainForm():VL_WinForm( true )
42 {
43 SetClientWidth( 400 );
44 SetClientHeight( 300 );
45 SetBorder(vwfbSingle);
46 SetText(L " Command Lines " );
47 InitControls();
48 MoveCenter();
49 }
50 };
51
52 void main()
53 {
54 ( new MainForm) -> Show();
55 GetApplication() -> Run();
56 }
然后是运行结果:
程序中用到的VL_WinParameters类的代码如下:
头文件:
1
class
VL_WinParameters :
public
VL_Base
2 {
3 protected :
4 class CommandPair
5 {
6 public :
7 typedef VL_List < CommandPair , false > List;
8
9 VUnicodeString Parameter;
10 VUnicodeString Value;
11 };
12
13 VUnicodeString FString;
14 CommandPair::List FCommands;
15 VWChar FParameterChar;
16 VWChar FValueChar;
17 VBool FParsed;
18 public :
19 VL_WinParameters(VUnicodeString Command);
20 ~ VL_WinParameters();
21
22 VUnicodeString GetCommandLineString();
23 VInt GetCount();
24 VUnicodeString GetParameter(VInt Index);
25 VUnicodeString GetValue(VInt Index);
26 VBool IsParsed();
27 void Parse(VWChar ParameterChar , VWChar ValueChar);
28 };
2 {
3 protected :
4 class CommandPair
5 {
6 public :
7 typedef VL_List < CommandPair , false > List;
8
9 VUnicodeString Parameter;
10 VUnicodeString Value;
11 };
12
13 VUnicodeString FString;
14 CommandPair::List FCommands;
15 VWChar FParameterChar;
16 VWChar FValueChar;
17 VBool FParsed;
18 public :
19 VL_WinParameters(VUnicodeString Command);
20 ~ VL_WinParameters();
21
22 VUnicodeString GetCommandLineString();
23 VInt GetCount();
24 VUnicodeString GetParameter(VInt Index);
25 VUnicodeString GetValue(VInt Index);
26 VBool IsParsed();
27 void Parse(VWChar ParameterChar , VWChar ValueChar);
28 };
实现文件:
1
VL_WinParameters::VL_WinParameters(VUnicodeString Command)
2 {
3 FString = Command;
4 FParsed = false ;
5 FParameterChar = L ' \0 ' ;
6 FValueChar = L ' \0 ' ;
7 }
8
9 VL_WinParameters:: ~ VL_WinParameters()
10 {
11 }
12
13 VUnicodeString VL_WinParameters::GetCommandLineString()
14 {
15 return FString;
16 }
17
18 VInt VL_WinParameters::GetCount()
19 {
20 return FCommands.GetCount();
21 }
22
23 VUnicodeString VL_WinParameters::GetParameter(VInt Index)
24 {
25 return FCommands[Index].Parameter;
26 }
27
28 VUnicodeString VL_WinParameters::GetValue(VInt Index)
29 {
30 return FCommands[Index].Value;
31 }
32
33 VBool VL_WinParameters::IsParsed()
34 {
35 return FParsed;
36 }
37
38 void VL_WinParameters::Parse(VWChar ParameterChar , VWChar ValueChar)
39 {
40 if ( ! ParameterChar || ! ValueChar) return ;
41 if (FParameterChar != ParameterChar || FValueChar != ValueChar)
42 {
43 FParameterChar = ParameterChar;
44 FValueChar = ValueChar;
45
46 FCommands.Clear();
47 VL_List < VUnicodeString , false > CommandStrings;
48 {
49 PCWChar Buffer = FString.Buffer();
50 VUnicodeString CurrentCommand;
51 VBool InString = false ;
52
53 while ( true )
54 {
55 if (InString)
56 {
57 switch ( * Buffer)
58 {
59 case L ' \0 ' :
60 InString = false ;
61 if (CurrentCommand != L "" )
62 {
63 CommandStrings.Add(CurrentCommand);
64 CurrentCommand = L "" ;
65 }
66 break ;
67 case L ' \" ' :
68 InString = false ;
69 default :
70 CurrentCommand +=* Buffer;
71 }
72 }
73 else
74 {
75 switch ( * Buffer)
76 {
77 case L ' ' : case L ' \0 ' :
78 if (CurrentCommand != L "" )
79 {
80 CommandStrings.Add(CurrentCommand);
81 CurrentCommand = L "" ;
82 }
83 break ;
84 case L ' \" ' :
85 InString = true ;
86 default :
87 CurrentCommand +=* Buffer;
88 }
89 }
90 if ( * Buffer)
91 {
92 Buffer ++ ;
93 }
94 else
95 {
96 break ;
97 }
98 }
99 }
100 for (VInt i = 0 ;i < CommandStrings.GetCount();i ++ )
101 {
102 CommandPair Pair;
103 PCWChar Buffer = CommandStrings[i].Buffer();
104 if ( * Buffer == FParameterChar)
105 {
106 Buffer ++ ;
107 while ( true )
108 {
109 if ( * Buffer)
110 {
111 if ( * Buffer == FValueChar)
112 {
113 Buffer ++ ;
114 break ;
115 }
116 else
117 {
118 Pair.Parameter +=* Buffer;
119 Buffer ++ ;
120 }
121 }
122 else
123 {
124 break ;
125 }
126 }
127 }
128 if ( * Buffer)
129 {
130 Pair.Value = Buffer;
131 if (Pair.Value.Length() >= 2 && Pair.Value.GetChar( 0 ) == L ' \" ' && Pair.Value.GetChar(Pair.Value.Length() - 1 ) == L ' \" ' )
132 {
133 Pair.Value = Pair.Value.SubString( 1 ,Pair.Value.Length() - 2 );
134 }
135 }
136 FCommands.Add(Pair);
137 }
138 FParsed = true ;
139 }
140 }
2 {
3 FString = Command;
4 FParsed = false ;
5 FParameterChar = L ' \0 ' ;
6 FValueChar = L ' \0 ' ;
7 }
8
9 VL_WinParameters:: ~ VL_WinParameters()
10 {
11 }
12
13 VUnicodeString VL_WinParameters::GetCommandLineString()
14 {
15 return FString;
16 }
17
18 VInt VL_WinParameters::GetCount()
19 {
20 return FCommands.GetCount();
21 }
22
23 VUnicodeString VL_WinParameters::GetParameter(VInt Index)
24 {
25 return FCommands[Index].Parameter;
26 }
27
28 VUnicodeString VL_WinParameters::GetValue(VInt Index)
29 {
30 return FCommands[Index].Value;
31 }
32
33 VBool VL_WinParameters::IsParsed()
34 {
35 return FParsed;
36 }
37
38 void VL_WinParameters::Parse(VWChar ParameterChar , VWChar ValueChar)
39 {
40 if ( ! ParameterChar || ! ValueChar) return ;
41 if (FParameterChar != ParameterChar || FValueChar != ValueChar)
42 {
43 FParameterChar = ParameterChar;
44 FValueChar = ValueChar;
45
46 FCommands.Clear();
47 VL_List < VUnicodeString , false > CommandStrings;
48 {
49 PCWChar Buffer = FString.Buffer();
50 VUnicodeString CurrentCommand;
51 VBool InString = false ;
52
53 while ( true )
54 {
55 if (InString)
56 {
57 switch ( * Buffer)
58 {
59 case L ' \0 ' :
60 InString = false ;
61 if (CurrentCommand != L "" )
62 {
63 CommandStrings.Add(CurrentCommand);
64 CurrentCommand = L "" ;
65 }
66 break ;
67 case L ' \" ' :
68 InString = false ;
69 default :
70 CurrentCommand +=* Buffer;
71 }
72 }
73 else
74 {
75 switch ( * Buffer)
76 {
77 case L ' ' : case L ' \0 ' :
78 if (CurrentCommand != L "" )
79 {
80 CommandStrings.Add(CurrentCommand);
81 CurrentCommand = L "" ;
82 }
83 break ;
84 case L ' \" ' :
85 InString = true ;
86 default :
87 CurrentCommand +=* Buffer;
88 }
89 }
90 if ( * Buffer)
91 {
92 Buffer ++ ;
93 }
94 else
95 {
96 break ;
97 }
98 }
99 }
100 for (VInt i = 0 ;i < CommandStrings.GetCount();i ++ )
101 {
102 CommandPair Pair;
103 PCWChar Buffer = CommandStrings[i].Buffer();
104 if ( * Buffer == FParameterChar)
105 {
106 Buffer ++ ;
107 while ( true )
108 {
109 if ( * Buffer)
110 {
111 if ( * Buffer == FValueChar)
112 {
113 Buffer ++ ;
114 break ;
115 }
116 else
117 {
118 Pair.Parameter +=* Buffer;
119 Buffer ++ ;
120 }
121 }
122 else
123 {
124 break ;
125 }
126 }
127 }
128 if ( * Buffer)
129 {
130 Pair.Value = Buffer;
131 if (Pair.Value.Length() >= 2 && Pair.Value.GetChar( 0 ) == L ' \" ' && Pair.Value.GetChar(Pair.Value.Length() - 1 ) == L ' \" ' )
132 {
133 Pair.Value = Pair.Value.SubString( 1 ,Pair.Value.Length() - 2 );
134 }
135 }
136 FCommands.Add(Pair);
137 }
138 FParsed = true ;
139 }
140 }