/*] Copyright (c) 2009-2011, Charles McGarvey [***************************** **] All rights reserved. * * Distributable under the terms and conditions of the 2-clause BSD license; * see the file COPYING for a complete text of the license. * *****************************************************************************/ #include #include #include "script.hh" #include "string.hh" #include "ConvertUTF.h" namespace moof { wstring multi_to_wide(const string& multi) { typedef boost::shared_array buffer; if (sizeof(wchar_t) == 2) { 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) { 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"); } } string wide_to_multi(const wstring& wide) { typedef boost::shared_array buffer; if (sizeof(wchar_t) == 2) { 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 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"); } } 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& 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& 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; } } // namespace moof