- now works properly (still debugging --help)

Thu, 24 Jul 2014 16:54:45 +0300

author
Teemu Piippo <crimsondusk64@gmail.com>
date
Thu, 24 Jul 2014 16:54:45 +0300
changeset 141
68d60e2cfa76
parent 140
04a6eb68f226
child 142
1f5518dd8146

- now works properly (still debugging --help)

CMakeLists.txt file | annotate | diff | comparison | revisions
src/commandline.cpp file | annotate | diff | comparison | revisions
src/commandline.h file | annotate | diff | comparison | revisions
src/format.cpp file | annotate | diff | comparison | revisions
src/format.h file | annotate | diff | comparison | revisions
src/main.cpp file | annotate | diff | comparison | revisions
src/main.h file | annotate | diff | comparison | revisions
src/parser.cpp file | annotate | diff | comparison | revisions
src/parser.h file | annotate | diff | comparison | revisions
src/stringClass.cpp file | annotate | diff | comparison | revisions
src/stringClass.h file | annotate | diff | comparison | revisions
--- a/CMakeLists.txt	Tue Jul 22 19:22:31 2014 +0300
+++ b/CMakeLists.txt	Thu Jul 24 16:54:45 2014 +0300
@@ -59,7 +59,7 @@
 include_directories (${CMAKE_SOURCE_DIR}/src)
 
 if (NOT MSVC)
-	set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -W -Wall -Og")
+	set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -W -Wall")
 
 	if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug" OR "${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo")
 		set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDEBUG")
--- a/src/commandline.cpp	Tue Jul 22 19:22:31 2014 +0300
+++ b/src/commandline.cpp	Thu Jul 24 16:54:45 2014 +0300
@@ -38,20 +38,14 @@
 
 // _________________________________________________________________________________________________
 //
-void CommandLine::addOption (CommandLineOption* option)
-{
-	_options << option;
-}
-
-// _________________________________________________________________________________________________
-//
-StringList CommandLine::process (int argc, char* argv[])
+StringList CommandLine::process (int const argc, char* argv[])
 {
 	StringList args;
+	int const trueargc = argc;
 
-	for (int argn = 1; argn < argc; ++argn)
+	for (int argn = 1; argn < trueargc; ++argn)
 	{
-		String arg (argv[argn]);
+		String const arg (argv[argn]);
 
 		if (arg == "--")
 		{
@@ -62,14 +56,14 @@
 			break;
 		}
 
-		if (arg[0] != '-')
+		if (arg[0] != '-' or arg[1] == '\0')
 		{
 			// non-option argument - pass to result
 			args << arg;
 			continue;
 		}
 
-		if (arg[1] != '-')
+		if (arg[1] != '-' and arg[1] != '\0')
 		{
 			// short-form options
 			for (int i = 1; i < arg.length(); ++i)
@@ -80,9 +74,7 @@
 				});
 
 				if (not optionptr)
-				{
 					error ("unknown option -%1", arg[i]);
-				}
 
 				CommandLineOption* option = *optionptr;
 
@@ -90,20 +82,21 @@
 				{
 					// Bool options need no parameters
 					option->handleValue ("");
-					continue;
 				}
-
-				// Ensure we got a valid parameter coming up
-				if (argn == argc - 1)
-					error ("option -%1 requires a parameter", option->describe());
+				else
+				{
+					// Ensure we got a valid parameter coming up
+					if (argn == argc - 1)
+						error ("option -%1 requires a parameter", option->describe());
 
-				if (i != arg.length() - 1)
-				{
-					error ("option %1 requires a parameter but has option -%2 stacked on",
+					if (i != arg.length() - 1)
+					{
+						error ("option %1 requires a parameter but has option -%2 stacked on",
 							option->describe(), arg[i + 1]);
-				}
+					}
 
-				option->handleValue (argv[++argn]);
+					option->handleValue (argv[++argn]);
+				}
 			}
 		}
 		else
@@ -134,7 +127,7 @@
 
 			if ((*optionptr)->isOfType<bool>() and not value.isEmpty())
 				error ("option %1 does not take a value", (*optionptr)->describe());
-
+ 
 			(*optionptr)->handleValue (value);
 		}
 	}
