2025-11-28 00:35:46 +09:00

150 lines
6.8 KiB
C++

//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
#include "pch.h"
#include "CmdLine.h"
//
// Parse the command line and set options based on those arguments.
//
bool ParseCommandLine(int argc, wchar_t* argv[], const CommandLineSwitch Switches[], size_t SwitchCount)
{
//
// Iterate over the command line arguments
for (int i = 1; i < argc; i += 1)
{
if (argv[i][0] == L'-' || argv[i][0] == L'/')
{
size_t switchIndex;
for (switchIndex = 0; switchIndex < SwitchCount; switchIndex += 1)
{
size_t switchNameLength = wcslen(Switches[switchIndex].SwitchName);
if (_wcsnicmp(&argv[i][1], Switches[switchIndex].SwitchName, switchNameLength) == 0 &&
(argv[i][switchNameLength + 1] == L':' || argv[i][switchNameLength + 1] == '\0'))
{
wchar_t* switchValue = NULL;
if (Switches[switchIndex].SwitchType != CommandLineSwitch::SwitchTypeNone)
{
//
// This is a switch value that expects an argument.
//
// Check to see if the last character of the argument is a ":".
//
// If it is, then the user specified an argument, so we should use the value after the ":"
// as the argument.
//
if (argv[i][switchNameLength + 1] == L':')
{
switchValue = &argv[i][switchNameLength + 2];
}
else if (i < argc)
{
//
// If the switch value isn't optional, the next argument
// must be the value.
//
if (!Switches[switchIndex].SwitchValueOptional)
{
switchValue = argv[i + 1];
i += 1; // Skip the argument.
}
//
// Otherwise the switch value is optional, so check the next parameter.
//
// If it's a switch, the user didn't specify a value, if it's not a switch
// the user DID specify a value.
//
else if (argv[i + 1][0] != L'-' && argv[i + 1][0] != L'/')
{
switchValue = argv[i + 1];
i += 1; // Skip the argument.
}
}
else if (!Switches[switchIndex].SwitchValueOptional)
{
printf("Invalid command line argument parsing option %ls\n", Switches[switchIndex].SwitchName);
return false;
}
}
switch (Switches[switchIndex].SwitchType)
{
//
// SwitchTypeNone switches take a boolean parameter indiating whether or not the parameter was present.
//
case CommandLineSwitch::SwitchTypeNone:
*reinterpret_cast<bool*>(Switches[switchIndex].SwitchValue) = true;
break;
//
// SwitchTypeInteger switches take an integer parameter.
//
case CommandLineSwitch::SwitchTypeInteger:
{
wchar_t* endValue;
long value = wcstoul(switchValue, &endValue, 0);
if (value == ULONG_MAX || value == 0 || (*endValue != L'\0' && !iswspace(*endValue)))
{
printf("Command line switch %ls expected an integer value, received %ls\n", Switches[switchIndex].SwitchName, switchValue);
return false;
}
*reinterpret_cast<long*>(Switches[switchIndex].SwitchValue) = value;
break;
}
//
// SwitchTypeString switches take a string parameter - allocate a buffer for the string using operator new[].
//
case CommandLineSwitch::SwitchTypeString:
{
wchar_t** switchLocation = reinterpret_cast<wchar_t**>(Switches[switchIndex].SwitchValue);
//
// If the user didn't specify a value, set the location to NULL.
//
if (switchValue == NULL || *switchValue == '\0')
{
*switchLocation = NULL;
}
else
{
size_t switchLength = wcslen(switchValue) + 1;
*switchLocation = new (std::nothrow) wchar_t[switchLength];
if (*switchLocation == NULL)
{
printf("Unable to allocate memory for switch %ls", Switches[switchIndex].SwitchName);
return false;
}
HRESULT hr = StringCchCopy(*switchLocation, switchLength, switchValue);
if (FAILED(hr))
{
printf("Unable to copy command line string %ls to buffer\n", switchValue);
return false;
}
}
break;
}
default:
break;
}
// We've processed this command line switch, we can move to the next argument.
//
break;
}
}
if (switchIndex == SwitchCount)
{
printf("unrecognized switch: %ls\n", argv[i]);
return false;
}
}
}
return true;
}