CPatch: New memory management
[TortoiseGit.git] / src / Utils / CmdLineParser.cpp
blobd5884e598dc6f96e5c378a2455b37872a4061ddc
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2013, 2016-2017 - TortoiseGit
4 // Copyright (C) 2003-2006,2012 - Stefan Kueng
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "stdafx.h"
21 #include "CmdLineParser.h"
22 #include <locale>
23 #include <algorithm>
25 const TCHAR CCmdLineParser::m_sDelims[] = L"-/";
26 const TCHAR CCmdLineParser::m_sQuotes[] = L"\"";
27 const TCHAR CCmdLineParser::m_sValueSep[] = L" :"; // don't forget space!!
30 CCmdLineParser::CCmdLineParser(LPCTSTR sCmdLine)
32 if(sCmdLine)
33 Parse(sCmdLine);
36 CCmdLineParser& CCmdLineParser::operator=(CCmdLineParser&& other)
38 m_sCmdLine = std::move(other.m_sCmdLine);
39 m_valueMap = std::move(other.m_valueMap);
40 return *this;
43 BOOL CCmdLineParser::Parse(LPCTSTR sCmdLine)
45 const std::wstring sEmpty; //use this as a value if no actual value is given in commandline
47 if(!sCmdLine)
48 return false;
50 m_valueMap.clear();
51 m_sCmdLine = sCmdLine;
53 tstring working = sCmdLine;
54 auto sCurrent = working.data();
56 for(;;)
58 //format is -Key:"arg"
60 if (!sCurrent[0])
61 break; // no more data, leave loop
63 LPCTSTR sArg = wcspbrk(sCurrent, m_sDelims);
64 if(!sArg)
65 break; // no (more) delimiters found
66 sArg = _wcsinc(sArg);
68 if (!sArg[0])
69 break; // ends with delim
71 LPCTSTR sVal = wcspbrk(sArg, m_sValueSep);
72 if (!sVal)
74 std::wstring Key(sArg);
75 std::transform(Key.begin(), Key.end(), Key.begin(), ::towlower);
76 m_valueMap.insert(CValsMap::value_type(Key, sEmpty));
77 break;
79 else
81 std::wstring Key(sArg, (int)(sVal - sArg));
82 std::transform(Key.begin(), Key.end(), Key.begin(), ::towlower);
84 LPCTSTR sQuote(nullptr), sEndQuote(nullptr);
85 if (sVal[0])
87 if (sVal[0] != L' ')
88 sVal = _wcsinc(sVal);
89 else
91 while (sVal[0] == L' ')
92 sVal = _wcsinc(sVal);
95 LPCTSTR nextArg = wcspbrk(sVal, m_sDelims);
97 sQuote = wcspbrk(sVal, m_sQuotes);
99 if (nextArg == sVal)
101 // current key has no value, but a next key exist - so don't use next key as value of current one
102 --sVal;
103 sQuote = sVal;
104 sEndQuote = sVal;
106 else if (nextArg && nextArg < sQuote)
108 // current key has a value w/o quotes, but next key one has value in quotes
109 sQuote = sVal;
110 sEndQuote = wcschr(sQuote, L' ');
112 else
114 if(sQuote == sVal)
116 // string with quotes (defined in m_sQuotes, e.g. '")
117 sQuote = _wcsinc(sVal);
118 sEndQuote = wcspbrk(sQuote, m_sQuotes);
120 // search for double quotes
121 while (sEndQuote)
123 auto nextQuote = _wcsinc(sEndQuote);
124 if (nextQuote[0] == L'"')
126 working.erase(working.begin() + (sEndQuote - working.data()));
127 sEndQuote = wcspbrk(nextQuote, m_sQuotes);
128 continue;
130 break;
133 else
135 sQuote = sVal;
136 sEndQuote = wcschr(sQuote, L' ');
141 if (!sEndQuote)
143 // no end quotes or terminating space, take the rest of the string to its end
144 if (!Key.empty() && sQuote)
146 std::wstring csVal(sQuote);
147 m_valueMap.insert(CValsMap::value_type(Key, csVal));
149 break;
151 else
153 // end quote
154 if(!Key.empty())
156 std::wstring csVal(sQuote, (int)(sEndQuote - sQuote));
157 m_valueMap.insert(CValsMap::value_type(Key, csVal));
159 sCurrent = _wcsinc(sEndQuote);
160 continue;
165 return !m_valueMap.empty(); //TRUE if arguments were found
168 CCmdLineParser::CValsMap::const_iterator CCmdLineParser::findKey(LPCTSTR sKey) const
170 std::wstring s(sKey);
171 std::transform(s.begin(), s.end(), s.begin(), ::towlower);
172 return m_valueMap.find(s);
175 BOOL CCmdLineParser::HasKey(LPCTSTR sKey) const
177 CValsMap::const_iterator it = findKey(sKey);
178 if (it == m_valueMap.cend())
179 return false;
180 return true;
184 BOOL CCmdLineParser::HasVal(LPCTSTR sKey) const
186 CValsMap::const_iterator it = findKey(sKey);
187 if (it == m_valueMap.cend())
188 return false;
189 if(it->second.empty())
190 return false;
191 return true;
194 LPCTSTR CCmdLineParser::GetVal(LPCTSTR sKey) const
196 CValsMap::const_iterator it = findKey(sKey);
197 if (it == m_valueMap.cend())
198 return 0;
199 return it->second.c_str();
202 LONG CCmdLineParser::GetLongVal(LPCTSTR sKey) const
204 CValsMap::const_iterator it = findKey(sKey);
205 if (it == m_valueMap.cend())
206 return 0;
207 return _wtol(it->second.c_str());
210 __int64 CCmdLineParser::GetLongLongVal(LPCTSTR sKey) const
212 CValsMap::const_iterator it = findKey(sKey);
213 if (it == m_valueMap.cend())
214 return 0;
215 return _wtoi64(it->second.c_str());
218 CCmdLineParser::ITERPOS CCmdLineParser::begin() const
220 return m_valueMap.cbegin();
223 CCmdLineParser::ITERPOS CCmdLineParser::getNext(ITERPOS& pos, std::wstring& sKey, std::wstring& sValue) const
225 if (m_valueMap.cend() == pos)
227 sKey.clear();
228 return pos;
230 else
232 sKey = pos->first;
233 sValue = pos->second;
234 return ++pos;
238 BOOL CCmdLineParser::isLast(const ITERPOS& pos) const
240 return (pos == m_valueMap.cend());