Files
App-Installer-For-Windows-8…/appinstaller/cmdargs.h
2025-11-20 09:17:32 +08:00

161 lines
5.5 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#pragma once
#include <vector>
#include <string>
#include <map>
#include <set>
#include "nstring.h"
#include "rctools.h"
#include "filepath.h"
#include "raii.h"
// 允许忽视命令行前缀。如当命令行前缀为“-”"/"时,且开启此项,则输入“-args”与"/args"和"args" 是等效的
#define CMDARG_IGNOREPREFIXS 0b001
// 允许参数后跟着值,如“/args=file”但要求必须配置后缀且是有效的字符
#define CMDARG_ENABLEPARAMS 0b010
// 当 CMDARG_ENABLEPARAMS 开启时允许参数为空。如 “/args=file”和"/args"都是允许的
#define CMDARG_IGNOREPARAMS 0b100
// 命令行参数
struct cmdarg
{
std::vector <std::wstring> prefixs; // 允许无前缀(长度为 0
std::vector <std::wstring> commands; // 参数(长度不能为 0不能为空
std::vector <std::wstring> postfixs; // 允许无后缀(长度为 0
std::wstring uniquelabel; // 唯一标识,参数名
std::wstring description; // 描述,用于生成帮助文本
DWORD flags; // 标志
};
#define CMDARG_PREFIXS_DEFAULT {L"-", L"/"}
#define CMDARG_POSTFIXS_DEFAULT {}
std::vector <cmdarg> g_argslist = {
{CMDARG_PREFIXS_DEFAULT, {L"silent", L"quiet", L"passive"}, CMDARG_POSTFIXS_DEFAULT, L"silent", GetRCStringSW (0), CMDARG_IGNOREPREFIXS},
{CMDARG_PREFIXS_DEFAULT, {L"verysilent", L"veryquiet"}, CMDARG_POSTFIXS_DEFAULT, L"verysilent", GetRCStringSW (0), CMDARG_IGNOREPREFIXS},
{CMDARG_PREFIXS_DEFAULT, {L"multiple", L"filelist"}, {L"="}, L"multiple", GetRCStringSW (0), CMDARG_IGNOREPREFIXS | CMDARG_ENABLEPARAMS}
};
bool IsFile (const std::wstring &path)
{
return IsPathExists (path);
}
bool IsURI (const std::wstring &str)
{
try
{
auto uristr = gcnew System::String (str.c_str ());
auto uri = gcnew System::Uri (uristr);
return uri != nullptr;
}
catch (...) { return false; }
}
enum class paramtype
{
string,
file,
uri
};
struct cmdkey
{
std::wnstring key; // 键
paramtype type; // 键类型当传入的参数是存在的文件路径时如“C:\1.txt”则键的类型为文件。同理也可设置为 uri
operator std::wnstring () { return key; }
operator LPCWSTR () { return key.c_str (); }
cmdkey (const std::wstring &k): key (k)
{
if (IsFile (k)) type = paramtype::file;
else if (IsURI (k)) type = paramtype::uri;
else type = paramtype::string;
}
cmdkey (const std::wstring &k, paramtype pt): key (k), type (pt) {}
bool operator == (const cmdkey &r) const { return key == r.key; }
bool operator > (const cmdkey &r) const { return key > r.key; }
bool operator < (const cmdkey &r) const { return key < r.key; }
};
struct cmdvalue
{
std::wstring value; // 值
paramtype type;
bool isnull; // 当参数不支持跟着值时,或允许时值为空时设置为真。
};
// 对于从命令行获取到的 argv 和 argcargc 最小为 1argv 的第一个元素指向程序。所以 startpos 为 1。
void ParseCmdArgs (LPWSTR *argv, DWORD argc, std::map <cmdkey, cmdvalue> &parseresult, DWORD startpos = 1)
{
for (size_t i = startpos; i < argc; i ++)
{
std::wnstring arg = argv [i];
arg = arg.trim ();
if (IsFile (arg)) parseresult [cmdkey (arg, paramtype::file)] = cmdvalue {L"", paramtype::file, true};
else if (IsURI (arg)) parseresult [cmdkey (arg, paramtype::uri)] = cmdvalue {L"", paramtype::uri, true};
else
{
for (auto &it : g_argslist)
{
std::set <std::wnstring> prefixs;
for (auto &it_s : it.prefixs) prefixs.insert (it_s);
int cmdhead = -1;
for (auto &it_s : prefixs)
{
auto plen = GetNormalizeStringLength (it_s);
auto parg = GetStringLeft (arg, plen);
if (it_s == parg) { cmdhead = plen; break; }
}
if (((it.flags & CMDARG_IGNOREPREFIXS) || !it.prefixs.size () || !prefixs.size ()) && cmdhead < 0)
{
if (!arg.length ()) continue;
cmdhead = 0;
}
if (cmdhead < 0) continue;
int postfixhead = -1;
std::set <std::wnstring> commands;
for (auto &it_s : it.commands) if (GetNormalizeStringLength (it_s)) commands.insert (it_s);
if (commands.empty ()) continue;
for (auto &it_s : commands)
{
auto clen = it_s.length ();
auto carg = GetStringLeft (arg.substr (cmdhead), clen);
if (it_s == carg) { postfixhead = cmdhead + clen; }
}
if (postfixhead < 0) continue;
std::set <std::wnstring> postfixs;
for (auto &it_s : it.postfixs) if (GetNormalizeStringLength (it_s)) postfixs.insert (it_s);
if (!(it.flags & CMDARG_ENABLEPARAMS)) it.postfixs.clear ();
if ((it.flags & CMDARG_ENABLEPARAMS) && postfixs.size ())
{
int valuehead = -1;
auto rightpart = StringTrim (GetStringRight (arg, lstrlenW (arg.c_str ()) - postfixhead));
if (it.flags & CMDARG_IGNOREPARAMS)
{
if (!rightpart.length ()) { parseresult [cmdkey (it.uniquelabel, paramtype::string)] = cmdvalue {L"", paramtype::string, true}; break; }
}
for (auto &it_s : postfixs)
{
auto plen = it_s.length ();
auto parg = GetStringLeft (rightpart, plen);
if (it_s == parg) { valuehead = plen; break; }
}
if (valuehead < 0) continue;
else
{
auto value = rightpart.substr (valuehead);
paramtype ptype = paramtype::string;
if (IsFile (value)) ptype = paramtype::file;
else if (IsURI (StringTrim (value))) ptype = paramtype::uri;
parseresult [cmdkey (it.uniquelabel, paramtype::string)] = cmdvalue {value, ptype, false};
}
break;
}
else
{
parseresult [cmdkey (it.uniquelabel, paramtype::string)] = cmdvalue {L"", paramtype::string, true};
break;
}
}
}
}
}
void ParseCmdLine (LPCWSTR lpCommandLine, std::map <cmdkey, cmdvalue> &parseresult)
{
int argc = 0;
LPWSTR *alpstr = CommandLineToArgvW (lpCommandLine, &argc);
destruct relt ([&alpstr] () {
if (alpstr) LocalFree (alpstr);
});
ParseCmdArgs (alpstr, argc, parseresult, 0);
}