Blame winpr/libwinpr/utils/cmdline.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * WinPR: Windows Portable Runtime
Packit 1fb8d4
 * Command-Line Utils
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/cmdline.h>
Packit 1fb8d4
Packit Service 5a9772
#include "../log.h"
Packit Service 5a9772
Packit Service 5a9772
#define TAG WINPR_TAG("commandline")
Packit Service 5a9772
Packit 1fb8d4
/**
Packit 1fb8d4
 * Command-line syntax: some basic concepts:
Packit 1fb8d4
 * https://pythonconquerstheuniverse.wordpress.com/2010/07/25/command-line-syntax-some-basic-concepts/
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Command-Line Syntax:
Packit 1fb8d4
 *
Packit 1fb8d4
 * <sigil><keyword><separator><value>
Packit 1fb8d4
 *
Packit 1fb8d4
 * <sigil>: '/' or '-' or ('+' | '-')
Packit 1fb8d4
 *
Packit 1fb8d4
 * <keyword>: option, named argument, flag
Packit 1fb8d4
 *
Packit 1fb8d4
 * <separator>: ':' or '='
Packit 1fb8d4
 *
Packit 1fb8d4
 * <value>: argument value
Packit 1fb8d4
 *
Packit 1fb8d4
 */
Packit 1fb8d4
Packit Service 5a9772
static void log_error(DWORD flags, LPCSTR message, int index, LPCSTR argv)
Packit Service 5a9772
{
Packit Service 5a9772
	if ((flags & COMMAND_LINE_SILENCE_PARSER) == 0)
Packit Service 5a9772
		WLog_ERR(TAG, message, index, argv);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
int CommandLineParseArgumentsA(int argc, LPSTR* argv, COMMAND_LINE_ARGUMENT_A* options, DWORD flags,
Packit Service 5a9772
                               void* context, COMMAND_LINE_PRE_FILTER_FN_A preFilter,
Packit Service 5a9772
                               COMMAND_LINE_POST_FILTER_FN_A postFilter)
Packit 1fb8d4
{
Packit 1fb8d4
	int i, j;
Packit 1fb8d4
	int status;
Packit 1fb8d4
	int count;
Packit 1fb8d4
	size_t length;
Packit 1fb8d4
	BOOL notescaped;
Packit 1fb8d4
	const char* sigil;
Packit 1fb8d4
	size_t sigil_length;
Packit 1fb8d4
	char* keyword;
Packit Service 5a9772
	size_t keyword_length;
Packit 1fb8d4
	SSIZE_T keyword_index;
Packit 1fb8d4
	char* separator;
Packit 1fb8d4
	char* value;
Packit 1fb8d4
	int toggle;
Packit 1fb8d4
	status = 0;
Packit 1fb8d4
	notescaped = FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!argv)
Packit 1fb8d4
		return status;
Packit 1fb8d4
Packit 1fb8d4
	if (argc == 1)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (flags & COMMAND_LINE_IGN_UNKNOWN_KEYWORD)
Packit 1fb8d4
			status = 0;
Packit 1fb8d4
		else
Packit 1fb8d4
			status = COMMAND_LINE_STATUS_PRINT_HELP;
Packit 1fb8d4
Packit 1fb8d4
		return status;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	for (i = 1; i < argc; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		BOOL found = FALSE;
Packit 1fb8d4
		BOOL escaped = TRUE;
Packit 1fb8d4
Packit 1fb8d4
		if (preFilter)
Packit 1fb8d4
		{
Packit 1fb8d4
			count = preFilter(context, i, argc, argv);
Packit 1fb8d4
Packit 1fb8d4
			if (count < 0)
Packit 1fb8d4
			{
Packit Service 5a9772
				log_error(flags, "Failed for index %d [%s]: PreFilter rule could not be applied", i,
Packit Service 5a9772
				          argv[i]);
Packit 1fb8d4
				status = COMMAND_LINE_ERROR;
Packit 1fb8d4
				return status;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if (count > 0)
Packit 1fb8d4
			{
Packit 1fb8d4
				i += (count - 1);
Packit 1fb8d4
				continue;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		sigil = argv[i];
Packit 1fb8d4
		length = strlen(argv[i]);
Packit 1fb8d4
Packit 1fb8d4
		if ((sigil[0] == '/') && (flags & COMMAND_LINE_SIGIL_SLASH))
Packit 1fb8d4
		{
Packit 1fb8d4
			sigil_length = 1;
Packit 1fb8d4
		}
Packit 1fb8d4
		else if ((sigil[0] == '-') && (flags & COMMAND_LINE_SIGIL_DASH))
Packit 1fb8d4
		{
Packit 1fb8d4
			sigil_length = 1;
Packit 1fb8d4
Packit 1fb8d4
			if (length > 2)
Packit 1fb8d4
			{
Packit 1fb8d4
				if ((sigil[1] == '-') && (flags & COMMAND_LINE_SIGIL_DOUBLE_DASH))
Packit 1fb8d4
					sigil_length = 2;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
		else if ((sigil[0] == '+') && (flags & COMMAND_LINE_SIGIL_PLUS_MINUS))
Packit 1fb8d4
		{
Packit 1fb8d4
			sigil_length = 1;
Packit 1fb8d4
		}
Packit 1fb8d4
		else if ((sigil[0] == '-') && (flags & COMMAND_LINE_SIGIL_PLUS_MINUS))
Packit 1fb8d4
		{
Packit 1fb8d4
			sigil_length = 1;
Packit 1fb8d4
		}
Packit 1fb8d4
		else if (flags & COMMAND_LINE_SIGIL_NONE)
Packit 1fb8d4
		{
Packit 1fb8d4
			sigil_length = 0;
Packit 1fb8d4
		}
Packit 1fb8d4
		else if (flags & COMMAND_LINE_SIGIL_NOT_ESCAPED)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (notescaped)
Packit Service 5a9772
			{
Packit Service 5a9772
				log_error(flags, "Failed at index %d [%s]: Unescaped sigil", i, argv[i]);
Packit 1fb8d4
				return COMMAND_LINE_ERROR;
Packit Service 5a9772
			}
Packit 1fb8d4
Packit 1fb8d4
			sigil_length = 0;
Packit 1fb8d4
			escaped = FALSE;
Packit 1fb8d4
			notescaped = TRUE;
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit Service 5a9772
			log_error(flags, "Failed at index %d [%s]: Invalid sigil", i, argv[i]);
Packit 1fb8d4
			return COMMAND_LINE_ERROR;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if ((sigil_length > 0) || (flags & COMMAND_LINE_SIGIL_NONE) ||
Packit 1fb8d4
		    (flags & COMMAND_LINE_SIGIL_NOT_ESCAPED))
Packit 1fb8d4
		{
Packit 1fb8d4
			if (length < (sigil_length + 1))
Packit 1fb8d4
			{
Packit 1fb8d4
				if ((flags & COMMAND_LINE_IGN_UNKNOWN_KEYWORD))
Packit 1fb8d4
					continue;
Packit 1fb8d4
Packit 1fb8d4
				return COMMAND_LINE_ERROR_NO_KEYWORD;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			keyword_index = sigil_length;
Packit 1fb8d4
			keyword = &argv[i][keyword_index];
Packit 1fb8d4
			toggle = -1;
Packit 1fb8d4
Packit 1fb8d4
			if (flags & COMMAND_LINE_SIGIL_ENABLE_DISABLE)
Packit 1fb8d4
			{
Packit 1fb8d4
				if (strncmp(keyword, "enable-", 7) == 0)
Packit 1fb8d4
				{
Packit 1fb8d4
					toggle = TRUE;
Packit 1fb8d4
					keyword_index += 7;
Packit 1fb8d4
					keyword = &argv[i][keyword_index];
Packit 1fb8d4
				}
Packit 1fb8d4
				else if (strncmp(keyword, "disable-", 8) == 0)
Packit 1fb8d4
				{
Packit 1fb8d4
					toggle = FALSE;
Packit 1fb8d4
					keyword_index += 8;
Packit 1fb8d4
					keyword = &argv[i][keyword_index];
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			separator = NULL;
Packit 1fb8d4
Packit 1fb8d4
			if ((flags & COMMAND_LINE_SEPARATOR_COLON) && (!separator))
Packit 1fb8d4
				separator = strchr(keyword, ':');
Packit 1fb8d4
Packit 1fb8d4
			if ((flags & COMMAND_LINE_SEPARATOR_EQUAL) && (!separator))
Packit 1fb8d4
				separator = strchr(keyword, '=');
Packit 1fb8d4
Packit 1fb8d4
			if (separator)
Packit 1fb8d4
			{
Packit 1fb8d4
				SSIZE_T separator_index = (separator - argv[i]);
Packit 1fb8d4
				SSIZE_T value_index = separator_index + 1;
Packit 1fb8d4
				keyword_length = (separator - keyword);
Packit 1fb8d4
				value = &argv[i][value_index];
Packit 1fb8d4
			}
Packit 1fb8d4
			else
Packit 1fb8d4
			{
Packit 1fb8d4
				keyword_length = (length - keyword_index);
Packit 1fb8d4
				value = NULL;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if (!escaped)
Packit 1fb8d4
				continue;
Packit 1fb8d4
Packit 1fb8d4
			for (j = 0; options[j].Name != NULL; j++)
Packit 1fb8d4
			{
Packit 1fb8d4
				BOOL match = FALSE;
Packit 1fb8d4
Packit 1fb8d4
				if (strncmp(options[j].Name, keyword, keyword_length) == 0)
Packit 1fb8d4
				{
Packit 1fb8d4
					if (strlen(options[j].Name) == keyword_length)
Packit 1fb8d4
						match = TRUE;
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				if ((!match) && (options[j].Alias != NULL))
Packit 1fb8d4
				{
Packit 1fb8d4
					if (strncmp(options[j].Alias, keyword, keyword_length) == 0)
Packit 1fb8d4
					{
Packit 1fb8d4
						if (strlen(options[j].Alias) == keyword_length)
Packit 1fb8d4
							match = TRUE;
Packit 1fb8d4
					}
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				if (!match)
Packit 1fb8d4
					continue;
Packit 1fb8d4
Packit 1fb8d4
				found = match;
Packit 1fb8d4
				options[j].Index = i;
Packit 1fb8d4
Packit 1fb8d4
				if ((flags & COMMAND_LINE_SEPARATOR_SPACE) && ((i + 1) < argc))
Packit 1fb8d4
				{
Packit 1fb8d4
					BOOL argument;
Packit 1fb8d4
					int value_present = 1;
Packit 1fb8d4
Packit 1fb8d4
					if (flags & COMMAND_LINE_SIGIL_DASH)
Packit 1fb8d4
					{
Packit 1fb8d4
						if (strncmp(argv[i + 1], "-", 1) == 0)
Packit 1fb8d4
							value_present = 0;
Packit 1fb8d4
					}
Packit 1fb8d4
Packit 1fb8d4
					if (flags & COMMAND_LINE_SIGIL_DOUBLE_DASH)
Packit 1fb8d4
					{
Packit 1fb8d4
						if (strncmp(argv[i + 1], "--", 2) == 0)
Packit 1fb8d4
							value_present = 0;
Packit 1fb8d4
					}
Packit 1fb8d4
Packit 1fb8d4
					if (flags & COMMAND_LINE_SIGIL_SLASH)
Packit 1fb8d4
					{
Packit 1fb8d4
						if (strncmp(argv[i + 1], "/", 1) == 0)
Packit 1fb8d4
							value_present = 0;
Packit 1fb8d4
					}
Packit 1fb8d4
Packit 1fb8d4
					if ((options[j].Flags & COMMAND_LINE_VALUE_REQUIRED) ||
Packit 1fb8d4
					    (options[j].Flags & COMMAND_LINE_VALUE_OPTIONAL))
Packit 1fb8d4
						argument = TRUE;
Packit 1fb8d4
					else
Packit 1fb8d4
						argument = FALSE;
Packit 1fb8d4
Packit 1fb8d4
					if (value_present && argument)
Packit 1fb8d4
					{
Packit 1fb8d4
						i++;
Packit 1fb8d4
						value = argv[i];
Packit 1fb8d4
					}
Packit 1fb8d4
					else if (!value_present && (options[j].Flags & COMMAND_LINE_VALUE_OPTIONAL))
Packit 1fb8d4
					{
Packit 1fb8d4
						value = NULL;
Packit 1fb8d4
					}
Packit 1fb8d4
					else if (!value_present && argument)
Packit Service 5a9772
					{
Packit Service 5a9772
						log_error(flags, "Failed at index %d [%s]: Argument required", i, argv[i]);
Packit 1fb8d4
						return COMMAND_LINE_ERROR;
Packit Service 5a9772
					}
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				if (!(flags & COMMAND_LINE_SEPARATOR_SPACE))
Packit 1fb8d4
				{
Packit 1fb8d4
					if (value && (options[j].Flags & COMMAND_LINE_VALUE_FLAG))
Packit Service 5a9772
					{
Packit Service 5a9772
						log_error(flags, "Failed at index %d [%s]: Unexpected value", i, argv[i]);
Packit 1fb8d4
						return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
Packit Service 5a9772
					}
Packit 1fb8d4
				}
Packit 1fb8d4
				else
Packit 1fb8d4
				{
Packit 1fb8d4
					if (value && (options[j].Flags & COMMAND_LINE_VALUE_FLAG))
Packit 1fb8d4
					{
Packit 1fb8d4
						i--;
Packit 1fb8d4
						value = NULL;
Packit 1fb8d4
					}
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				if (!value && (options[j].Flags & COMMAND_LINE_VALUE_REQUIRED))
Packit 1fb8d4
				{
Packit Service 5a9772
					log_error(flags, "Failed at index %d [%s]: Missing value", i, argv[i]);
Packit 1fb8d4
					status = COMMAND_LINE_ERROR_MISSING_VALUE;
Packit 1fb8d4
					return status;
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				options[j].Flags |= COMMAND_LINE_ARGUMENT_PRESENT;
Packit 1fb8d4
Packit 1fb8d4
				if (value)
Packit 1fb8d4
				{
Packit 1fb8d4
					if (options[j].Flags & (COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_VALUE_BOOL))
Packit Service 5a9772
					{
Packit Service 5a9772
						log_error(flags, "Failed at index %d [%s]: Unexpected value", i, argv[i]);
Packit 1fb8d4
						return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
Packit Service 5a9772
					}
Packit 1fb8d4
Packit 1fb8d4
					options[j].Value = value;
Packit 1fb8d4
					options[j].Flags |= COMMAND_LINE_VALUE_PRESENT;
Packit 1fb8d4
				}
Packit 1fb8d4
				else
Packit 1fb8d4
				{
Packit 1fb8d4
					if (options[j].Flags & COMMAND_LINE_VALUE_FLAG)
Packit 1fb8d4
					{
Packit Service 5a9772
						options[j].Value = (LPSTR)1;
Packit 1fb8d4
						options[j].Flags |= COMMAND_LINE_VALUE_PRESENT;
Packit 1fb8d4
					}
Packit 1fb8d4
					else if (options[j].Flags & COMMAND_LINE_VALUE_BOOL)
Packit 1fb8d4
					{
Packit 1fb8d4
						if (flags & COMMAND_LINE_SIGIL_ENABLE_DISABLE)
Packit 1fb8d4
						{
Packit 1fb8d4
							if (toggle == -1)
Packit 1fb8d4
								options[j].Value = BoolValueTrue;
Packit 1fb8d4
							else if (!toggle)
Packit 1fb8d4
								options[j].Value = BoolValueFalse;
Packit 1fb8d4
							else
Packit 1fb8d4
								options[j].Value = BoolValueTrue;
Packit 1fb8d4
						}
Packit 1fb8d4
						else
Packit 1fb8d4
						{
Packit 1fb8d4
							if (sigil[0] == '+')
Packit 1fb8d4
								options[j].Value = BoolValueTrue;
Packit 1fb8d4
							else if (sigil[0] == '-')
Packit 1fb8d4
								options[j].Value = BoolValueFalse;
Packit 1fb8d4
							else
Packit 1fb8d4
								options[j].Value = BoolValueTrue;
Packit 1fb8d4
						}
Packit 1fb8d4
Packit 1fb8d4
						options[j].Flags |= COMMAND_LINE_VALUE_PRESENT;
Packit 1fb8d4
					}
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				if (postFilter)
Packit 1fb8d4
				{
Packit 1fb8d4
					count = postFilter(context, &options[j]);
Packit 1fb8d4
Packit 1fb8d4
					if (count < 0)
Packit 1fb8d4
					{
Packit Service 5a9772
						log_error(flags,
Packit Service 5a9772
						          "Failed at index %d [%s]: PostFilter rule could not be applied",
Packit Service 5a9772
						          i, argv[i]);
Packit 1fb8d4
						status = COMMAND_LINE_ERROR;
Packit 1fb8d4
						return status;
Packit 1fb8d4
					}
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				if (options[j].Flags & COMMAND_LINE_PRINT)
Packit 1fb8d4
					return COMMAND_LINE_STATUS_PRINT;
Packit 1fb8d4
				else if (options[j].Flags & COMMAND_LINE_PRINT_HELP)
Packit 1fb8d4
					return COMMAND_LINE_STATUS_PRINT_HELP;
Packit 1fb8d4
				else if (options[j].Flags & COMMAND_LINE_PRINT_VERSION)
Packit 1fb8d4
					return COMMAND_LINE_STATUS_PRINT_VERSION;
Packit 1fb8d4
				else if (options[j].Flags & COMMAND_LINE_PRINT_BUILDCONFIG)
Packit 1fb8d4
					return COMMAND_LINE_STATUS_PRINT_BUILDCONFIG;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if (!found && (flags & COMMAND_LINE_IGN_UNKNOWN_KEYWORD) == 0)
Packit Service 5a9772
			{
Packit Service 5a9772
				log_error(flags, "Failed at index %d [%s]: Unexpected keyword", i, argv[i]);
Packit 1fb8d4
				return COMMAND_LINE_ERROR_NO_KEYWORD;
Packit Service 5a9772
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int CommandLineParseArgumentsW(int argc, LPWSTR* argv, COMMAND_LINE_ARGUMENT_W* options,
Packit Service 5a9772
                               DWORD flags, void* context, COMMAND_LINE_PRE_FILTER_FN_W preFilter,
Packit Service 5a9772
                               COMMAND_LINE_POST_FILTER_FN_W postFilter)
Packit 1fb8d4
{
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int CommandLineClearArgumentsA(COMMAND_LINE_ARGUMENT_A* options)
Packit 1fb8d4
{
Packit 1fb8d4
	size_t i;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; options[i].Name != NULL; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		options[i].Flags &= COMMAND_LINE_INPUT_FLAG_MASK;
Packit 1fb8d4
		options[i].Value = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int CommandLineClearArgumentsW(COMMAND_LINE_ARGUMENT_W* options)
Packit 1fb8d4
{
Packit 1fb8d4
	int i;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; options[i].Name != NULL; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		options[i].Flags &= COMMAND_LINE_INPUT_FLAG_MASK;
Packit 1fb8d4
		options[i].Value = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
COMMAND_LINE_ARGUMENT_A* CommandLineFindArgumentA(COMMAND_LINE_ARGUMENT_A* options, LPCSTR Name)
Packit 1fb8d4
{
Packit 1fb8d4
	int i;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; options[i].Name != NULL; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (strcmp(options[i].Name, Name) == 0)
Packit 1fb8d4
			return &options[i];
Packit 1fb8d4
Packit 1fb8d4
		if (options[i].Alias != NULL)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (strcmp(options[i].Alias, Name) == 0)
Packit 1fb8d4
				return &options[i];
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
COMMAND_LINE_ARGUMENT_W* CommandLineFindArgumentW(COMMAND_LINE_ARGUMENT_W* options, LPCWSTR Name)
Packit 1fb8d4
{
Packit 1fb8d4
	int i;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; options[i].Name != NULL; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (_wcscmp(options[i].Name, Name) == 0)
Packit 1fb8d4
			return &options[i];
Packit 1fb8d4
Packit 1fb8d4
		if (options[i].Alias != NULL)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (_wcscmp(options[i].Alias, Name) == 0)
Packit 1fb8d4
				return &options[i];
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
COMMAND_LINE_ARGUMENT_A* CommandLineFindNextArgumentA(COMMAND_LINE_ARGUMENT_A* argument)
Packit 1fb8d4
{
Packit 1fb8d4
	COMMAND_LINE_ARGUMENT_A* nextArgument;
Packit 1fb8d4
Packit 1fb8d4
	if (!argument || !argument->Name)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	nextArgument = &argument[1];
Packit 1fb8d4
Packit 1fb8d4
	if (nextArgument->Name == NULL)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	return nextArgument;
Packit 1fb8d4
}
Packit Service 5a9772
Packit Service 5a9772
char** CommandLineParseCommaSeparatedValuesEx(const char* name, const char* list, size_t* count)
Packit Service 5a9772
{
Packit Service 5a9772
	char** p;
Packit Service 5a9772
	char* str;
Packit Service 5a9772
	size_t nArgs;
Packit Service 5a9772
	size_t index;
Packit Service 5a9772
	size_t nCommas;
Packit Service 5a9772
	size_t prefix, len;
Packit Service 5a9772
	nCommas = 0;
Packit Service 5a9772
Packit Service 5a9772
	if (count == NULL)
Packit Service 5a9772
		return NULL;
Packit Service 5a9772
Packit Service 5a9772
	*count = 0;
Packit Service 5a9772
Packit Service 5a9772
	if (!list)
Packit Service 5a9772
	{
Packit Service 5a9772
		if (name)
Packit Service 5a9772
		{
Packit Service 5a9772
			size_t len = strlen(name);
Packit Service 5a9772
			p = (char**)calloc(2UL + len, sizeof(char*));
Packit Service 5a9772
Packit Service 5a9772
			if (p)
Packit Service 5a9772
			{
Packit Service 5a9772
				char* dst = (char*)&p[1];
Packit Service 5a9772
				p[0] = dst;
Packit Service 5a9772
				sprintf_s(dst, len + 1, "%s", name);
Packit Service 5a9772
				*count = 1;
Packit Service 5a9772
				return p;
Packit Service 5a9772
			}
Packit Service 5a9772
		}
Packit Service 5a9772
Packit Service 5a9772
		return NULL;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	{
Packit Service 5a9772
		const char* it = list;
Packit Service 5a9772
Packit Service 5a9772
		while ((it = strchr(it, ',')) != NULL)
Packit Service 5a9772
		{
Packit Service 5a9772
			it++;
Packit Service 5a9772
			nCommas++;
Packit Service 5a9772
		}
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	nArgs = nCommas + 1;
Packit Service 5a9772
Packit Service 5a9772
	if (name)
Packit Service 5a9772
		nArgs++;
Packit Service 5a9772
Packit Service 5a9772
	prefix = (nArgs + 1UL) * sizeof(char*);
Packit Service 5a9772
	len = strlen(list);
Packit Service 5a9772
	p = (char**)calloc(len + prefix + 1, sizeof(char*));
Packit Service 5a9772
Packit Service 5a9772
	if (!p)
Packit Service 5a9772
		return NULL;
Packit Service 5a9772
Packit Service 5a9772
	str = &((char*)p)[prefix];
Packit Service 5a9772
	memcpy(str, list, len);
Packit Service 5a9772
Packit Service 5a9772
	if (name)
Packit Service 5a9772
		p[0] = (char*)name;
Packit Service 5a9772
Packit Service 5a9772
	for (index = name ? 1 : 0; index < nArgs; index++)
Packit Service 5a9772
	{
Packit Service 5a9772
		char* comma = strchr(str, ',');
Packit Service 5a9772
		p[index] = str;
Packit Service 5a9772
Packit Service 5a9772
		if (comma)
Packit Service 5a9772
		{
Packit Service 5a9772
			str = comma + 1;
Packit Service 5a9772
			*comma = '\0';
Packit Service 5a9772
		}
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	*count = nArgs;
Packit Service 5a9772
	return p;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
char** CommandLineParseCommaSeparatedValues(const char* list, size_t* count)
Packit Service 5a9772
{
Packit Service 5a9772
	return CommandLineParseCommaSeparatedValuesEx(NULL, list, count);
Packit Service 5a9772
}