-/*] Copyright (c) 2009-2010, Charles McGarvey [**************************
+/*] Copyright (c) 2009-2011, Charles McGarvey [*****************************
**] All rights reserved.
*
-* vi:ts=4 sw=4 tw=75
-*
* Distributable under the terms and conditions of the 2-clause BSD license;
* see the file COPYING for a complete text of the license.
*
-**************************************************************************/
+*****************************************************************************/
#include <stdexcept>
-#include "ConvertUTF.h"
+#include <boost/shared_array.hpp>
+
+#include "script.hh"
#include "string.hh"
+#include "ConvertUTF.h"
namespace moof {
-// TODO this code is ugly
-
wstring multi_to_wide(const string& multi)
{
- size_t length = multi.length();
+ typedef boost::shared_array<wchar_t> buffer;
if (sizeof(wchar_t) == 2)
{
- wchar_t* wide = new wchar_t[length + 1];
-
- const UTF8* srcStart = reinterpret_cast<const UTF8*>(multi.c_str());
- const UTF8* srcEnd = srcStart + length;
- UTF16* targetStart = reinterpret_cast<UTF16*>(wide);
- UTF16* targetEnd = targetStart + length+1;
-
- ConversionResult res = ConvertUTF8toUTF16(&srcStart, srcEnd,
- &targetStart, targetEnd, lenientConversion);
- if (res != conversionOK)
- {
- delete[] wide;
- throw std::runtime_error("bad conversion from multi to wide characters");
- }
-
- *targetStart = 0;
- wstring convertedStr(wide);
- delete[] wide;
-
- return convertedStr;
+ size_t length = multi.length();
+ buffer wide(new wchar_t[length + 1]);
+ const UTF8* src1 = (const UTF8*)multi.c_str();
+ const UTF8* src2 = src1 + length;
+ UTF16* dst1 = (UTF16*)wide.get();
+ UTF16* dst2 = dst1 + length + 1;
+
+ if (ConvertUTF8toUTF16(&src1, src2,
+ &dst1, dst2,
+ lenientConversion) != conversionOK)
+ throw std::runtime_error("bad string conversion");
+
+ *dst1 = 0;
+ wstring str(wide.get());
+ return str;
}
else if (sizeof(wchar_t) == 4)
{
- wchar_t* wide = new wchar_t[length];
-
- const UTF8* srcStart = reinterpret_cast<const UTF8*>(multi.c_str());
- const UTF8* srcEnd = srcStart + length;
- UTF32* targetStart = reinterpret_cast<UTF32*>(wide);
- UTF32* targetEnd = targetStart + length;
-
- ConversionResult res = ConvertUTF8toUTF32(&srcStart, srcEnd,
- &targetStart, targetEnd, lenientConversion);
- if (res != conversionOK)
- {
- delete[] wide;
- throw std::runtime_error("bad conversion from multi to wide characters");
- }
-
- *targetStart = 0;
- wstring convertedStr(wide);
- delete[] wide;
-
- return convertedStr;
+ size_t length = multi.length();
+ buffer wide(new wchar_t[length + 1]);
+ const UTF8* src1 = (const UTF8*)multi.c_str();
+ const UTF8* src2 = src1 + length;
+ UTF32* dst1 = (UTF32*)wide.get();
+ UTF32* dst2 = dst1 + length + 1;
+
+ if (ConvertUTF8toUTF32(&src1, src2,
+ &dst1, dst2,
+ lenientConversion) != conversionOK)
+ throw std::runtime_error("bad string conversion");
+
+ *dst1 = 0;
+ wstring str(wide.get());
+ return str;
}
else
{
throw std::runtime_error("unknown size of wide characters");
}
- return L"";
}
string wide_to_multi(const wstring& wide)
{
- size_t length = wide.length();
+ typedef boost::shared_array<char> buffer;
if (sizeof(wchar_t) == 2)
{
- size_t multiLength = 3 * length + 1;
- char* multi = new char[multiLength];
-
- const UTF16* srcStart = reinterpret_cast<const UTF16*>(wide.c_str());
- const UTF16* srcEnd = srcStart + length;
- UTF8* targetStart = reinterpret_cast<UTF8*>(multi);
- UTF8* targetEnd = targetStart + multiLength;
-
- ConversionResult res = ConvertUTF16toUTF8(&srcStart, srcEnd,
- &targetStart, targetEnd, lenientConversion);
- if (res != conversionOK)
- {
- delete[] multi;
- throw std::runtime_error("bad conversion from wide to multi-characters");
- }
-
- *targetStart = 0;
- string convertedStr(multi);
- delete[] multi;
-
- return convertedStr;
+ size_t length = wide.length();
+ size_t multi_length = 3 * length + 1;
+ buffer multi(new char[multi_length]);
+ const UTF16* src1 = (const UTF16*)wide.c_str();
+ const UTF16* src2 = src1 + length;
+ UTF8* dst1 = (UTF8*)multi.get();
+ UTF8* dst2 = dst1 + multi_length;
+
+ if (ConvertUTF16toUTF8(&src1, src2,
+ &dst1, dst2,
+ lenientConversion) != conversionOK)
+ throw std::runtime_error("bad string conversion");
+
+ *dst1 = 0;
+ string str(multi.get());
+ return str;
}
else if (sizeof(wchar_t) == 4)
{
- size_t multiLength = 4 * length + 1;
- char* multi = new char[multiLength];
-
- const UTF32* srcStart = reinterpret_cast<const UTF32*>(wide.c_str());
- const UTF32* srcEnd = srcStart + length;
- UTF8* targetStart = reinterpret_cast<UTF8*>(multi);
- UTF8* targetEnd = targetStart + multiLength;
-
- ConversionResult res = ConvertUTF32toUTF8(&srcStart, srcEnd,
- &targetStart, targetEnd, lenientConversion);
- if (res != conversionOK)
- {
- delete[] multi;
- throw std::runtime_error("bad conversion from wide to multi-characters");
- }
-
- *targetStart = 0;
- string convertedStr(multi);
- delete[] multi;
-
- return convertedStr;
+ size_t length = wide.length();
+ size_t multi_length = 4 * length + 1;
+ buffer multi(new char[multi_length]);
+ const UTF32* src1 = (const UTF32*)wide.c_str();
+ const UTF32* src2 = src1 + length;
+ UTF8* dst1 = (UTF8*)multi.get();
+ UTF8* dst2 = dst1 + multi_length;
+
+ if (ConvertUTF32toUTF8(&src1, src2,
+ &dst1, dst2,
+ lenientConversion) != conversionOK)
+ throw std::runtime_error("bad string conversion");
+
+ *dst1 = 0;
+ string str(multi.get());
+ return str;
}
else
{
throw std::runtime_error("unknown size of wide characters");
}
- return "";
+}
+
+
+static script& pattern_script()
+{
+ static script script;
+ static bool init = true;
+ if (init)
+ {
+ script.import_string_library();
+ script.globals().push_field("string").push_field("match");
+ script.globals().set_field("match");
+ script.top().push_field("gmatch");
+ script.globals().set_field("gmatch");
+ script.top().push_field("gsub");
+ script.globals().set_field("gsub");
+ script.push_nil();
+ script.globals().set_field("string");
+ script.pop();
+ init = false;
+ }
+ return script;
+}
+
+pattern::pattern(const std::string& pattern)
+{
+ pattern::string(pattern);
+}
+
+pattern::pattern(const std::string& pattern, const std::string& source)
+{
+ pattern::string(pattern);
+ match(source);
+}
+
+pattern::~pattern()
+{
+ script& script = pattern_script();
+ script.push_pointer(this);
+ script.push_nil();
+ script.globals().set_field();
+ script.push_pointer(this);
+ script.push_nil();
+ script.registry().set_field();
+}
+
+std::string pattern::string() const
+{
+ script& script = pattern_script();
+ script.push_pointer(this);
+ script::slot saved = script.registry().push_field();
+
+ std::string pattern;
+ saved.get(pattern);
+
+ saved.pop();
+ return pattern;
+}
+
+void pattern::string(const std::string& pattern)
+{
+ script& script = pattern_script();
+ script.push_pointer(this);
+ script.push(pattern);
+ script.registry().set_field();
+}
+
+void pattern::match(const std::string& source)
+{
+ script& script = pattern_script();
+ script.push_pointer(this);
+
+ script.globals().push_field("gmatch");
+ script.push(source);
+ script.push_pointer(this);
+ script.registry().push_field();
+ script.call(2, 1);
+
+ script.globals().set_field();
+}
+
+bool pattern::get(std::string& match)
+{
+ script& script = pattern_script();
+ script.push_pointer(this);
+ script::slot value = script.globals().push_field();
+ if (!value.is_function())
+ {
+ script.clear_stack();
+ return false;
+ }
+
+ script.call(0, 1);
+ bool result = value.get(match);
+ script.pop();
+ return result;
+}
+
+bool pattern::get(std::vector<std::string>& captures)
+{
+ script& script = pattern_script();
+ script.push_pointer(this);
+ script::slot value = script.globals().push_field();
+ if (!value.is_function())
+ {
+ script.clear_stack();
+ return false;
+ }
+
+ script.call();
+ captures.clear();
+
+ while (value.is_string())
+ {
+ captures.resize(captures.size() + 1);
+ value.get(captures.back());
+ ++value.index;
+ }
+
+ script.clear_stack();
+ return 0 < captures.size();
+}
+
+bool pattern::match(std::string& match,
+ const std::string& pattern, const std::string& source, int position)
+{
+ script& script = pattern_script();
+ script::slot value = script.globals().push_field("match");
+ script.push(source);
+ script.push(pattern);
+ ++position; // lua indices count from one
+ script.push(position);
+ script.call(3, 1);
+
+ bool result = value.get(match);
+ script.clear_stack();
+ return result;
+}
+
+bool pattern::match(std::vector<std::string>& captures,
+ const std::string& pattern, const std::string& source, int position)
+{
+ script& script = pattern_script();
+ script::slot value = script.globals().push_field("match");
+ script.push(source);
+ script.push(pattern);
+ ++position; // lua indices count from one
+ script.push(position);
+ script.call(3);
+
+ captures.clear();
+
+ while (value.is_string())
+ {
+ captures.resize(captures.size() + 1);
+ value.get(captures.back());
+ ++value.index;
+ }
+
+ script.clear_stack();
+ return 0 < captures.size();
+}
+
+int pattern::sub(std::string& substitution,
+ const std::string& pattern,
+ const std::string& source, const std::string& replacement)
+{
+ script& script = pattern_script();
+ script::slot value = script.globals().push_field("gsub");
+ script.push(source);
+ script.push(pattern);
+ script.push(replacement);
+ script.call(3, 2);
+
+ value.get(substitution);
+
+ ++value.index;
+ int count = 0;
+ value.get(count);
+
+ script.clear_stack();
+ return count;
}