Phinecos(洞庭散人)
光荣在于平淡,艰巨因为漫长
一个面向对象的命令行解析器
这个类能解析如下格式的参数:
-b
-h www.codeproject.com
stdafx.cpp
-temp:-7
除此以外,还可以解析以“
—
”或“
/
”打头的参数。
一般有三类参数需要解析:
作为标识的参数(例如“
ls –l
”),这叫空参数
有其值的参数(例如“
netstat –p tcp
”),这叫值参数
不带任何“
-
”的(例如“
copy a.cpp b.cpp
”),这叫默认参数。
#include
<
map
>
#include
<
string
>
#define
UNKNOWN_PARAM "UNKNOWN_PARAM"
#define
NO_VALUE_PARAM "PARAM_NO_VALUE"
#define
GENERIC_ERROR "GENERIC_ERROR"
/**/
/*
*
Interface that must be implemented by the objects that requires access to the
command line arguments.
@see CCommandLineParser
*/
class
ICmdLineParam
{
public
:
/**/
/*
*
Method called by the CCommandLineParser to pass the arguments and the values.
The parser calls this method to indicate the name of the arguments and/or
the values only when applicable. The '-' or '/' of the arguments are eliminated
before reach this method.
@return false only if the parser must stop, on a serious error.
true when the argument is OK or is malformed, in this second case
the function GetError must return a description, see below.
*/
virtual
bool
Parse(std::
string
argument,std::
string
value)
=
0
;
/**/
/*
* Method called by the CCommandLineParser to retrieve the error description.
// if an fail in command line occurs, this method must return a description of the error.
// Ex: "Inaccesible input file", "invalid type of algorithm",..,etc.
@retrun "" to indicate that no error was produced.
*/
virtual
std::
string
GetError()
=
0
;
}
;
class
CCommandLineParser
{
public
:
CCommandLineParser()
{m_defaultCommand
=
NULL;}
/**/
/*
*
Object that handle the default arguments. Only one can be specified.
*/
void
SetDefaultCommand(ICmdLineParam
*
e);
/**/
/*
*
Objects that handle the empty arguments. Can be called how many times as necesary.
@param para name of the argument that this ICmdLineParam expect.
@e ICmdLineParam
*/
void
PutEmptyCommand(std::
string
argument,ICmdLineParam
*
e);
/**/
/*
*
Entry that handle the values arguments. Can be called how many times as necesary.
@param para name of the argument that this ICmdLineParam expect.
@e ICmdLineParam
*/
void
PutValueCommand(std::
string
argument,ICmdLineParam
*
e);
/**/
/*
*
Entry that handle the errors of the CCommandLineParser. Only one can be specified.
*/
void
SetErrorCommand(ICmdLineParam
*
e);
/**/
/*
*
Inits the parse process.
@param argn number of arguments passed to the application.
@param argv array of string with the arguments passed to the application.
*/
bool
ParseArguments(
int
argn,
char
*
argv[]);
private
:
ICmdLineParam
*
m_defaultCommand;
ICmdLineParam
*
m_errorCommand;
std::map
<
std::
string
,ICmdLineParam
*>
m_mapValueCommand;
//
值参数映射表
std::map
<
std::
string
,ICmdLineParam
*>
m_mapEmptyCommand;
//
空参数映射表
/**/
/*
*
Deletes the '-', '--', '/' of the argument.
@return <b>true</b> if the argument is not a value.
*/
bool
DeleteMinus(std::
string
&
param);
}
;
void
CCommandLineParser::SetDefaultCommand(ICmdLineParam
*
obj)
{
m_defaultCommand
=
obj;
}
void
CCommandLineParser::PutEmptyCommand(std::
string
argument,ICmdLineParam
*
obj)
{
m_mapEmptyCommand[argument]
=
obj;
}
void
CCommandLineParser::PutValueCommand(std::
string
argument,ICmdLineParam
*
obj)
{
m_mapValueCommand[argument]
=
obj;
}
void
CCommandLineParser::SetErrorCommand(ICmdLineParam
*
obj)
{
m_errorCommand
=
obj;
}
bool
CCommandLineParser::ParseArguments(
int
argn,
char
*
argv[])
{
bool
bAllOK
=
true
;
int
i
=
1
;
//
First paramter is discarded becouse it's the execution program path.
while
(i
<
argn )
{
std::
string
argument
=
argv[i];
//
当前待处理的参数
if
(DeleteMinus(argument))
{
//
到值参数映射表中寻找待设置的值参数
//
Check if this argument requires a value.
std::map
<
std::
string
,ICmdLineParam
*>
::iterator it
=
m_mapValueCommand.find(argument);
if
(it
!=
m_mapValueCommand.end())
{
//
值参数表中存在
if
(argv[i
+
1
]
==
NULL)
{
//
没有提供值
bAllOK
&=
m_errorCommand
->
Parse(NO_VALUE_PARAM,argument);
return
false
;
}
std::
string
paso
=
argv[i
+
1
];
if
(DeleteMinus(paso))
{
//
没有提供值
bAllOK
&=
m_errorCommand
->
Parse(NO_VALUE_PARAM,argument);
return
false
;
}
else
{
bAllOK
&=
it
->
second
->
Parse(argument,paso);
//
解析出值
i
++
;
}
}
else
{
//
值参数表中不存在
it
=
m_mapEmptyCommand.find(argument);
//
到空参数表中寻找
if
(it
!=
m_mapEmptyCommand.end())
{
//
找到了
bAllOK
&=
it
->
second
->
Parse(argument,
""
);
}
else
{
//
用户设置的格式是”参数:值“,对这种情况进行解析
//
Try to split a ":"
std::
string
::size_type position
=
argument.find_first_of(
"
:
"
);
if
(position
!=
std::
string
::npos)
{
std::
string
command
=
argument.substr(
0
,position);
std::
string
value
=
argument.substr(position
+
1
);
//
到值参数映射表中寻址
std::map
<
std::
string
,ICmdLineParam
*>
::iterator it
=
m_mapValueCommand.find(command);
if
(it
!=
m_mapValueCommand.end())
{
//
找到
bAllOK
&=
it
->
second
->
Parse(command,value);
}
else
{
//
不存在
bAllOK
&=
m_errorCommand
->
Parse(UNKNOWN_PARAM,command);
return
false
;
}
}
else
{
//
未知参数
bAllOK
&=
m_errorCommand
->
Parse(UNKNOWN_PARAM,argument);
return
false
;
}
}
}
}
else
{
//
不是附加参数,而是默认参数
if
(m_defaultCommand
!=
NULL)
{
bAllOK
&=
m_defaultCommand
->
Parse(
""
,argument);
}
else
{
return
false
;
}
}
i
++
;
}
//
错误处理
std::
string
error
=
m_defaultCommand
->
GetError();
if
(error
!=
""
)
{
m_errorCommand
->
Parse(GENERIC_ERROR,error);
return
false
;
}
std::map
<
std::
string
,ICmdLineParam
*>
::iterator it
=
m_mapValueCommand.begin();
while
(it
!=
m_mapValueCommand.end())
{
error
=
it
->
second
->
GetError();
if
(error
!=
""
)
{
m_errorCommand
->
Parse(GENERIC_ERROR,error);
return
false
;
}
it
++
;
}
std::map
<
std::
string
,ICmdLineParam
*>
::iterator it2
=
m_mapEmptyCommand.begin();
while
(it2
!=
m_mapEmptyCommand.end())
{
error
=
it2
->
second
->
GetError();
if
(error
!=
""
)
{
m_errorCommand
->
Parse(GENERIC_ERROR,error);
return
false
;
}
it2
++
;
}
return
bAllOK;
//
Devuelve false si ha habido error.
}
bool
CCommandLineParser::DeleteMinus(std::
string
&
argument)
{
//
去掉参数前的分隔符
switch
(argument[
0
])
{
case
'
/
'
:
argument
=
&
(argument.c_str()[
1
]);
return
true
;
case
'
-
'
:
if
(argument[
1
]
==
'
-
'
)
{
argument
=
&
(argument.c_str()[
2
]);
}
else
{
argument
=
&
(argument.c_str()[
1
]);
}
return
true
;
}
return
false
;
}
测试程序
#define
APP_USAGE "Usage: hashfile [-alg md5|sha1] [-out hex] file\nDefault: -alg md5 -out hex\n"
class
CHashType :
public
ICmdLineParam
{
enum
types
{MD5,SHA1}
;
//
hash类型
types m_type;
string
m_strError;
//
上次错误字段
public
:
CHashType()
{
m_strError
=
""
;