@@ -144,28 +137,93 @@
 
 // _________________________________________________________________________________________________
 //
-void CommandLineOption::handleValue (String const& value)
+String CommandLine::describeOptions() const
+{
+	StringList lines;
+
+	for (CommandLineOption* option : _options)
+	{
+		String line ("  ");
+
+		if (option->shortform() != '\0')
+			line += String ({'-', option->shortform(), '\0'});
+		else
+			line += "  ";
+
+		line += "  ";
+
+		if (not option->longform().isEmpty())
+		{
+			line += "--" + option->longform();
+			String description (option->describeArgument());
+
+			if (not description.isEmpty())
+				line += "=" + description;
+		}
+
+		lines << line;
+	}
+
+	int maxlength (0);
+
+	for (String& line : lines)
+		maxlength = max (maxlength, line.length());
+
+	maxlength += 2;
+	ASSERT_EQ (lines.size(), _options.size());
+
+	for (int i = 0; i < lines.size(); ++i)
+	{
+		while (lines[i].length() < maxlength)
+			lines[i] += " ";
+
+		lines[i] += _options[i]->description();
+	}
+
+	StringList extralines;
+
+	for (CommandLineOption* option : _options)
+	{
+		String extradata = option->describeExtra();
+
+		if (not extradata.isEmpty())
+		{
+			if (extralines.isEmpty())
+				extralines << "";
+
+			extralines << extradata;
+		}
+	}
+
+	lines.merge (extralines);
+	String result (lines.join ("\n"));
+	return result;
+}
+
+// _________________________________________________________________________________________________
+//
+void CommandLineOption::handleValue (const String& a)
 {
 	if (isOfType<bool>())
 	{
-		*reinterpret_cast<bool*> (pointer()) = value;
+		pointer().setValue (true);
 	}
 	elif (isOfType<int>())
 	{
 		bool ok;
-		*reinterpret_cast<int*> (pointer()) = value.toLong (&ok);
+		pointer().setValue (a.toLong (&ok));
 
 		if (not ok)
 			error ("bad integral value passed to %1", describe());
 	}
 	elif (isOfType<String>())
 	{
-		*reinterpret_cast<String*> (pointer()) = value;
+		pointer().setValue (a);
 	}
 	elif (isOfType<double>())
 	{
 		bool ok;
-		*reinterpret_cast<double*> (pointer()) = value.toDouble (&ok);
+		pointer().setValue (a.toDouble (&ok));
 
 		if (not ok)
 			error ("bad floating-point value passed to %1", describe());
@@ -175,3 +233,17 @@
 		error ("OMGWTFBBQ: %1 has an invalid type index", describe());
 	}
 }
+
+// _________________________________________________________________________________________________
+//
+String CommandLineOption::describeArgument() const
+{
+	if (isOfType<int>())
+		return "INTEGER";
+	elif (isOfType<String>())
+		return "STRING";
+	elif (isOfType<double>())
+		return "FLOAT";
+
+	return "";
+}
--- a/src/commandline.h	Tue Jul 22 19:22:31 2014 +0300
+++ b/src/commandline.h	Thu Jul 24 16:54:45 2014 +0300
@@ -41,7 +41,30 @@
 	String _longform;
 	String _description;
 	std::type_info const* _type;
-	void* _ptr;
+
+	union PointerUnion
+	{
+		int* asInt;
+		long* asLong;
+		char* asChar;
+		bool* asBool;
+		String* asString;
+		double* asDouble;
+
+		PointerUnion (int* a) : asInt (a) {}
+		PointerUnion (bool* a) : asBool (a) {}
+		PointerUnion (String* a) : asString (a) {}
+		PointerUnion (double* a) : asDouble (a) {}
+		PointerUnion (long* a) : asLong (a) {}
+		PointerUnion (char* a) : asChar (a) {}
+
+		void setValue (int const& a) { *asInt = a; }
+		void setValue (bool const& a) { *asBool = a; }
+		void setValue (String const& a) { *asString = a; }
+		void setValue (double const& a) { *asDouble = a; }
+		void setValue (long const& a) { *asLong = a; }
+		void setValue (char const& a) { *asChar = a; }
+	} _ptr;
 
 public:
 	template<typename T>
