www.pudn.com > CmdLine-src.zip > cmdline.h


//-------------------------------------------------------------------------------------------- 
//   Copyright (c) 2001-2004 Klaus H. Probst [kprobst@vbbox.com] 
// 
//   This software is provided 'as-is', without any express or implied warranty. In no event 
//   will the authors be held liable for any damages arising from the use of this software. 
// 
//   Permission is granted to anyone to use this software for any purpose, including 
//   commercial applications, and to alter it and redistribute it freely, subject to the 
//   following restrictions: 
// 
//   ~ The origin of this software must not be misrepresented; you must not claim that you 
//     wrote the original software. If you use this software in a product, an acknowledgment 
//     in the product documentation would be appreciated but is not required. 
//   ~ Altered source versions must be plainly marked as such, and must not be misrepresented 
//     as being the original software. 
//   ~ This notice may not be removed or altered from any source distribution. 
//-------------------------------------------------------------------------------------------- 
// 
//  CmdLine.h 
// 
//  A fairly complete command line parser* class for console or windowed applications. It  
//	supports both straight command line parsing (as provided by the OS) or custom command  
//	lines typed by the user, for example, from an interactive console. 
// 
//	CommandLine assumes a few things about how your application's command line is  
//	structured. Basically, it roughly expects something like the following format: 
// 
//		myapp.exe arg1 /a /b:c /d @arg2 /g arg3 arg4 arg5 
// 
//	Where: 
// 
//		myapp.exe		- This is the path to the executable or a dummy placeholder. In the 
//						  class this is the 'path'. 
//		arg1			- A positional argument (not an option). More than one OK. Spaces OK 
//						  as long as the argument is quoted. The max length is MAX_PATH. In 
//						  the class, this is considered a 'Command'. 
//		/a, /d, /g		- Option switches. The '/' is called a 'switch marker' and can be 
//						  whatever non-alphanumeric or whitespace character you want. For  
//						  example, '-' or '#' or whatever. Normally '-' or '/' are expected 
//						  by users. Max length of each one is 32 characters. 
//		/b:c			- A switch with a value. The ':' is called a 'value marker' and it has 
//						  to be different than the switch marker. Whatever comes after it is 
//						  considered the value. Spaces are OK as long as the whole thing is 
//						  enclosed in quotes. The max length is MAX_PATH. 
//		@arg2			- A 'marked' argument that begins with a special character different 
//						  from both the switch and value markers. For example, a 'response file' 
//						  as used by some compilers and compression utilities. 
//		arg3,arg4,arg5	- Trailing positional arguments that can be enumerated as long as they 
//						  come after a switch. For example, a list of files. 
// 
//	This is just a sample. You can also use it like so: 
// 
//		myapp.exe arg1 arg2 -a val1 -bc -d -E val2 
// 
//	which looks more like a *nix-style command line. Specifically, the 'val1' and 'val2' can be  
//	considered switch values and retrieved even though the command line does not use a character  
//	to delimit values. The class can also work in case-sensitive mode, so '-f' is different  
//	from '-F'. 
// 
//	These are just a few examples. You can use different switch markers and value delimiters 
//	(or none at all), as well as marked arguments and multiple trailing positional arguments.  
// 
//  Pleass refer to the README.HTML file and the online page (accessible from vbbox.com/cpp/) for  
//	(fairly) complete documentation. The code itself is also well documented so if you can't  
//	figure something out from the docs you should be able to divine it using the comments =) 
// 
//	* It's really self-serving to call this a 'parser' since the parsing is really done by the  
//	  OS. It's really more of a 'structured accessor' or something like that. Sorta. 
// 
//-------------------------------------------------------------------------------------------- 
#pragma once 
 
#ifndef _CMDLINE_INC 
#define _CMDLINE_INC 
 
// A common problem - _UNICODE is used by the CRT 
#ifdef UNICODE 
#ifndef _UNICODE 
#define _UNICODE 
#endif 
#endif 
 
#include  
 
#define CMDLINE_MAX_SWITCH				32					    // Max length for a switch 
#define CMDLINE_MAX_VALUE				MAX_PATH                // Max length for a switch value 
#define CMDLINE_MAX_ARGUMENT			CMDLINE_MAX_VALUE       // Max length for a positional argument 
 
// Value types. 
#define CMDLINE_VALUETYPE_NONE			0 
#define CMDLINE_VALUETYPE_TCHAR			1 
#define CMDLINE_VALUETYPE_INT			2 
#define CMDLINE_VALUETYPE_FLOAT			3 
 
class CommandLine 
{ 
 
protected: 
	 
	// Intended for implementations. 
	CommandLine() 
	{ 
	} 
 
public: 
 
	// 
	//	Initialize a new instance using whatever GetCommandLine() returns. 
	//	This is probably better for non-command line apps. When running on 
	//	an NT box and building with UNICODE #defined, the constructors will  
	//	use the GetCommandLine() API to initialize the argument array.  
	//	Otherwise they'll use the __argv and __argc globals exported from 
	//	 
	// 
	//	These overloads should be used by windowed applications on Win9x and 
	//	ANSI builds on NT. 
	//	 
	CommandLine(TCHAR switchMarker, TCHAR valueMarker) 
	{ 
#if defined (UNICODE) && defined (_WIN32_WINNT) 
		InitializeFromCommandLine(GetCommandLine(), switchMarker, valueMarker, false, false); 
#else 
		InitializeFromCommandLine(NULL, switchMarker, valueMarker, false, false); 
#endif 
	} 
 
