mirror of
https://github.com/notepad-plus-plus/notepad-plus-plus.git
synced 2025-07-26 07:15:21 +02:00
Fix commandline parsing issue
Fix issues where filenames would have multiple whitespaces in them. Fixes #5861, close #5883
This commit is contained in:
parent
607999c8b8
commit
dc6bd2a8d2
@ -81,70 +81,48 @@ void allowWmCopydataMessages(Notepad_plus_Window& notepad_plus_plus, const NppPa
|
|||||||
ParamVector parseCommandLine(const TCHAR* commandLine)
|
ParamVector parseCommandLine(const TCHAR* commandLine)
|
||||||
{
|
{
|
||||||
ParamVector result;
|
ParamVector result;
|
||||||
int numArgs = 0;
|
if ( commandLine[0] != '\0' )
|
||||||
|
{
|
||||||
|
int numArgs;
|
||||||
LPWSTR* tokenizedCmdLine = CommandLineToArgvW( commandLine, &numArgs );
|
LPWSTR* tokenizedCmdLine = CommandLineToArgvW( commandLine, &numArgs );
|
||||||
if ( tokenizedCmdLine != nullptr )
|
if ( tokenizedCmdLine != nullptr )
|
||||||
{
|
{
|
||||||
result.assign( tokenizedCmdLine+1, tokenizedCmdLine+numArgs ); // If numArgs == 1, it will do nothing
|
result.assign( tokenizedCmdLine, tokenizedCmdLine+numArgs );
|
||||||
LocalFree( tokenizedCmdLine );
|
LocalFree( tokenizedCmdLine );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Looks for -z arguments and strips command line arguments following those, if any
|
|
||||||
void stripIgnoredParams(ParamVector & params)
|
|
||||||
{
|
|
||||||
for ( auto it = params.begin(); it != params.end(); )
|
|
||||||
{
|
|
||||||
if (lstrcmp(it->c_str(), TEXT("-z")) == 0)
|
|
||||||
{
|
|
||||||
auto nextIt = std::next(it);
|
|
||||||
if ( nextIt != params.end() )
|
|
||||||
{
|
|
||||||
params.erase(nextIt);
|
|
||||||
}
|
|
||||||
it = params.erase(it);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. Converts /p to -quickPrint if it exists as the first parameter
|
// 1. Converts /p to -quickPrint if it exists as the first parameter
|
||||||
// 2. Concatenates all remaining parameters to form a file path, adding appending .txt extension if necessary
|
// 2. Concatenates all remaining parameters to form a file path, adding appending .txt extension if necessary
|
||||||
// This seems to mirror Notepad's behaviour
|
// This seems to mirror Notepad's behaviour
|
||||||
void convertParamsToNotepadStyle(ParamVector & params)
|
ParamVector convertParamsToNotepadStyle(PWSTR pCmdLine)
|
||||||
{
|
{
|
||||||
ParamVector newParams;
|
ParamVector params;
|
||||||
auto it = params.begin();
|
if ( _tcsnicmp(TEXT("/p"), pCmdLine, 2) == 0 ) // Notepad accepts both /p and /P, so compare case insensitively
|
||||||
if ( it != params.end() && lstrcmpi(TEXT("/p"), it->c_str()) == 0 ) // Notepad accepts both /p and /P, so compare case insensitively
|
|
||||||
{
|
{
|
||||||
++it;
|
params.emplace_back(TEXT("-quickPrint"));
|
||||||
newParams.emplace_back(TEXT("-quickPrint"));
|
pCmdLine += 2; // Length of "/p"
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ssHasContents = false;
|
// Advance to the first non-whitespace character
|
||||||
generic_stringstream ss;
|
while ( iswspace( *pCmdLine ) )
|
||||||
for ( ; it != params.end(); ++it )
|
|
||||||
{
|
{
|
||||||
ssHasContents = true;
|
++pCmdLine;
|
||||||
ss << *it;
|
|
||||||
if ( std::next(it) != params.end() ) ss << TEXT(" ");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ssHasContents )
|
// Now form a file name from the remaining commandline (if any is left)
|
||||||
|
if ( *pCmdLine != '\0' )
|
||||||
{
|
{
|
||||||
generic_string str = ss.str();
|
generic_string str(pCmdLine);
|
||||||
if ( *PathFindExtension(str.c_str()) == '\0' )
|
if ( *PathFindExtension(str.c_str()) == '\0' )
|
||||||
{
|
{
|
||||||
str.append(TEXT(".txt")); // If joined path has no extension, Notepad adds a .txt extension
|
str.append(TEXT(".txt")); // If joined path has no extension, Notepad adds a .txt extension
|
||||||
}
|
}
|
||||||
newParams.push_back(std::move(str));
|
params.push_back(std::move(str));
|
||||||
}
|
}
|
||||||
|
return params;
|
||||||
params = std::move(newParams);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isInList(const TCHAR *token2Find, ParamVector& params, bool eraseArg = true)
|
bool isInList(const TCHAR *token2Find, ParamVector& params, bool eraseArg = true)
|
||||||
@ -307,16 +285,81 @@ void doException(Notepad_plus_Window & notepad_plus_plus)
|
|||||||
::MessageBox(Notepad_plus_Window::gNppHWND, TEXT("Unfortunatly, Notepad++ was not able to save your work. We are sorry for any lost data."), TEXT("Recovery failure"), MB_OK | MB_ICONERROR);
|
::MessageBox(Notepad_plus_Window::gNppHWND, TEXT("Unfortunatly, Notepad++ was not able to save your work. We are sorry for any lost data."), TEXT("Recovery failure"), MB_OK | MB_ICONERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PWSTR advanceCmdLine(PWSTR pCmdLine, const generic_string& string)
|
||||||
|
{
|
||||||
|
const size_t len = string.length();
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
PWSTR ignoredString = wcsstr(pCmdLine, string.c_str());
|
||||||
|
if (ignoredString == nullptr)
|
||||||
|
{
|
||||||
|
// Should never happen - tokenized parameters contain string somewhere, so it HAS to match
|
||||||
|
// This is there just in case
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match the substring only if it matched an entire substring
|
||||||
|
if ( (ignoredString == pCmdLine || iswspace(*(ignoredString-1)) ) && // Check start
|
||||||
|
(iswspace(*(ignoredString+len)) || *(ignoredString+len) == '\0') )
|
||||||
|
{
|
||||||
|
ignoredString += len;
|
||||||
|
|
||||||
|
// Advance to the first non-whitespace and not quotation mark character
|
||||||
|
while ( iswspace( *ignoredString ) || *ignoredString == L'"' )
|
||||||
|
{
|
||||||
|
++ignoredString;
|
||||||
|
}
|
||||||
|
pCmdLine = ignoredString;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pCmdLine = ignoredString+len; // Just skip this match and resume from another
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pCmdLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Looks for -z arguments and strips command line arguments following those, if any
|
||||||
|
// Also advances pCmdLine to point after the last ignored parameter
|
||||||
|
// -notepadStyleCmdline is also considered an ignored parameter here, as we don't want it to be part of the assembled file name
|
||||||
|
PWSTR stripIgnoredParams(ParamVector & params, PWSTR pCmdLine)
|
||||||
|
{
|
||||||
|
for ( auto it = params.begin(); it != params.end(); )
|
||||||
|
{
|
||||||
|
if (lstrcmp(it->c_str(), TEXT("-z")) == 0)
|
||||||
|
{
|
||||||
|
pCmdLine = advanceCmdLine(pCmdLine, *it);
|
||||||
|
|
||||||
|
auto nextIt = std::next(it);
|
||||||
|
if ( nextIt != params.end() )
|
||||||
|
{
|
||||||
|
pCmdLine = advanceCmdLine(pCmdLine, *nextIt);
|
||||||
|
params.erase(nextIt);
|
||||||
|
}
|
||||||
|
it = params.erase(it);
|
||||||
|
}
|
||||||
|
else if (lstrcmp(it->c_str(), FLAG_NOTEPAD_COMPATIBILITY) == 0)
|
||||||
|
{
|
||||||
|
pCmdLine = advanceCmdLine(pCmdLine, *it++);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pCmdLine;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int)
|
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int)
|
||||||
{
|
{
|
||||||
ParamVector params = parseCommandLine(::GetCommandLine());
|
ParamVector params = parseCommandLine(pCmdLine);
|
||||||
stripIgnoredParams(params);
|
PWSTR pCmdLineWithoutIgnores = stripIgnoredParams(params, pCmdLine);
|
||||||
|
|
||||||
MiniDumper mdump; //for debugging purposes.
|
MiniDumper mdump; //for debugging purposes.
|
||||||
|
|
||||||
@ -329,7 +372,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int)
|
|||||||
// Convert commandline to notepad-compatible format, if applicable
|
// Convert commandline to notepad-compatible format, if applicable
|
||||||
if ( isInList(FLAG_NOTEPAD_COMPATIBILITY, params) )
|
if ( isInList(FLAG_NOTEPAD_COMPATIBILITY, params) )
|
||||||
{
|
{
|
||||||
convertParamsToNotepadStyle(params);
|
params = convertParamsToNotepadStyle(pCmdLineWithoutIgnores);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isParamePresent;
|
bool isParamePresent;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user