这个类能解析如下格式的参数:
-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 = "" ; m_type = MD5; // 默认hash类型 } bool Parse( string argument, string value) { // alg是参数名称,value是参数值 if (argument == " alg " ) { if (value == " md5 " ) { m_type = MD5; } else if (value == " sha1 " ) { m_type = SHA1; } else { m_strError = " Incorrect hash algorithm. Correct values(case sensitive): md5, sha1. Default md5. " ; return false ; } } return true ; } string GetError() { return m_strError; } void CalcHash( string strFileName, unsigned char *& outbuffer,DWORD & rdwDataLen) { // 用指定算法进行Hash加密计算 unsigned int dLenBuffer = 1024 ; unsigned int dDataLen = 0 ; FILE * hFile = fopen(strFileName.c_str(), " rb " ); outbuffer = new unsigned char [dLenBuffer]; GUID g; CoCreateGuid( & g); char szContName[ 100 ]; _snprintf(szContName, 100 , " %u-%u-%u-%u " ,g.Data1,g.Data2,g.Data3,g.Data4); HCRYPTPROV hProv; if (CryptAcquireContext( & hProv,szContName,MS_DEF_PROV,PROV_RSA_FULL,CRYPT_NEWKEYSET)) { } else { HandleError( " CryptAcquireContext1 fail " ); } ALG_ID alg_id = CALG_MD5; switch (m_type) { case SHA1: alg_id = CALG_SHA1; break ; case MD5: alg_id = CALG_MD5; break ; } ; HCRYPTHASH hHash; if (CryptCreateHash(hProv,alg_id, 0 , 0 , & hHash)) { } else { HandleError( " CryptCreateHash fail " ); } while ( ! feof(hFile)) { dDataLen = fread(outbuffer, 1 ,dLenBuffer,hFile); if (CryptHashData(hHash,outbuffer,dDataLen, 0 )) { } else { HandleError( " CryptHashData fail " ); } } rdwDataLen = 1024 ; if (CryptGetHashParam(hHash,HP_HASHVAL,outbuffer, & rdwDataLen, 0 )) { } else { HandleError( " CryptHashData fail " ); } fclose(hFile); CryptReleaseContext(hProv,0 ); CryptAcquireContext( & hProv,szContName,MS_DEF_PROV,PROV_RSA_FULL,CRYPT_DELETEKEYSET); } }; class COutputType : public ICmdLineParam { enum types {HEX} ; // 输出进制 types m_type; string m_strError; public : COutputType() { m_type = HEX; // 默认是十六进制 } bool Parse( string argument, string value) { if (argument == " out " ) { if (value == " hex " ) { m_type = HEX; } else { m_strError = " Incorrect output type codification. Correct values(case sensitive): hex. Default hex. " ; return false ; } } return true ; } string GetError() { return m_strError; } void OutputHash(unsigned char * inbuffer,DWORD dwDataLen) { char cad[ 3 ]; switch (m_type) { case HEX: for ( int i = 0 ; i < dwDataLen ; i ++ ) { sprintf(cad, " %02x " ,inbuffer[i]); cout << cad; } break ; } } }; class CFileHash : public ICmdLineParam { string m_filename; string m_strError; public : CFileHash() { m_filename = "" ; m_strError = "" ; } string GetFileName() { return m_filename; } bool Parse( string argument, string value) { if (argument == "" ) { m_filename = value; if (access(m_filename.c_str(), 04 ) != 0 ) { m_strError = " Inaccesible input file: " + value; return false ; } } return true ; } string GetError() { if (m_filename == "" ) { return " Must specify a file name. " ; } return m_strError; } }; class CError : public ICmdLineParam { public : bool m_displayHelp; CError() { m_displayHelp = false ; } bool Parse( string argument, string value) { // 对错误类型进行处理 if (argument == " h " ) { m_displayHelp = true ; return false ; } if (argument == GENERIC_ERROR) { cout << value << endl << endl; cout << APP_USAGE; return false ; } if (argument == UNKNOWN_PARAM) { cout << " Invalid argument ' " << value << " '. " << endl << endl; cout << APP_USAGE; return false ; } if (argument == NO_VALUE_PARAM) { cout << " Empty argument ' " << value << " ' must specify one value. " << endl << endl; cout << APP_USAGE; return false ; } return true ; } string GetError() { if (m_displayHelp) { return APP_USAGE; } else { return "" ; } } }; int main( int argc, char * argv[]) { CCommandLineParser parser; COutputType output; CHashType hash; CError err; CFileHash file; parser.PutValueCommand( " out " , & output); // 第一个值参数 parser.PutValueCommand( " alg " , & hash); // 第二个值参数 parser.SetDefaultCommand( & file); parser.PutEmptyCommand( " h " , & err); // 第一个空参数 parser.PutEmptyCommand( " help " , & err); // 第二个空参数 parser.SetErrorCommand( & err); if (parser.ParseArguments(argc,argv)) { unsigned char * inbuffer = NULL; DWORD dwDataLen = 1024 ; // 数据进行hash计算 hash.CalcHash(file.GetFileName().c_str(),inbuffer,dwDataLen); output.OutputHash(inbuffer,dwDataLen); // 输出 delete[] inbuffer; } system(" pause " ); return 0 ; } void HandleError( char * s) { char message[ 1000 ]; int length = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0 ,GetLastError(), 0 ,message, 1000 ,NULL); fprintf(stderr, " An error occurred in running the program. /n " ); fprintf(stderr, " %s/n " ,s); fprintf(stderr, " Error number %x: %s./n " , GetLastError(),message); fprintf(stderr, " Program terminating. /n " ); exit( 1 ); } // End of HandleError