	CommandLine(TCHAR switchMarker, TCHAR valueMarker, bool caseSensitive) 
	{ 
#if defined (UNICODE) && defined (_WIN32_WINNT) 
		InitializeFromCommandLine(GetCommandLine(), switchMarker, valueMarker, false, caseSensitive); 
#else 
		InitializeFromCommandLine(NULL, switchMarker, valueMarker, false, caseSensitive); 
#endif 
	} 
 
    // 
	//	Create a new instance using the argv and argc params passed to _tmain(). This 
	//	should be the default for most console apps.  
	// 
	CommandLine(int argc, TCHAR** argv, TCHAR switchMarker, TCHAR valueMarker) : _argvOwned(false),  
																				 _caseSensitive(false) 
	{ 
		_argc = argc; 
		_argv = argv; 
		_switchMarker = switchMarker; 
		_valueMarker = valueMarker; 
 
	} 
 
	CommandLine(int argc, TCHAR** argv, TCHAR switchMarker, TCHAR valueMarker, bool caseSensitive) : _argvOwned(false) 
	{ 
 
		_argc = argc; 
		_argv = argv; 
		_switchMarker = switchMarker; 
		_valueMarker = valueMarker; 
 
		_caseSensitive = caseSensitive; 
 
	} 
 
#if defined (UNICODE) && defined (_WIN32_WINNT) 
 
	// 
	//	These overloads can be used when passing a custom command line not 
	//	actually provided by the OS. For example, commands typed by a user 
	//	in an interactive way, or read from a file. Because the class 
	//	assumes that the first element in _argv is always *something* other 
	//	than a switch or a positional/marked argument, the overloads that 
	//	accept the 'custom' parameter will actually prepend a dummy placeholder 
	//  plus one space to the passed command line before running it through 
	//  CommandLineToArgvW() if the 'custom' argument is set to true. The  
	//	default is false. 
	// 
	//	Obviously this also works for non-command line applications that don't 
	//	have access to argc/argv (though those are always exposed from the CRT). 
	//	In those cases simply take whatever GetCommandLine() returns and pass 
	//	it to the appropriate overload without the 'custom' parameter (because 
	//	it will already have the app's path in there). Or, use one of the first 
	//	two constructor overloads that automatically pull the command line. 
	//	 
	//	Custom command lines are not supported on 9x systems (because we use 
	//  a Unicode-only API to parse them). They are also not supported for 
	//	ANSI builds on NT boxes. Theoretically this could be implemented by 
	//	converting and managing the _argv array internally but I really don't  
	//	want to go there. 
	// 
	CommandLine(LPCTSTR commandLine, TCHAR switchMarker, TCHAR valueMarker) 
	{ 
		InitializeFromCommandLine(commandLine, switchMarker, valueMarker, false, false); 
	} 
 
	CommandLine(bool custom, LPCTSTR commandLine, TCHAR switchMarker, TCHAR valueMarker) 
	{ 
		InitializeFromCommandLine(commandLine, switchMarker, valueMarker, custom, false); 
	} 
 
	CommandLine(bool custom, LPCTSTR commandLine, TCHAR switchMarker, TCHAR valueMarker, bool caseSensitive) 
	{ 
		InitializeFromCommandLine(commandLine, switchMarker, valueMarker, custom, caseSensitive); 
	} 
 
	CommandLine(LPCTSTR commandLine, TCHAR switchMarker, TCHAR valueMarker, bool caseSensitive) 
	{ 
		InitializeFromCommandLine(commandLine, switchMarker, valueMarker, false, caseSensitive); 
	} 
 
 
#endif 
 
	//  
    //  Yah 
    // 
	virtual ~CommandLine() 
	{ 
 
		if ((_argvOwned) && (_argv != NULL)) 
			GlobalFree(static_cast(_argv)); 
	} 
 
public: 
 
	//  
	//	Return whether or not this instance 
	//	is case-sensitive. 
	// 
	bool CaseSensitive() const 
	{ 
		return _caseSensitive; 
	} 
 
	// 
	//	Return the switch and value marker characters. 
	// 
	virtual TCHAR SwitchMarker() const 
	{ 
		return _switchMarker; 
	} 
	 
	virtual TCHAR ValueMarker() const 
	{ 
		return _valueMarker; 
	} 
 
	// 
	//	Return the number of arguments.  
	//	 
	//	Note that this is not a count of switches - this 
	//	is the total number of elements in the parsed array 
	//	excluding the first one (the path or dummy placeholder). 
	// 
	virtual int Count() const 
	{ 
		return (_argc - 1); 
	} 
 
	// 
	//	This should always be here, but it won't be valid 
	//	if it wasn't initialized with a real command line 
	//	from the OS. 
	// 
	virtual LPCTSTR Path() const 
	{ 
		return _argv[0]; 
	} 
 
	// 
	//	This assumes that the second element in the 
	//	argument array is something other than a  
	//	switch. For example: 
	// 
	//		C:\myapp.exe blah.txt /a /b 
	// 
	//                   ^------^ 
	// 
	//	This is called a 'positional' argument, and 
	//	it is not an 'option'. Switches are options. 
	//	If your app requires more than one positional 
	//	argument, use the Argument() method to retrieve 
	//	them instead. 
	// 
	virtual LPCTSTR Command() const 
	{ 
 
		if (_argv[1][0] == _switchMarker) 
			return NULL; 
 
		return _argv[1]; 
	} 
 
