=== modified file 'src/libmatrix/Makefile'
@@ -9,6 +9,7 @@
$(TESTDIR)/inverse_test.cc \
$(TESTDIR)/transpose_test.cc \
$(TESTDIR)/shader_source_test.cc \
+ $(TESTDIR)/util_split_test.cc \
$(TESTDIR)/libmatrix_test.cc
TESTOBJS = $(TESTSRCS:.cc=.o)
@@ -32,6 +33,7 @@
$(TESTDIR)/inverse_test.o: $(TESTDIR)/inverse_test.cc $(TESTDIR)/inverse_test.h $(TESTDIR)/libmatrix_test.h mat.h
$(TESTDIR)/transpose_test.o: $(TESTDIR)/transpose_test.cc $(TESTDIR)/transpose_test.h $(TESTDIR)/libmatrix_test.h mat.h
$(TESTDIR)/shader_source_test.o: $(TESTDIR)/shader_source_test.cc $(TESTDIR)/shader_source_test.h $(TESTDIR)/libmatrix_test.h shader-source.h
+$(TESTDIR)/util_split_test.o: $(TESTDIR)/util_split_test.cc $(TESTDIR)/util_split_test.h $(TESTDIR)/libmatrix_test.h util.h
$(TESTDIR)/libmatrix_test: $(TESTOBJS) libmatrix.a
$(CXX) -o $@ $^
run_tests: $(LIBMATRIX_TESTS)
=== modified file 'src/libmatrix/log.cc'
@@ -10,6 +10,7 @@
// Alexandros Frantzis <alexandros.frantzis@linaro.org>
// Jesse Barker <jesse.barker@linaro.org>
//
+#include <unistd.h>
#include <cstdio>
#include <cstdarg>
#include <string>
@@ -26,8 +27,7 @@
const string Log::continuation_prefix("\x10");
string Log::appname_;
bool Log::do_debug_(false);
-
-#ifndef ANDROID
+std::ostream* Log::extra_out_(0);
static const string terminal_color_normal("\033[0m");
static const string terminal_color_red("\033[1;31m");
@@ -96,17 +96,26 @@
delete[] buf;
}
+
void
Log::info(const char *fmt, ...)
{
static const string infoprefix("Info");
+ const string& prefix(do_debug_ ? infoprefix : empty);
+ va_list ap;
+ va_start(ap, fmt);
+
+#ifndef ANDROID
static const string& infocolor(isatty(fileno(stdout)) ? terminal_color_cyan : empty);
- va_list ap;
- va_start(ap, fmt);
- if (do_debug_)
- print_prefixed_message(std::cout, infocolor, infoprefix, fmt, ap);
- else
- print_prefixed_message(std::cout, empty, empty, fmt, ap);
+ const string& color(do_debug_ ? infocolor : empty);
+ print_prefixed_message(std::cout, color, prefix, fmt, ap);
+#else
+ __android_log_vprint(ANDROID_LOG_INFO, appname_.c_str(), fmt, ap);
+#endif
+
+ if (extra_out_)
+ print_prefixed_message(*extra_out_, empty, prefix, fmt, ap);
+
va_end(ap);
}
@@ -114,12 +123,21 @@
Log::debug(const char *fmt, ...)
{
static const string dbgprefix("Debug");
+ if (!do_debug_)
+ return;
+ va_list ap;
+ va_start(ap, fmt);
+
+#ifndef ANDROID
static const string& dbgcolor(isatty(fileno(stdout)) ? terminal_color_yellow : empty);
- if (!do_debug_)
- return;
- va_list ap;
- va_start(ap, fmt);
print_prefixed_message(std::cout, dbgcolor, dbgprefix, fmt, ap);
+#else
+ __android_log_vprint(ANDROID_LOG_DEBUG, appname_.c_str(), fmt, ap);
+#endif
+
+ if (extra_out_)
+ print_prefixed_message(*extra_out_, empty, dbgprefix, fmt, ap);
+
va_end(ap);
}
@@ -127,52 +145,29 @@
Log::error(const char *fmt, ...)
{
static const string errprefix("Error");
+ va_list ap;
+ va_start(ap, fmt);
+
+#ifndef ANDROID
static const string& errcolor(isatty(fileno(stderr)) ? terminal_color_red : empty);
- va_list ap;
- va_start(ap, fmt);
print_prefixed_message(std::cerr, errcolor, errprefix, fmt, ap);
+#else
+ __android_log_vprint(ANDROID_LOG_ERROR, appname_.c_str(), fmt, ap);
+#endif
+
+ if (extra_out_)
+ print_prefixed_message(*extra_out_, empty, errprefix, fmt, ap);
+
va_end(ap);
}
void
Log::flush()
{
+#ifndef ANDROID
std::cout.flush();
std::cerr.flush();
-}
-#else
-void
-Log::info(const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- __android_log_vprint(ANDROID_LOG_INFO, appname_.c_str(), fmt, ap);
- va_end(ap);
-}
-
-void
-Log::debug(const char *fmt, ...)
-{
- if (!do_debug_)
- return;
- va_list ap;
- va_start(ap, fmt);
- __android_log_vprint(ANDROID_LOG_DEBUG, appname_.c_str(), fmt, ap);
- va_end(ap);
-}
-
-void
-Log::error(const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- __android_log_vprint(ANDROID_LOG_ERROR, appname_.c_str(), fmt, ap);
- va_end(ap);
-}
-
-void
-Log::flush()
-{
-}
-
#endif
+ if (extra_out_)
+ extra_out_->flush();
+}
=== modified file 'src/libmatrix/log.h'
@@ -14,14 +14,17 @@
#define LOG_H_
#include <string>
+#include <iostream>
class Log
{
public:
- static void init(const std::string& appname, bool do_debug = false)
+ static void init(const std::string& appname, bool do_debug = false,
+ std::ostream *extra_out = 0)
{
appname_ = appname;
do_debug_ = do_debug;
+ extra_out_ = extra_out;
}
// Emit an informational message
static void info(const char *fmt, ...);
@@ -41,6 +44,8 @@
static std::string appname_;
// Indicates whether debug level messages should generate any output
static bool do_debug_;
+ // Extra stream to output log messages to
+ static std::ostream *extra_out_;
};
#endif /* LOG_H_ */
=== modified file 'src/libmatrix/program.cc'
@@ -20,6 +20,7 @@
using std::string;
using LibMatrix::mat4;
+using LibMatrix::mat3;
using LibMatrix::vec2;
using LibMatrix::vec3;
using LibMatrix::vec4;
@@ -276,6 +277,17 @@
}
Program::Symbol&
+Program::Symbol::operator=(const mat3& m)
+{
+ if (type_ == Uniform)
+ {
+ // Our matrix representation is column-major, so transpose is false here.
+ glUniformMatrix3fv(location_, 1, GL_FALSE, m);
+ }
+ return *this;
+}
+
+Program::Symbol&
Program::Symbol::operator=(const vec2& v)
{
if (type_ == Uniform)
=== modified file 'src/libmatrix/program.h'
@@ -127,6 +127,7 @@
// These members cause data to be bound to program variables, so
// the program must be bound for use for these to be effective.
Symbol& operator=(const LibMatrix::mat4& m);
+ Symbol& operator=(const LibMatrix::mat3& m);
Symbol& operator=(const LibMatrix::vec2& v);
Symbol& operator=(const LibMatrix::vec3& v);
Symbol& operator=(const LibMatrix::vec4& v);
=== modified file 'src/libmatrix/shader-source.cc'
@@ -589,7 +589,7 @@
{
std::vector<std::string> elems;
- Util::split(precision_values, ',', elems);
+ Util::split(precision_values, ',', elems, Util::SplitModeNormal);
for (size_t i = 0; i < elems.size() && i < 4; i++) {
const std::string& pstr(elems[i]);
=== modified file 'src/libmatrix/test/libmatrix_test.cc'
@@ -8,6 +8,7 @@
//
// Contributors:
// Jesse Barker - original implementation.
+// Alexandros Frantzis - Util::split tests
//
#include <iostream>
#include <string>
@@ -17,6 +18,7 @@
#include "transpose_test.h"
#include "const_vec_test.h"
#include "shader_source_test.h"
+#include "util_split_test.h"
using std::cerr;
using std::cout;
@@ -42,6 +44,8 @@
testVec.push_back(new MatrixTest3x3Transpose());
testVec.push_back(new MatrixTest4x4Transpose());
testVec.push_back(new ShaderSourceBasic());
+ testVec.push_back(new UtilSplitTestNormal());
+ testVec.push_back(new UtilSplitTestQuoted());
for (vector<MatrixTest*>::iterator testIt = testVec.begin();
testIt != testVec.end();
=== added file 'src/libmatrix/test/util_split_test.cc'
@@ -0,0 +1,180 @@
+//
+// Copyright (c) 2012 Linaro Limited
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the MIT License which accompanies
+// this distribution, and is available at
+// http://www.opensource.org/licenses/mit-license.php
+//
+// Contributors:
+// Alexandros Frantzis - original implementation.
+//
+#include <iostream>
+#include <string>
+#include <vector>
+#include "libmatrix_test.h"
+#include "util_split_test.h"
+#include "../util.h"
+
+using std::cout;
+using std::endl;
+using std::string;
+using std::vector;
+
+template <typename T> static bool
+areVectorsEqual(vector<T>& vec1, vector<T>& vec2)
+{
+ if (vec1.size() != vec2.size())
+ return false;
+
+ for (unsigned int i = 0; i < vec1.size(); i++)
+ {
+ if (vec1[i] != vec2[i])
+ return false;
+ }
+
+ return true;
+}
+
+template <typename T> static void
+printVector(vector<T>& vec)
+{
+ cout << "[";
+ for (unsigned int i = 0; i < vec.size(); i++)
+ {
+ cout << '"' << vec[i] << '"';
+ if (i < vec.size() - 1)
+ cout << ", ";
+ }
+ cout << "]";
+}
+
+void
+UtilSplitTestNormal::run(const Options& options)
+{
+ const string test1("abc def ghi");
+ const string test2(" abc: def :ghi ");
+ vector<string> expected1;
+ vector<string> expected2;
+ vector<string> results;
+
+ expected1.push_back("abc");
+ expected1.push_back("def");
+ expected1.push_back("ghi");
+
+ expected2.push_back(" abc");
+ expected2.push_back(" def ");
+ expected2.push_back("ghi ");
+
+ if (options.beVerbose())
+ {
+ cout << "Testing string \"" << test1 << "\"" << endl;
+ }
+
+ Util::split(test1, ' ', results, Util::SplitModeNormal);
+
+ if (options.beVerbose())
+ {
+ cout << "Split result: ";
+ printVector(results);
+ cout << endl << "Expected: ";
+ printVector(expected1);
+ cout << endl;
+ }
+
+ if (!areVectorsEqual(results, expected1))
+ {
+ return;
+ }
+
+ results.clear();
+
+ if (options.beVerbose())
+ {
+ cout << "Testing string \"" << test2 << "\"" << endl;
+ }
+
+ Util::split(test2, ':', results, Util::SplitModeNormal);
+
+ if (options.beVerbose())
+ {
+ cout << "Split result: ";
+ printVector(results);
+ cout << endl << "Expected: ";
+ printVector(expected2);
+ cout << endl;
+ }
+
+ if (!areVectorsEqual(results, expected2))
+ {
+ return;
+ }
+
+ pass_ = true;
+}
+
+void
+UtilSplitTestQuoted::run(const Options& options)
+{
+ const string test1("abc \"def' ghi\" klm\\ nop -b qr:title='123 \"456'");
+ const string test2("abc: def='1:2:3:'ghi : \":jk\"");
+ vector<string> expected1;
+ vector<string> expected2;
+ vector<string> results;
+
+ expected1.push_back("abc");
+ expected1.push_back("def' ghi");
+ expected1.push_back("klm nop");
+ expected1.push_back("-b");
+ expected1.push_back("qr:title=123 \"456");
+
+ expected2.push_back("abc");
+ expected2.push_back(" def=1:2:3:ghi ");
+ expected2.push_back(" :jk");
+
+ if (options.beVerbose())
+ {
+ cout << "Testing string \"" << test1 << "\"" << endl;
+ }
+
+ Util::split(test1, ' ', results, Util::SplitModeQuoted);
+
+ if (options.beVerbose())
+ {
+ cout << "Split result: ";
+ printVector(results);
+ cout << endl << "Expected: ";
+ printVector(expected1);
+ cout << endl;
+ }
+
+ if (!areVectorsEqual(results, expected1))
+ {
+ return;
+ }
+
+ results.clear();
+
+ if (options.beVerbose())
+ {
+ cout << "Testing string \"" << test2 << "\"" << endl;
+ }
+
+ Util::split(test2, ':', results, Util::SplitModeQuoted);
+
+ if (options.beVerbose())
+ {
+ cout << "Split result: ";
+ printVector(results);
+ cout << endl << "Expected: ";
+ printVector(expected2);
+ cout << endl;
+ }
+
+ if (!areVectorsEqual(results, expected2))
+ {
+ return;
+ }
+
+ pass_ = true;
+}
=== added file 'src/libmatrix/test/util_split_test.h'
@@ -0,0 +1,31 @@
+//
+// Copyright (c) 2012 Linaro Limited
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the MIT License which accompanies
+// this distribution, and is available at
+// http://www.opensource.org/licenses/mit-license.php
+//
+// Contributors:
+// Alexandros Frantzis - original implementation.
+//
+#ifndef UTIL_SPLIT_TEST_H_
+#define UTIL_SPLIT_TEST_H_
+
+class MatrixTest;
+class Options;
+
+class UtilSplitTestNormal : public MatrixTest
+{
+public:
+ UtilSplitTestNormal() : MatrixTest("Util::split::normal") {}
+ virtual void run(const Options& options);
+};
+
+class UtilSplitTestQuoted : public MatrixTest
+{
+public:
+ UtilSplitTestQuoted() : MatrixTest("Util::split::quoted") {}
+ virtual void run(const Options& options);
+};
+#endif // UTIL_SPLIT_TEST_H_
=== modified file 'src/libmatrix/util.cc'
@@ -25,25 +25,102 @@
using std::string;
using std::vector;
-void
-Util::split(const string& src, char delim, vector<string>& elementVec, bool fuzzy)
-{
- // Trivial rejection
- if (src.empty())
- {
- return;
- }
-
- // Simple case: we want to enforce the value of 'delim' strictly
- if (!fuzzy)
- {
- std::stringstream ss(src);
- string item;
- while(std::getline(ss, item, delim))
- elementVec.push_back(item);
- return;
- }
-
+/*
+ * State machine for bash-like quoted string escaping:
+ *
+ * \
+ * -----------> +---------+
+ * | ---------- | Escaped |
+ * | | *,ESC +---------+
+ * | |
+ * | v '
+ * +--------+ ---> +--------------+ -----
+ * | Normal | <--- | SingleQuoted | | *, ESC
+ * +--------+ ' +--------------+ <----
+ * | ^
+ * | |
+ * | | " +--------------+ ----
+ * | ---------- | DoubleQuoted | | *, ESC
+ * -----------> +--------------+ <---
+ * " | ^
+ * \ | | *, ESC
+ * v |
+ * +---------------------+
+ * | DoubleQuotedEscaped |
+ * +---------------------+
+ *
+ * ESC: Mark character as Escaped
+ */
+static void
+fill_escape_vector(const string &str, vector<bool> &esc_vec)
+{
+ enum State {
+ StateNormal,
+ StateEscaped,
+ StateDoubleQuoted,
+ StateDoubleQuotedEscaped,
+ StateSingleQuoted
+ };
+
+ State state = StateNormal;
+
+ for (string::const_iterator iter = str.begin();
+ iter != str.end();
+ iter++)
+ {
+ const char c(*iter);
+ bool esc = false;
+
+ switch (state) {
+ case StateNormal:
+ if (c == '"')
+ state = StateDoubleQuoted;
+ else if (c == '\\')
+ state = StateEscaped;
+ else if (c == '\'')
+ state = StateSingleQuoted;
+ break;
+ case StateEscaped:
+ esc = true;
+ state = StateNormal;
+ break;
+ case StateDoubleQuoted:
+ if (c == '"')
+ state = StateNormal;
+ else if (c == '\\')
+ state = StateDoubleQuotedEscaped;
+ else
+ esc = true;
+ break;
+ case StateDoubleQuotedEscaped:
+ esc = true;
+ state = StateDoubleQuoted;
+ break;
+ case StateSingleQuoted:
+ if (c == '\'')
+ state = StateNormal;
+ else
+ esc = true;
+ default:
+ break;
+ }
+
+ esc_vec.push_back(esc);
+ }
+}
+
+static void
+split_normal(const string& src, char delim, vector<string>& elementVec)
+{
+ std::stringstream ss(src);
+ string item;
+ while(std::getline(ss, item, delim))
+ elementVec.push_back(item);
+}
+
+static void
+split_fuzzy(const string& src, char delim, vector<string>& elementVec)
+{
// Fuzzy case: Initialize our delimiter string based upon the caller's plus
// a space to allow for more flexibility.
string delimiter(" ");
@@ -76,6 +153,70 @@
elementVec.push_back(str);
}
+static void
+split_quoted(const string& src, char delim, vector<string>& elementVec)
+{
+ std::stringstream ss;
+ vector<bool> escVec;
+
+ /* Mark characters in the string as escaped or not */
+ fill_escape_vector(src, escVec);
+
+ /* Sanity check... */
+ if (src.length() != escVec.size())
+ return;
+
+ for (vector<bool>::const_iterator iter = escVec.begin();
+ iter != escVec.end();
+ iter++)
+ {
+ bool escaped = static_cast<bool>(*iter);
+ char c = src[iter - escVec.begin()];
+
+ /* Output all characters, except unescaped ",\,' */
+ if ((c != '"' && c != '\\' && c != '\'') || escaped) {
+ /* If we reach an unescaped delimiter character, do a split */
+ if (c == delim && !escaped) {
+ elementVec.push_back(ss.str());
+ ss.str("");
+ ss.clear();
+ }
+ else {
+ ss << c;
+ }
+ }
+
+ }
+
+ /* Handle final element, delimited by end of string */
+ const string &finalElement(ss.str());
+ if (!finalElement.empty())
+ elementVec.push_back(finalElement);
+}
+
+void
+Util::split(const string& src, char delim, vector<string>& elementVec,
+ Util::SplitMode mode)
+{
+ // Trivial rejection
+ if (src.empty())
+ {
+ return;
+ }
+
+ switch (mode)
+ {
+ case Util::SplitModeNormal:
+ return split_normal(src, delim, elementVec);
+ case Util::SplitModeFuzzy:
+ return split_fuzzy(src, delim, elementVec);
+ case Util::SplitModeQuoted:
+ return split_quoted(src, delim, elementVec);
+ default:
+ break;
+ }
+}
+
uint64_t
Util::get_timestamp_us()
{
=== modified file 'src/libmatrix/util.h'
@@ -25,21 +25,33 @@
struct Util {
/**
+ * How to perform the split() operation
+ */
+ enum SplitMode {
+ /** Normal split operation */
+ SplitModeNormal,
+ /** Allow for spaces and multiple consecutive occurences of the delimiter */
+ SplitModeFuzzy,
+ /** Take into account bash-like quoting and escaping rules */
+ SplitModeQuoted
+ };
+
+ /**
* split() - Splits a string into elements using a provided delimiter
*
* @s: the string to split
* @delim: the delimiter to use
* @elems: the string vector to populate
- * @fuzzy: (optional) enable/disable strict handling of @delim
+ * @mode: the SplitMode to use
*
* Using @delim to determine field boundaries, splits @s into separate
* string elements. These elements are returned in the string vector
- * @elems. If @fuzzy is true, then the handling of @delim allows for
- * spaces and multiple consecutive occurences of @delim in determining
- * field boundaries. As long as @s is non-empty, there will be at least
- * one element in @elems.
+ * @elems. As long as @s is non-empty, there will be at least one
+ * element in @elems.
*/
- static void split(const std::string &s, char delim, std::vector<std::string> &elems, bool fuzzy = false);
+ static void split(const std::string& src, char delim,
+ std::vector<std::string>& elems,
+ Util::SplitMode mode);
/**
* get_timestamp_us() - Returns the current time in microseconds
*/