//********************************************************* // // 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(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(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(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; }