	// 
	//	Returns the positional argument at 
	//	index. This is the opposite of the 
	//	Switch() method, which checks for a 
	//	switch marker character. Use the Command() 
	//	method if you only have one positional 
	//	argument at the beginning of the sequence. 
	//	This of course assumes that you *know* where 
	//	your positional arguments are. That's why 
	//	they're called 'positional' =) 
	// 
	virtual LPCTSTR Argument(const int index) const 
	{ 
 
		if ((index < 0) || (index >= _argc)) 
			return NULL; 
 
		if (_argv[index][0] != _switchMarker) 
			return _argv[index]; 
 
		return NULL; 
 
	} 
 
	// 
	//	Returns any positional argument that does 
	//	not begin with the specified exclusion 
	//	character. Pass '0' if your command line 
	//	does not include marked arguments. This method 
	//	helps when you only have one positional argument 
	//	but you allow the user to place it anywhere instead 
	//	of forcing it to be the first thing entered. 
	// 
	virtual LPCTSTR Argument(const TCHAR exclude) const 
	{ 
 
		for (int i = 0; i < _argc; i++) 
		{ 
			TCHAR ch = _argv[i][0]; 
 
			if ((ch != _switchMarker) && (ch != exclude)) 
				return _argv[i]; 
		} 
 
		return NULL; 
 
	} 
 
	// 
	//	Allows for enumeration of all positional 
	//	arguments. Note that this will enumerate 
	//	anything that is not a switch, including 
	//	marked arguments. The previous parameter 
	//	is normally zero, but you can pass a known 
	//	position (for example, returned from 
	//	LastSwitch()) to start enumeration there. 
	// 
	virtual LPCTSTR NextArgument(int* previous) const 
	{ 
 
		for (int i = *previous + 1; i < _argc; i++) 
		{ 
			LPCTSTR nextArg = Argument(i); 
 
			if (nextArg) 
			{ 
				*previous =  i; 
				return nextArg; 
			} 
 
		} 
 
		return NULL; 
	} 
 
	// 
	//	Attempts to find a positional argument that  
	//	matches the string you passed. This method is 
	//	not very useful because it amounts to using 
	//	arguments as switches, which is kind of dumb. 
	//	But, you can do it if you want. The only check 
	//	performed by the class is to ensure that you're 
	//	not trying to match a switch. It is also rather 
	//	slow. The comparison is done based on the class 
	//	level case setting. 
	// 
	virtual bool ArgumentExists(LPCTSTR argument) const 
	{ 
		for (int i = 1; i < _argc; i++) 
		{ 
			LPCTSTR thisArgument = Argument(i); 
 
			if (thisArgument != NULL) 
			{ 
				if (_caseSensitive) 
				{ 
					if (lstrcmp(argument, thisArgument) == 0) 
						return true; 
				} 
				else 
				{ 
					if (lstrcmpi(argument, thisArgument) == 0) 
						return true; 
				} 
 
			} 
 
		} 
 
		return false; 
 
	} 
 
	 
	// 
	//	Returns the number of times that a given switch appears 
	//	in the command line, and optionally the index of each 
	//	instance in the command array. 
	//	This method is useful when you have a switch that you 
	//	want to allow the user to repeat. For example, a utility 
	//	that processes folders recursively might accept a switch 
	//	called -exclude that has a name or wildcard that specifies 
	//	a given pattern to skip. Instead of telling the user to 
	//	enter the list of exclusions as a single switch delimited 
	//	with commas or something like that, the user enters each 
	//	option in a different instance of the same switch: 
	// 
	//	  myapp.exe -a -b -x one -x two -x three -cd 
	// 
	//	So now you have three instances of the -x switch. If you 
	//	use the normal class methods to retrieve the value of 
	//	-x you'll simply get the first one. Instead, use this 
	//	method. 
	// 
	//	Initially you'll want to call in here and pass NULL in the 
	//	indexes argument or call CountOf(). The method will return  
	//	the number of instances of the named switch it finds. Then  
	//	use that number to allocate an array of int and pass it  
	//	again. This time the method will fill it with the actual  
	//	indexes of the switch instances. 
	//	Once you have the indexes, use the ValueOf() method to get 
	//	the actual switch value at each index. 
	// 
	virtual int IndexesOf(LPCTSTR switchName, int indexes[]) const 
	{ 
		int total = 0; 
 
		for (int i = 1; i < _argc; i++) 
		{ 
			TCHAR thisSwitch[CMDLINE_MAX_SWITCH]; 
			 
			if (GetSwitch(i, thisSwitch) != 0) 
			{ 
				if (lstrcmpi(switchName, thisSwitch) == 0) 
				{ 
					if (indexes != NULL) 
						indexes[total] = i; 
 
					total++; 
 
				} 
			} 
 
		} 
 
		return total; 
 
	} 
 