@@ -87,7 +110,7 @@
 		return _shortform;
 	}
 
-	inline void* pointer() const
+	inline PointerUnion& pointer()
 	{
 		return _ptr;
 	}
@@ -99,18 +122,26 @@
 	}
 
 	virtual void handleValue (String const& a);
+	virtual String describeArgument() const;
+	virtual String describeExtra() const { return ""; }
 };
 
+// _________________________________________________________________________________________________
+//
 template<typename T>
 class EnumeratedCommandLineOption : public CommandLineOption
 {
 	StringList _values;
 
 public:
+	using ValueType = typename std::underlying_type<T>::type;
+
 	EnumeratedCommandLineOption (T& data, char shortform, const char* longform,
 		const char* description) :
-		CommandLineOption (data, shortform, longform, description)
+		CommandLineOption (reinterpret_cast<ValueType&> (data), shortform,
+			longform, description)
 	{
+		// Store values
 		for (int i = 0; i < int (T::NumValues); ++i)
 		{
 			String value = MakeFormatArgument (T (i)).toLowercase();
@@ -127,17 +158,32 @@
 	{
 		String const lowvalue (value.toLowercase());
 
-		for (int i = 0; i < _values.size(); ++i)
+		for (ValueType i = 0; i < _values.size(); ++i)
 		{
-			if (_values[i].toLowercase() == lowvalue)
+			if (_values[i] == lowvalue)
 			{
-				*reinterpret_cast<T*> (pointer()) = T (i);
+				pointer().setValue (i);
 				return;
 			}
 		}
 
 		error ("bad value passed to %1 (%2), valid values are: %3", describe(), value, _values);
 	}
+
+	virtual String describeArgument() const
+	{
+		return "ENUM";
+	}
+
+	StringList const& validValues() const
+	{
+		return _values;
+	}
+
+	virtual String describeExtra() const
+	{
+		return format ("Valid values for %1: %2", describe(), validValues());
+	}
 };
 
 // _________________________________________________________________________________________________
@@ -153,13 +199,13 @@
 	template<typename Enum>
 	void addEnumeratedOption (Enum& e, char shortform, const char* longform,
 		const char* description);
-	void addOption (CommandLineOption* option);
-	StringList process (int argc, char* argv[]);
+	String describeOptions() const;
+	StringList process (const int argc, char* argv[]);
 
 	template<typename... Args>
-	void addOption (Args... args)
+	void addOption (Args&&... args)
 	{
-		addOption (new CommandLineOption (args...));
+		_options << new CommandLineOption (args...);
 	}
 };
 
@@ -169,8 +215,7 @@
 void CommandLine::addEnumeratedOption (Enum& e, char shortform, const char* longform,
 	const char* description)
 {
-	static_assert(std::is_enum<Enum>::value, "addEnumeratedOption requires a named enumerator");
-	auto enumoption = new EnumeratedCommandLineOption<Enum> (e, shortform, longform,
+	static_assert(std::is_enum<Enum>::value, "addEnumeratedOption requires a named enumerator"); 
+	_options << new EnumeratedCommandLineOption<Enum> (e, shortform, longform,
 		description);
-	addOption (static_cast<CommandLineOption*> (enumoption));
 }
--- a/src/format.cpp	Tue Jul 22 19:22:31 2014 +0300
+++ b/src/format.cpp	Thu Jul 24 16:54:45 2014 +0300
@@ -86,7 +86,12 @@
 
 		int i = fmt[pos + ofs]  - '0';
 
-		if (i > static_cast<signed> (args.size()))
+#ifdef DEBUG
+		if (i == 0)
+			formatError (fmtstr, "%0 in format string", pos);
+#endif
+
+		if (i > int (args.size()))
 			formatError (fmtstr, String ("Format argument #") + i + " used but not defined.", pos);
 
 		String replacement = args[i - 1];
--- a/src/format.h	Tue Jul 22 19:22:31 2014 +0300
+++ b/src/format.h	Thu Jul 24 16:54:45 2014 +0300
@@ -53,6 +53,11 @@
 	return String::fromNumber (a);
 }
 
+inline String MakeFormatArgument (double a)
+{
+	return String::fromNumber (a);
+}
+
 inline String MakeFormatArgument (size_t a)
 {
 	return String::fromNumber (long (a));
--- a/src/main.cpp	Tue Jul 22 19:22:31 2014 +0300
+++ b/src/main.cpp	Thu Jul 24 16:54:45 2014 +0300
@@ -47,16 +47,31 @@
 {
 	try
 	{
-		Verbosity verboselevel = Verbosity::None;
-		bool listcommands = false;
+		Verbosity verboselevel (Verbosity::None);
+		bool listcommands (false);
+		bool sendhelp (false);
+		bool test (true);
 
 		CommandLine cmdline;
-		cmdline.addOption (listcommands, 'l', "listfunctions",
-			"List available function signatures and exit");
-		cmdline.addEnumeratedOption (verboselevel, 'V', "verbose",
-			"Output more verbose information (0 through 2)");
+		cmdline.addOption (listcommands, 'l', "listfunctions", "List available functions");
+		cmdline.addOption (sendhelp, 'h', "help", "Print help text");
+		cmdline.addOption (test, 'x', "test", "testy test");
+		cmdline.addEnumeratedOption (verboselevel, 'V', "verbose", "Output more information");
 		StringList args = cmdline.process (argc, argv);
 
+		if (sendhelp)
+		{
+			// Print header
+			String header = APPNAME " " FULL_VERSION_STRING;
+#ifdef DEBUG
+			header += " (debug build)";
+#endif
+			printTo (stderr, "%1\n", header);
+			printTo (stderr, "usage: %1 [OPTIONS] SOURCE [OUTPUT]\n\n", argv[0]);
+			printTo (stderr, "Options:\n" + cmdline.describeOptions());
+			return EXIT_SUCCESS;
+		}
+
 		if (listcommands)
 		{
 			BotscriptParser parser;
@@ -66,22 +81,14 @@
 			for (CommandInfo* comm : getCommands())
 				print ("%1\n", comm->signature());
 
-			exit (0);
+			return EXIT_SUCCESS;
 		}
 
 		if (not within (args.size(), 1, 2))
 		{
-			// Print header
-			String header = APPNAME " " FULL_VERSION_STRING;
-#ifdef DEBUG
-			header += " (debug build)";
-#endif
-
-			printTo (stderr, "%1\n", header);
-			printTo (stderr, "usage: %1 <infile> [outfile] # compiles botscript\n", argv[0]);
-			printTo (stderr, "       %1 -l                 # lists commands\n", argv[0]);
-			printTo (stderr, "       %1 -v                 # displays version info\n", argv[0]);
-			exit (1);
+			printTo (stderr, "%1: need an input file.\nUse `%1 --help` for more information\n",
+				argv[0]);
+			return EXIT_FAILURE;
 		}
 
 		String outfile;
@@ -111,12 +118,12 @@
 
 		parser->writeToFile (outfile);
 		delete parser;
-		return 0;
+		return EXIT_SUCCESS;
 	}
 	catch (std::exception& e)
 	{
 		fprintf (stderr, "error: %s\n", e.what());
-		return 1;
+		return EXIT_FAILURE;
 	}
 }
 
@@ -175,7 +182,7 @@
 	ver += "." + String::fromNumber (minor);
 
 	if (patch != 0)
-		ver += "." + patch;
+		ver += String (".") + patch;
 
 	return ver;
 }
--- a/src/main.h	Tue Jul 22 19:22:31 2014 +0300
+++ b/src/main.h	Thu Jul 24 16:54:45 2014 +0300
@@ -32,6 +32,7 @@
 #include <cstdio>
 #include <cstdarg>
 #include <cstdint>
+#include <cstdlib>
 #include "macros.h"
 #include "property.h"
 #include "types.h"
--- a/src/parser.cpp	Tue Jul 22 19:22:31 2014 +0300
+++ b/src/parser.cpp	Thu Jul 24 16:54:45 2014 +0300
@@ -202,7 +202,7 @@
 				m_lexer->skip (-1);
 				DataBuffer* b = parseStatement();
 
-				if (b == false)
+				if (b == null)
 				{
 					m_lexer->next();
 					error ("unknown token `%1`", getTokenString());
@@ -865,7 +865,7 @@
 	// Return value
 	m_lexer->mustGetAnyOf ({Token::Int,Token::Void,Token::Bool,Token::Str});
 	comm->returnvalue = getTypeByName (m_lexer->token()->text); // TODO
-	ASSERT_NE (comm->returnvalue, -1);
+	ASSERT_NE (comm->returnvalue, TYPE_Unknown);
 
 	// Number
 	m_lexer->mustGetNext (Token::Number);
@@ -888,7 +888,7 @@
 		CommandArgument arg;
 		m_lexer->mustGetAnyOf ({Token::Int,Token::Bool,Token::Str});
 		DataType type = getTypeByName (m_lexer->token()->text); // TODO
-		ASSERT_NE (type, -1)
+		ASSERT_NE (type, TYPE_Unknown)
 		ASSERT_NE (type, TYPE_Void)
 		arg.type = type;
 
--- a/src/parser.h	Tue Jul 22 19:22:31 2014 +0300
+++ b/src/parser.h	Thu Jul 24 16:54:45 2014 +0300
@@ -37,7 +37,7 @@
 
 class DataBuffer;
 class Lexer;
-class Variable;
+struct Variable;
 
 // _________________________________________________________________________________________________
 //
--- a/src/stringClass.cpp	Tue Jul 22 19:22:31 2014 +0300
+++ b/src/stringClass.cpp	Thu Jul 24 16:54:45 2014 +0300
@@ -446,3 +446,47 @@
 	::sprintf (buf, "%ld", a);
 	return String (buf);
 }
+
+// =============================================================================
+//
+String String::fromNumber (double a)
+{
+	char buf[64];
+	::sprintf (buf, "%f", a);
+	return String (buf);
+}
+
+#ifndef _WIN32
+# define DIRSLASH "/"
+#else
+# define DIRSLASH "\\"
+#endif
+
+// =============================================================================
+//
+String dirname (String const& path)
+{
+	int lastpos = path.lastIndexOf (DIRSLASH);
+
+	if (lastpos > 0)
+		return path.mid (0, lastpos);
+
+#ifndef _WIN32
+	if (path[0] == '/')
+		return "/";
+#endif // _WIN32
+
+	return "";
+}
+
+// =============================================================================
+//
+String basename (String const& path)
+{
+	long lastpos = path.lastIndexOf (DIRSLASH);
+
+	if (lastpos != -1)
+		return path.mid (lastpos + 1);
+
+	return path;
+}
--- a/src/stringClass.h	Tue Jul 22 19:22:31 2014 +0300
+++ b/src/stringClass.h	Thu Jul 24 16:54:45 2014 +0300
@@ -102,6 +102,7 @@
 
 	static String						fromNumber (int a);
 	static String						fromNumber (long a);
+	static String						fromNumber (double a);
 
 	String								operator+ (const String& data) const;
 	String								operator+ (const char* data) const;
@@ -140,6 +141,9 @@
 inline bool operator== (const char* a, const String& b);
 inline String operator+ (const char* a, const String& b);
 
+String basename (String const& path);
+String dirname (String const& path);
+
 // =============================================================================
 //
 // IMPLEMENTATIONS

mercurial