mirror of
https://github.com/rizonesoft/Notepad3.git
synced 2026-06-14 21:09:05 +08:00
252 lines
6.9 KiB
C++
252 lines
6.9 KiB
C++
// sktoolslib - common files for SK tools
|
|
|
|
// Copyright (C) 2012, 2017 - Stefan Kueng
|
|
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU General Public License
|
|
// as published by the Free Software Foundation; either version 2
|
|
// of the License, or (at your option) any later version.
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software Foundation,
|
|
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#include "CmdLineParser.h"
|
|
#include <locale>
|
|
#include <algorithm>
|
|
|
|
const TCHAR CCmdLineParser::m_sDelims[] = _T("-/");
|
|
const TCHAR CCmdLineParser::m_sQuotes[] = _T("\"");
|
|
const TCHAR CCmdLineParser::m_sValueSep[] = _T(" :"); // don't forget space!!
|
|
|
|
|
|
static void SearchReplace(stdstring& str, const stdstring& toreplace, const stdstring& replacewith)
|
|
{
|
|
stdstring result;
|
|
stdstring::size_type pos = 0;
|
|
for (;;)
|
|
{
|
|
stdstring::size_type next = str.find(toreplace, pos);
|
|
result.append(str, pos, next - pos);
|
|
if (next != stdstring::npos)
|
|
{
|
|
result.append(replacewith);
|
|
pos = next + toreplace.size();
|
|
}
|
|
else
|
|
{
|
|
break; // exit loop
|
|
}
|
|
}
|
|
str = std::move(result);
|
|
}
|
|
|
|
|
|
CCmdLineParser::CCmdLineParser(LPCTSTR sCmdLine)
|
|
{
|
|
if (sCmdLine)
|
|
{
|
|
Parse(sCmdLine);
|
|
}
|
|
}
|
|
|
|
CCmdLineParser::~CCmdLineParser()
|
|
{
|
|
m_valueMap.clear();
|
|
}
|
|
|
|
BOOL CCmdLineParser::Parse(LPCTSTR sCmdLine)
|
|
{
|
|
const stdstring sEmpty = _T(""); // use this as a value if no actual value is given in commandline
|
|
|
|
if (!sCmdLine)
|
|
return false;
|
|
|
|
m_valueMap.clear();
|
|
m_sCmdLine = sCmdLine;
|
|
|
|
LPCTSTR sCurrent = sCmdLine;
|
|
|
|
for (;;)
|
|
{
|
|
//format is -Key:"arg"
|
|
|
|
if (sCurrent[0] == '\0')
|
|
break; // no more data, leave loop
|
|
|
|
LPCTSTR sArg = _tcspbrk(sCurrent, m_sDelims);
|
|
if (!sArg)
|
|
break; // no (more) delimiters found
|
|
sArg = _tcsinc(sArg);
|
|
|
|
if (sArg[0] == '\0')
|
|
break; // ends with delim
|
|
|
|
LPCTSTR sVal = _tcspbrk(sArg, m_sValueSep);
|
|
if (sVal == nullptr)
|
|
{
|
|
stdstring Key(sArg);
|
|
std::transform(Key.begin(), Key.end(), Key.begin(), ::towlower);
|
|
m_valueMap.insert(CValsMap::value_type(Key, sEmpty));
|
|
break;
|
|
}
|
|
else if (sVal[0] == _T(' ') || _tcslen(sVal) == 1)
|
|
{
|
|
// cmdline ends with /Key: or a key with no value
|
|
stdstring Key(sArg, (int)(sVal - sArg));
|
|
if (!Key.empty())
|
|
{
|
|
std::transform(Key.begin(), Key.end(), Key.begin(), ::towlower);
|
|
m_valueMap.insert(CValsMap::value_type(Key, sEmpty));
|
|
}
|
|
sCurrent = _tcsinc(sVal);
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
// key has value
|
|
stdstring Key(sArg, (int)(sVal - sArg));
|
|
std::transform(Key.begin(), Key.end(), Key.begin(), ::towlower);
|
|
|
|
sVal = _tcsinc(sVal);
|
|
|
|
LPCTSTR sQuote = _tcspbrk(sVal, m_sQuotes), sEndQuote(nullptr);
|
|
bool hasEscapedQuotes = false;
|
|
if (sQuote == sVal)
|
|
{
|
|
// string with quotes (defined in m_sQuotes, e.g. '")
|
|
sQuote = _tcsinc(sVal);
|
|
sEndQuote = _tcspbrk(sQuote, m_sQuotes);
|
|
while (sEndQuote && sEndQuote[-1] == '\\')
|
|
{
|
|
hasEscapedQuotes = true;
|
|
sEndQuote = _tcsinc(sEndQuote);
|
|
sEndQuote = _tcspbrk(sEndQuote, m_sQuotes);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sQuote = sVal;
|
|
sEndQuote = _tcschr(sQuote, _T(' '));
|
|
while (sEndQuote && sEndQuote[-1] == '\\')
|
|
{
|
|
hasEscapedQuotes = true;
|
|
sEndQuote = _tcsinc(sEndQuote);
|
|
sEndQuote = _tcspbrk(sEndQuote, m_sQuotes);
|
|
}
|
|
}
|
|
|
|
if (sEndQuote == nullptr)
|
|
{
|
|
// no end quotes or terminating space, take the rest of the string to its end
|
|
stdstring csVal(sQuote);
|
|
if (hasEscapedQuotes)
|
|
SearchReplace(csVal, _T("\\\""), _T("\""));
|
|
if (!Key.empty())
|
|
{
|
|
m_valueMap.insert(CValsMap::value_type(Key, csVal));
|
|
}
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// end quote
|
|
if (!Key.empty())
|
|
{
|
|
stdstring csVal(sQuote, (int)(sEndQuote - sQuote));
|
|
if (hasEscapedQuotes)
|
|
SearchReplace(csVal, _T("\\\""), _T("\""));
|
|
m_valueMap.insert(CValsMap::value_type(Key, csVal));
|
|
}
|
|
sCurrent = _tcsinc(sEndQuote);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
CCmdLineParser::CValsMap::const_iterator CCmdLineParser::findKey(LPCTSTR sKey) const
|
|
{
|
|
stdstring s(sKey);
|
|
std::transform(s.begin(), s.end(), s.begin(), ::towlower);
|
|
return m_valueMap.find(s);
|
|
}
|
|
|
|
BOOL CCmdLineParser::HasKey(LPCTSTR sKey) const
|
|
{
|
|
CValsMap::const_iterator it = findKey(sKey);
|
|
if (it == m_valueMap.end())
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
|
|
BOOL CCmdLineParser::HasVal(LPCTSTR sKey) const
|
|
{
|
|
CValsMap::const_iterator it = findKey(sKey);
|
|
if (it == m_valueMap.end())
|
|
return false;
|
|
if (it->second.empty())
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
LPCTSTR CCmdLineParser::GetVal(LPCTSTR sKey) const
|
|
{
|
|
CValsMap::const_iterator it = findKey(sKey);
|
|
if (it == m_valueMap.end())
|
|
return 0;
|
|
return it->second.c_str();
|
|
}
|
|
|
|
LONG CCmdLineParser::GetLongVal(LPCTSTR sKey) const
|
|
{
|
|
CValsMap::const_iterator it = findKey(sKey);
|
|
if (it == m_valueMap.end())
|
|
return 0;
|
|
return _tstol(it->second.c_str());
|
|
}
|
|
|
|
__int64 CCmdLineParser::GetLongLongVal(LPCTSTR sKey) const
|
|
{
|
|
CValsMap::const_iterator it = findKey(sKey);
|
|
if (it == m_valueMap.end())
|
|
return 0;
|
|
return _ttoi64(it->second.c_str());
|
|
}
|
|
|
|
CCmdLineParser::ITERPOS CCmdLineParser::begin() const
|
|
{
|
|
return m_valueMap.begin();
|
|
}
|
|
|
|
CCmdLineParser::ITERPOS CCmdLineParser::getNext(ITERPOS& pos, stdstring& sKey, stdstring& sValue) const
|
|
{
|
|
if (m_valueMap.end() == pos)
|
|
{
|
|
sKey.clear();
|
|
return pos;
|
|
}
|
|
else
|
|
{
|
|
sKey = pos->first;
|
|
sValue = pos->second;
|
|
++pos;
|
|
return pos;
|
|
}
|
|
}
|
|
|
|
BOOL CCmdLineParser::isLast(const ITERPOS& pos) const
|
|
{
|
|
return (pos == m_valueMap.end());
|
|
}
|