	// 
	//	Returns the value of the switch at the specified 
	//	index. This method should only be called with 
	//	indexes obtained by calling IndexesOf(). Set 
	//	checkArgument to true if your command line uses 
	//	positional arguments as values instead of character  
	//	markers. 
	// 
	virtual bool ValueOf(int index, LPTSTR buffer, bool checkArgument) const 
	{ 
		LPCTSTR value = NULL; 
 
		if (index > _argc) 
			return false; 
 
		if (!checkArgument) 
		{ 
			TCHAR* valueMarker = _tcschr(_argv[index], _valueMarker); 
 
			if (valueMarker) 
				value = CharNext(valueMarker); 
		} 
		else 
		{ 
			if ( (index + 1) >= _argc) 
				return false; 
 
			// Make sure it's not a switch 
			if (_argv[index + 1][0] != _switchMarker) 
				value = _argv[index + 1]; 
		} 
 
		if (value != NULL) 
		{ 
			lstrcpyn(buffer, value, CMDLINE_MAX_VALUE); 
			return true; 
		} 
 
		return false; 
	} 
 
	virtual bool ValueOf(int index, LPTSTR buffer) const 
	{ 
		return ValueOf(index, buffer, false); 
	} 
 
	// 
	//	Same as calling IndexesOf() and passing NULL 
	//	instead of an array. 
	// 
	virtual int CountOf(LPCTSTR switchName) const 
	{ 
		return IndexesOf(switchName, NULL); 
	} 
 
 
	// 
	//	Returns the position of the last 
	//	switch in the argument array. 
	//	This is useful for situations were a 
	//	command line might include multiple 
	//	trailing positional arguments. 
	//	For example: 
	// 
	//	  myapp.exe /k /l one /g two three four 
	// 
	//	In this case, you could call LastSwitch() 
	//	to get the position of the '/g' switch 
	//	and use that to start the enumeration of 
	//	positional arguments using NextArgument() 
	//	because you're not interested in the 'one' 
	//	argument although it's also not a switch. 
	// 
	virtual int LastSwitch() const 
	{ 
		for (int i = _argc - 1; i > 1; i--) 
		{ 
			if (_argv[i][0] == _switchMarker) 
				return i; 
		} 
 
		return -1; 
	} 
 
	// 
	//	Returns the position of the first switch 
	//	in the argument array. 
	// 
	virtual int FirstSwitch() const 
	{ 
 
		for (int i = 0; i < _argc; i++) 
		{ 
			if (_argv[i][0] == _switchMarker) 
				return i; 
		} 
 
		return -1; 
	} 
 
 
	// 
	//	Returns whether or not a 'compound switch' 
	//	contains a given character. A compound switch 
	//	is something that looks like this: 
	// 
	//	  myapp.exe -abCdefg 
	// 
	//	Some applications use switches like these. Compare 
	//	that to this: 
	// 
	//	  myapp.exe -a -b -C -d -e -f -g 
	// 
	//	By definition, compound switches are case sensitive 
	//	and so the class-level setting that controls string 
	//	comparison has no effect when testing for them. 
	//	Also, a compound switch has to be the only switch in  
	//	the command line. Or at least the class assumes that  
	//	if you're asking for a compound switch it will be the  
	//	first one in the sequence array. 
	// 
	//	The method returns the index of the character that 
	//	was matched to 'ch', or zero if no match was made. If 
	//	there is no switch or the switch had a value marker, 
	//	the return is -1. 
	// 
	virtual int CompoundSwitchContains(const TCHAR identifier) const 
	{ 
		int index = FirstSwitch(); 
 
		if (index != -1) 
		{ 
			TCHAR* valueMarker = _tcschr(_argv[index], _valueMarker); 
			if (valueMarker) 
				return -1; 
 
			int length = lstrlen(_argv[index]); 
 
			if (!length) 
				return -1; 
 
			// Char at index 0 is the switch marker. 
			for (int i = 1; i < length; i++) 
			{ 
				if (_argv[index][i] == identifier) 
					return i; 
			} 
 
            return 0; 
	 
		} 
 
		return -1; 
	} 
 
	// 
	//	This is just a shorthand method to test for a single TCHAR in 
	//	a switch value. Basically frees you from writing a loop that 
	//	does the same thing. The 'value' parameter should be a switch 
	//	value previously obtained from the class. If the character is  
	//	found in the value, the return is true. 
	//	 
	//	A 'compound value' is similar to a compound switch in that it looks 
	//	like this: 
	// 
	//	  /switch:abcdefg 
	// 
	//	This is sometimes easier when you want to limit the number of 
	//	switches and don't want to use duplicates that you'd obtain with 
	//	the IndexesOf() method. Or something. Hey, I just write this stuff. 
	// 
	virtual bool CompoundValueContains(LPCTSTR value, TCHAR identifier) const 
	{ 
		 
		for (int i = 0; i < lstrlen(value); i++) 
		{ 
			if (value[i] == identifier) 
				return true; 
		} 
 
		return false; 
 
	} 
 
