Alice

Alice Long optIons C++ Extractor is a command line parser for use with C++. Alice makes it easy to fetch a command line options, without the need for converting strings to the desired type. Alice also provides automatic help text generation, as well as the ability to export the command line in JSON format.

Obtaining Alice

The source for the latest Alice can be obtained by cloning the git repository

git clone https://github.com/milasudril/alice

To compile it, Maike is required, as well as a C++-14 complient compiler. The library can be installed by using the supplied install script:

maike
./install.sh --prefix=/home/bob

or if root

maike
sudo ./install.sh

Since /usr/local is the default prefix, Alice will be installed there.

Using Alice

An application that uses Alice needs to link to libalice. Using Maike, the "Hello, World" application looks like

//@	{
//@	"targets":
//@		[{
//@		 "name":"hello","type":"application"
//@		,"dependencies":[{"ref":"alice","rel":"external"}]
//@		}]
//@	}

#include <alice/alice.hpp>

ALICE_OPTION_DESCRIPTOR(OptionDescriptor
	,{"Category","option-name","Option description","string",Alice::Option::Multiplicity::ZERO_OR_ONE});

int main(int argc,char** argv)
	{
	try
		{
		Alice::CommandLine<OptionDescriptor> cmdline(argc,argv);

	//	Use the command line object. See test.cpp for more info.

		cmdline.help(1);
		}
	catch(const Alice::ErrorMessage& msg)
		{
		fprintf(stderr,"Command line error: %s\n",msg.data);
		return -1;
		}

	return 0;
	}

Since Alice requires C++14, additional options may be needed to the compiler. When using Maike, set the field cxxversion_min in the project configuration file to a value greater than or equal to 201402 to ensure that C++14 features are enabled.

The file test.cpp contains a minimal example demonstrating Alice's features. Since Maike will store all targets in the __targets directory, it can be run by executing

__targets/test

from the Alice source directory. The command

__targets/test --help

shows a description of the command line.

Creating a type alias

Alice uses quite technical names for data types. While this works well for generating the placeholder help text for the test application, it is probably not what an end user expects to see. If a built-in type is used to represent the value of a parameter, but its name is inappropriate, it is possible to define a type alias by inheriting from the corresponding version of MakeType.

namespace Alice
	{
	template<>
	struct MakeType<Stringkey("length")>:public MakeType<Stringkey("double")>
		{};
	}

Then, it is possible to use length instead of double in the option descriptor. If a length needs another explanation than a double, the description can be overrided:

namespace Alice
	{
	template<>
	struct MakeType<Stringkey("length")>:public MakeType<Stringkey("double")>
		{
		static constexpr const char* descriptionGet() noexcept
			{return "The length measured in meters";}
		};
	}

Defining custom types

Alice can also be extended by defining custom types. For example, there might be an option that accepts Hatter objects.

struct Hatter
	{
	std::string name;
	double madness;
	};

To add the Hatter type, first specialize the MakeType struct as above:

namespace Alice
	{
	template<>
	struct MakeType<Stringkey("hatter")>
		{
		typedef Hatter Type;
		static constexpr const char* descriptionGet() noexcept
			{
			return "A Hatter is entered as a pair `name,madness` where "
				"name is a string, and madness is a value greater than or equal to zero.";
			}
		};
	}

If the print method is ever called on the command line object, add a specialization of `Alice::print`

namespace Alice
	{
	template<>
	void print<Hatter>(const Hatter& hatter,FILE* dest)
		{
		fprintf(dest,"{\"name\":");
		print(hatter.name,dest);
		fprintf(dest,",\"madness\":");
		print(hatter.madness,dest);
		fprintf(dest,"}\n");
		}
	}

Finally, implement a parser, that converts a std::string to a Hatter, this takes more effort (see test.cpp), but below is a stub, that can be used as a starting point:

namespace Alice
	{
	template<class ErrorHandler>
	struct MakeValue<Hatter,ErrorHandler>
		{
		static Hatter make_value(const std::string& str);
		};

	template<class ErrorHandler>
	Hatter MakeValue<Hatter,ErrorHandler>::make_value(const std::string& str)
		{
		Hatter ret;
	//	Convert `str` into a Hatter somehow...
	
		return std::move(ret);
		}
	}