	// 
	//	Returns a 'marked' positional argument. 
	//	An example of this are applications like command line 
	//	compression utilities or compilers that accept a  
	//	parameter prefixed with '@' which points to a  
	//	response file from which further commands are read. 
	//	Ideally there should be only one marked argument 
	//	in a command line, but you can have more than one 
	//	as long as you use different marker characters. And 
	//	of course the marker should be different from whatever 
	//	is being used as the switch delimiter. 
	// 
	virtual LPCTSTR MarkedArgument(const TCHAR identifier) const 
	{ 
 
		LPCTSTR arg = NULL; 
 
		for (int i = 1; i < _argc; i++) 
		{ 
 
			if (_argv[i][0] == identifier) 
			{ 
				// Don't include the marker itself. 
				arg = CharNext(_argv[i]); 
				break; 
			} 
 
		} 
 
		return arg; 
	} 
 
 
	// 
	//	Returns the argument after the specified 
	//	switch. This method can be used to avoid 
	//	using a value marker (though *something* 
	//	has to be passed to the constructors) and 
	//	instead use spaces to separate values from 
	//	switches. For example: 
	//	 
	//	  myapp.exe -a arg -b -c 
	// 
	//	In this case, the switch delimiter was 
	//	set to '-'. Then do something like: 
	// 
	//	  LPCTSTR myValue = ArgumentAfter(_T("a")); 
	// 
	//	to retrieve the 'arg' positional parameter. 
	//	 
	//	Basically this lets you use the class to  
	//	parse 'classic' command lines that don't use 
	//	a value delimiter. Not my thing, but hey. 
	// 
	//	The second overload copies the value of the 
	//	argument (if found) to a buffer. Note that there 
	//	are no overloads for different types. 
	// 
	virtual LPCTSTR ArgumentAfter(LPCTSTR switchName) const 
	{ 
 
		int index = FindSwitch(switchName); 
		LPCTSTR arg = NULL; 
 
		if (index != -1) 
			arg = Argument(index + 1); 
 
		return arg; 
 
	} 
 
	virtual bool ArgumentAfter(LPCTSTR switchName, LPTSTR buffer) const 
	{ 
 
		LPCTSTR arg = ArgumentAfter(switchName); 
 
		if (arg) 
		{ 
			lstrcpyn(buffer, arg, CMDLINE_MAX_ARGUMENT); 
			return true; 
		} 
 
		return false; 
 
	} 
 
 
	// 
	//	Return the name of the switch at index. 
	//	Before returning, a check is made to 
	//	ensure that the element at is indeed a switch, 
	//	as opposed to a positional or marked argument. 
	//	In general you should not retrieve swtiches 
	//	by index, but by name. If the switch has a 
	//	value it will not be returned along with the 
	//	switch itself.  
	// 
	virtual bool Switch(const int index, LPTSTR buffer) const 
	{ 
		if ((index < 0) || (index >= _argc)) 
			return NULL; 
 
		return (GetSwitch(index, buffer) != 0); 
 
	} 
 
	// 
	//	Returns whatever is at _argv[n]. Unlike 
	//	the Switch() and Argument() methods, this 
	//	does no checking. Not useful since this 
	//	amounts to using the class directly as 
	//	a glorified array. 
	// 
	virtual LPCTSTR operator [] (const int index) const 
	{ 
		if ((index < 0) || (index >= _argc)) 
			return NULL; 
 
		return _argv[index]; 
	} 
 
	// 
	//	Returns true if a given switch exists. Note 
	//	that switchName should be the _name_ of the 
	//	switch without the actual switch delimiter. 
	// 
	//	The second override allows an application to 
	//	support short and long versions of switches. 
	//	For example, where '/v' and '/verb' should be 
	//	interpreted the same way. Simply pass an array  
	//	of possible names for a switch (and the count of 
	//	items in the array). The class will return the 
	//	index of the switches array that matched a switch  
	//	in the argument array. If you pass a valid buffer 
	//	then the matched switch name gets copied to it; 
	//	otherwise pass NULL if you're not interested in 
	//	having the class copy the name and you're going to 
	//	use the returned index into your own array. 
    // 
	//	From then on you have the actual switch name, 
	//	which you can use to call the other functions,  
    //  like SwitchHasValue(). If there is no match, the  
    //  return is NULL and you know that neither version 
    //  of the argument was there. Although the method  
    //  signature lets you pass an array of any size, 
    //  obviously the ideal is to have only two forms 
    //  of the same switch. Anything else will probably 
	//	be confusing to people who use your app. 
	// 
	//	Finally note that the 'switches' argument is const, 
	//	so either pass a const ref from your side or use a  
	//	const_cast: 
	// 
	//   const TCHAR* args[] = {_T("v"), _T("verb")}; 
	// 
	virtual bool SwitchExists(LPCTSTR switchName) const 
	{ 
		return (FindSwitch(switchName) != -1); 
	} 
 
	virtual int SwitchExists(const TCHAR** switches, const int count, LPTSTR buffer) const 
	{ 
		for (int i = 0; i < count; i++) 
		{ 
			int index = FindSwitch(switches[i], buffer); 
			if (index != -1) 
				return i; 
 
		} 
		 
		return -1; 
	} 
 
 
	// 
	//	Returns true if the switch exists, and has a value. 
	//	The second override can be used when positional 
	//	arguments are being used instead of values delimited with 
	//	markers. So while the first override checks for something 
	//	like this: 
	// 
	//		/f:blah 
	// 
	//	the second one checks for: 
	// 
	//		/f blah 
	// 
	//	assuming the 'checkArgument' parameter is true. This is 
    //  the same as calling ArgumentAfter(switchName). 
	// 
	virtual bool SwitchHasValue(LPCTSTR switchName) const 
	{ 
 
		int index = FindSwitch(switchName); 
		 
		if (index != -1) 
		{ 
			return GetValue(index, NULL, true); 
		} 
 
		return false; 
 
	} 
 
	virtual bool SwitchHasValue(LPCTSTR switchName, bool checkArgument) const 
	{ 
 
		if (!checkArgument) 
			return SwitchHasValue(switchName); 
 
		return (ArgumentAfter(switchName) != NULL); 
	} 
 
 
	//  
	//	These methods return the value of the specified switch. 
	//	There are three main overloads: TCHAR*, int and double. 
	//	Each of these have an additional overload that accepts a 
	//	default value that will be returned instead if the value 
	//	didn't exist. Keep in mind that when the default is returned 
	//	the methods will *still* return false. This lets you determine 
	//	if the default you passed is being returned or not. 
	// 
    //  For the TCHAR* overload, value is assumed to be CMDLINE_MAX_VALUE 
    //  in length. 
	// 
	virtual bool SwitchValue(LPCTSTR switchName, LPTSTR value) const 
	{ 
		int index = FindSwitch(switchName); 
		 
		if (index != -1) 
		{ 
			return GetValue(index, value, false); 
		} 
 
		return false; 
	} 
 
	virtual bool SwitchValue(LPCTSTR switchName, LPTSTR value, LPCTSTR defaultValue) const 
	{ 
 
		bool result = SwitchValue(switchName, value); 
 
		if (!result) 
			lstrcpy(value, defaultValue); 
		 
		return result; 
 
	} 
 
	virtual bool SwitchValue(LPCTSTR switchName, int* value) const 
	{ 
 
		TCHAR buffer[32]; 
 
		if (SwitchValue(switchName, buffer)) 
		{		 
			*value = _ttoi(buffer); 
			return true; 
		} 
 
		return false; 
	} 
 
	virtual bool SwitchValue(LPCTSTR switchName, int* value, const int defaultValue) const 
	{ 
		bool result = SwitchValue(switchName, value); 
 
		if (!result) 
			*value = defaultValue; 
		 
		return result; 
	} 
 
	virtual bool SwitchValue(LPCTSTR switchName, double* value) const 
	{ 
 
		TCHAR buffer[32]; 
 
		if (SwitchValue(switchName, buffer)) 
		{ 
//	There is no generic mapping for atof() in the CRT 
//	released with VC++ 6 (as far as I know). I.e., _tstof() is 
//	just not there AFAICT. Weird, eh. 
#if (_MSC_VER >= 1300)			// VC.NET 7.x is release 13 of the compiler. 
			*value = _tstof(buffer); 
#else 
			*value = _tcstod(buffer, NULL); 
#endif							//(_MSC_VER >= 1300) 
			return true; 
		} 
 
		return false; 
	} 
 
	virtual bool SwitchValue(LPCTSTR switchName, double* value, const double defaultValue) const 
	{ 
		bool result = SwitchValue(switchName, value); 
 
		if (!result) 
			*value = defaultValue; 
		 
		return result; 
	} 
 
	// 
	//	Determines if a switch exists and actually has a value, and 
	//	then compares it to the passed value. If they match, the 
    //  return is true. 
    // 
    //  The string version has one overload that specifies if the 
    //  comparison is case-sensitive. This is different from the 
    //  class-level case setting. If the argument is omitted the 
    //  default is to compare the values without regard to case. 
	// 
	//	There is an additional overload for int values, but not one 
	//	for double. Yes, there's an overload of SwitchValue() that 
	//	that accepts a double, but I don't want to get into 
	//	comparing floating point values. That's up to you =) Since 
	//	it's unlikely that heavy floating point support will be used 
	//	in a command line (i.e., two or three decimal positions should  
	//	be enough), perhaps the easiest way is to use *printf() to 
	//	compare them as strings instead. 
	// 
	virtual bool SwitchValueIs(LPCTSTR switchName, LPCTSTR value, const bool caseSensitive) const 
	{ 
		TCHAR buffer[CMDLINE_MAX_VALUE]; 
		int index = FindSwitch(switchName); 
		 
		if ((index != -1) && SwitchHasValue(switchName)) 
		{ 
			if (GetValue(index, buffer, false)) 
			{ 
                // Note that the class-level case setting does not apply here. 
				if (caseSensitive) 
					return (lstrcmp(buffer, value) == 0); 
				else 
					return (lstrcmpi(buffer, value) == 0); 
			} 
		} 
 
		return false; 
	} 
 
    virtual bool SwitchValueIs(LPCTSTR switchName, LPCTSTR value) const 
	{ 
        return SwitchValueIs(switchName, value, false); 
	} 
 
	virtual bool SwitchValueIs(LPCTSTR switchName, const int value) const 
	{ 
		int actualValue = 0; 
		int index = FindSwitch(switchName); 
		 
		if ((index != -1) && SwitchHasValue(switchName)) 
		{ 
			if (SwitchValue(switchName, &actualValue)) 
			{ 
				return (value == actualValue); 
			} 
		} 
 
		return false; 
	} 
 
	// 
	//	Returns the number of positional arguments 
	//	(those that don't start with a switch marker) 
	//	in the command line. The count does not include 
	//	the argument at position 0, which is either the 
	//	path to the executable or a dummy placeholder. 
	//	Note that this will also include marked positional 
	//	arguments, if they are there. 
	// 
	virtual int ArgumentCount() const 
	{ 
		int count = 0; 
 
		// Again, loop starts at one. 
		for (int i = 1; i < _argc; i++) 
		{ 
 
			if (_argv[i][0] != _switchMarker) 
				count++; 
		} 
 
		return count; 
	} 
 
 
	// 
	//	Returns the number of switches in the command 
    //  line. The count does not include the element 
	//	at position 0, which is either the path to the 
	//	executable or a dummy placeholder. 
	// 
	virtual int SwitchCount() const 
	{ 
		int count = 0; 
 
		// Again, loop starts at one. 
		for (int i = 1; i < _argc; i++) 
		{ 
 
			if (_argv[i][0] == _switchMarker) 
				count++; 
		} 
 
		return count; 
	} 
 
 
	// 
	//	Shorthand method for parsing individual commands. 
	//	This method is handy when processing arguments read from 
	//	a response file, for example. It prevents you from having 
	//	to create an instance of the class every time you need to 
	//	parse another command. 
	// 
	//	This method operates under the assumption that whatever 
	//	you are passing contains a single switch and, optionally, 
	//	a value. Multiple switches will not be parsed, and in fact 
	//	will probably cause weird behavior. If you need that then 
	//	just use an instance of the class. 
	// 
	//	Pass the raw string in the 'argument' parameter and  
	//	properly allocated buffers in the in the 'switchName' and 
	//	'value' parameters. If the string can be parsed as a  
	//	switch, the name is copied to 'switchName'. If the switch 
	//	has a value, it is copied to the 'value' parameter and the 
	//	'hasValue' parameter is set to true. Note that this does not 
	//	differentiate between delimited and positional values, which 
	//	means that you _must_ initialize the class with a value marker 
	//	set to the space character (0x20) if you're passing 
	//	commands that have values otherwise retrieved using the 
	//	ArgumentAfter() method. IOW, if your commands look like this: 
	// 
	//	  -switch value 
	// 
	//	then the switch marker must be set to 0x20. When using the 
	//	class to parse automatically using the OS this is not 
	//	necessary and you can just initialize the marker with something 
	//	else because, again, you get those with ArgumentAfter(). This is 
	//	due to how CommandLineToArgvW() works - it uses spaces as the  
	//	delimiter boundary to create the _argv array. I hope that makes 
	//	sense. 
	// 
	//	If you're not interested in the switch value being returned  
	//	simply pass a NULL pointer. The test will still be performed  
	//	and the 'hasValue' argument will be set to true (if a value  
	//	is there) but the value won't be copied. 
	// 
	//	The method will return false only if the 'argument' parameter 
	//	is NULL or is less than or equal to 1 character in length  
	//	(obviously a switch has to be at least two chars in length, 
	//	counting the marker itself), or if the first character is not 
	//	equal to the defined switch marker. 
	// 
	//	If you're parsing a response file and you're expecting positional 
	//	arguments (non-switches) to be there you can pass them here and 
	//	then see if the return is false. If the string itself is longer 
	//	than 1 character that means said string is a valid positional 
	//	argument. 
	//	 
	//	Note that there is no overload for int or double values. It's up 
	//	to your code to convert them if necessary based on the name of 
	//	the switch and its expected value. Always check the 'hasValue' 
	//	parameter to see if something was actually copied to the buffer. 
	// 
	bool Parse(LPTSTR argument,  
			   LPTSTR switchName,  
			   bool& hasValue,  
			   LPTSTR value) const 
	{ 
 
		if (!argument || lstrlen(argument) == 1) 
			return false; 
 
		if (argument[0] != _switchMarker) 
			return false; 
 
		TCHAR nameBuffer[CMDLINE_MAX_SWITCH]; 
		int chars = GetSwitch(argument, nameBuffer); 
 
		lstrcpyn(switchName, nameBuffer, chars + 1); 
 
		hasValue = false; 
 
		if (GetValue(argument, value, (value == NULL), true)) 
		{ 
			hasValue = true; 
		} 
 
		return true; 
	} 
 
 
protected: 
 
	// 
	//	Finds a switch in the argument array and 
	//	returns its index. If the argument can't 
	//	be found, the return is -1. 
	//	This is pretty much the meat of the class. 
	// 
	virtual int FindSwitch(LPCTSTR switchName, LPTSTR buffer = NULL) const 
	{ 
	 
 
		// Note the loop starts at 1, not zero. 
		for (int index = 1; index < _argc; index++) 
		{ 
 
			// Does this have a switch marker to begin with? 
			if (_argv[index][0] != _switchMarker) 
				continue; 
 
			// Obviously no single switch should exceed CMDLINE_MAX_SWITCH chars. 
			// Actually anything over 8 chars is an abomination. 
			TCHAR pzTemp[CMDLINE_MAX_SWITCH]; 
			int charCount = 0; 
 
			charCount = GetSwitch(index, pzTemp); 
 
			// Not the same length, don't bother. 
			if (charCount != lstrlen(switchName)) 
				continue; 
 
			bool found = false; 
 
			if (_caseSensitive) 
			{ 
				found = (_tcscmp(pzTemp, switchName) == 0); 
			} 
			else 
			{ 
				found = (_tcsicmp(pzTemp, switchName) == 0); 
			} 
 
			if (found) 
			{ 
				if (buffer != NULL) 
					lstrcpy(buffer, pzTemp); 
				 
				return index; 
			} 
 
		} 
 
		return -1; 
 
	} 
 
 
	// 
	//	Extracts the switch at index, removing the switch marker 
	//	itself and the value, if present. Returns the number of 
	//	characters copied to the buffer, which is assumed to 
	//	be CMDLINE_MAX_SWITCH chars in length. 
	// 
	virtual int GetSwitch(const int index, TCHAR* buffer) const 
	{ 
		return GetSwitch(_argv[index], buffer); 
	} 
 
	int GetSwitch(/* const */ TCHAR* item, TCHAR* buffer) const 
	{ 
 
		int charCount = 0; 
 
		// Does this have a switch marker to begin with? 
		if (item[0] != _switchMarker) 
			return 0; 
 
		TCHAR* valueMarker = NULL; 
 
		// See if it has a value separator. 
		// This should be enough to convince you not to use letters 
		// as switch or value delimiters (if nothing else did). 
		// We don't bother testing for the marker if it was initialized 
		// to zero. 
		if (_valueMarker != 0) 
			valueMarker = _tcschr(item, _valueMarker); 
 
		// In both cases below we substract one because we don't 
		// want to compare the argument + the marker; only the 
		// argument itself. 
		// In the case of a switch with no value marker, we just use 
		// the length of the argument (in the list, not the passed 
		// one). 
		// And in the case of a switch that has a value marker, 
		// we simply substract the location of the marker from 
		// the address of the argument. 
		if (valueMarker != NULL) 
		{ 
			charCount = (valueMarker - item) - 1; 
		} 
		else 
		{ 
			charCount = lstrlen(item) - 1; 
		} 
 
		if (charCount > 0) 
			lstrcpyn(buffer, CharNext(item), charCount + 1); 
 
		return charCount; 
 
	} 
 
	// 
	//	Retrieves the value of the switch at index. If the switch has no value 
	//	or does not include a value marker, the return is false and buffer is undefined.  
	//	If test is true, the method returns true if there's a value, but does not 
	//	actually copy it to the buffer. The buffer is assumed to be big enough. 
	// 
	virtual bool GetValue(int index, LPTSTR buffer, const bool test) const 
	{ 
 
		if (index != -1) 
			return GetValue(_argv[index], buffer, test, false); 
 
		return false; 
	} 
 
	// 
	//	If 'custom' is set to true the method will remove quotes from 
	//	the value. This is necessary because we want to support quotes 
	//	when the Parse() method is called, but we also want to support 
	//	double-quoted arguments when the OS is doing the parsing. 
	// 
	bool GetValue(/* const */ TCHAR* item, LPTSTR buffer, const bool test, const bool custom) const 
	{ 
 
		if (item) 
		{ 
			int length = lstrlen(item); 
			int chars = 0; 
 
			if (_valueMarker == 0x0) 
				return false; 
 
			TCHAR* valueMarker = _tcschr(item, _valueMarker); 
 
			if (valueMarker) 
			{ 
				if (!test) 
				{ 
					TCHAR* ptr = CharNext(valueMarker); 
					chars = lstrlen(ptr); 
 
					if (custom) 
					{ 
						TCHAR* szQuote = _tcschr(ptr, 0x22); 
 
						if (szQuote) 
						{ 
							ptr = CharNext(szQuote); 
							chars -= 2; 
						} 
					} 
 
					 
					lstrcpyn(buffer, ptr, chars + 1); 
				} 
				 
				return true; 
			} 
 
		} 
 
		return false; 
 
	} 
 
private: 
 
	// 
	//	Called from the custom command line constructors 
	// 
	void InitializeFromCommandLine(LPCTSTR commandLine,  
								   TCHAR switchMarker,  
								   TCHAR valueMarker,  
								   bool custom,  
								   bool caseSensitive) 
	{ 
		 
		 
		_caseSensitive = caseSensitive; 
 
		_switchMarker = switchMarker; 
		_valueMarker = valueMarker; 
 
#if defined (UNICODE) && defined (_WIN32_WINNT) 
 
		_argvOwned = true; 
 
		TCHAR* command = NULL; 
 
		if (custom) 
		{ 
			command = new TCHAR[10 + lstrlen(commandLine)]; 
			 
			lstrcpy(command, _T("_DUMMY_ "));			// Whatever 
			lstrcat(command, commandLine); 
 
			_argv = CommandLineToArgvW(command, &_argc); 
			 
			delete[] command; 
		} 
		else 
		{ 
			_argv = CommandLineToArgvW(commandLine, &_argc); 
		} 
 
#else 
		_argvOwned = false; 
		 
		_argv = __argv; 
		_argc = __argc; 
 
#endif		 
 
	} 
 
 
 
public: 
 
#ifdef DEBUG 
 
    // 
    //  Helper. 
    // 
	virtual void _Dump() 
	{ 
		for (int i = 0; i < _argc; i++) 
			_tprintf(_T("%i - %s\n"), i, _argv[i]); 
	} 
 
 
#endif 
 
protected: 
 
	int _argc;					// Number of arguments in the argument array 
	TCHAR** _argv;				// Argument array 
	TCHAR _switchMarker;		// TCHAR to use as switch delimiter 
	TCHAR _valueMarker;			// TCHAR to use as value delimiter 
	bool _caseSensitive;		// True if this instance is case sensitive, otherwise false. 
    bool _argvOwned;			// Flag that tells us we need to free _argv because we got it from CommandLineToArgvW 
 
}; 
 
#endif          // #ifndef _CMDLINE_INC