diff --git a/automation/include/aegisub/unicode.moon b/automation/include/aegisub/unicode.moon
index 8c1d210e5..672ff7a2a 100644
--- a/automation/include/aegisub/unicode.moon
+++ b/automation/include/aegisub/unicode.moon
@@ -28,6 +28,8 @@
-- Unicode (UTF-8) support functions for Aegisub Automation 4 Lua
-- http://www.ietf.org/rfc/rfc2279.txt
+impl = require 'aegisub.__unicode_impl'
+
local unicode
unicode =
-- Return the number of bytes occupied by the character starting at the i'th byte in s
@@ -84,4 +86,8 @@ unicode =
res = res*64 + s\byte(i) - 128
res
+ to_upper_case: impl.to_upper_case
+ to_lower_case: impl.to_lower_case
+ to_fold_case: impl.to_fold_case
+
return unicode
diff --git a/build/libaegisub/libaegisub.vcxproj b/build/libaegisub/libaegisub.vcxproj
index 26ec72c9b..36501fea3 100644
--- a/build/libaegisub/libaegisub.vcxproj
+++ b/build/libaegisub/libaegisub.vcxproj
@@ -127,6 +127,7 @@
+
diff --git a/build/libaegisub/libaegisub.vcxproj.filters b/build/libaegisub/libaegisub.vcxproj.filters
index 4e1262339..8975f5378 100644
--- a/build/libaegisub/libaegisub.vcxproj.filters
+++ b/build/libaegisub/libaegisub.vcxproj.filters
@@ -319,10 +319,13 @@
Lua
+
+ Lua\Modules
+
Header Files
-
+
\ No newline at end of file
diff --git a/libaegisub/Makefile b/libaegisub/Makefile
index ce8280629..a1be865a1 100644
--- a/libaegisub/Makefile
+++ b/libaegisub/Makefile
@@ -45,6 +45,7 @@ SRC += \
lua/modules/lfs.cpp \
lua/modules/lpeg.c \
lua/modules/re.cpp \
+ lua/modules/unicode.cpp \
lua/script_reader.cpp \
lua/utils.cpp \
unix/access.cpp \
diff --git a/libaegisub/lua/modules.cpp b/libaegisub/lua/modules.cpp
index b0c8565d1..305f9fb22 100644
--- a/libaegisub/lua/modules.cpp
+++ b/libaegisub/lua/modules.cpp
@@ -20,6 +20,7 @@
extern "C" int luaopen_luabins(lua_State *L);
extern "C" int luaopen_re_impl(lua_State *L);
+extern "C" int luaopen_unicode_impl(lua_State *L);
extern "C" int luaopen_lfs(lua_State *L);
extern "C" int luaopen_lpeg(lua_State *L);
@@ -33,6 +34,7 @@ void preload_modules(lua_State *L) {
lua_getfield(L, -1, "preload");
set_field(L, "aegisub.__re_impl", luaopen_re_impl);
+ set_field(L, "aegisub.__unicode_impl", luaopen_unicode_impl);
set_field(L, "lfs", luaopen_lfs);
set_field(L, "lpeg", luaopen_lpeg);
set_field(L, "luabins", luaopen_luabins);
diff --git a/libaegisub/lua/modules/unicode.cpp b/libaegisub/lua/modules/unicode.cpp
new file mode 100644
index 000000000..66b955497
--- /dev/null
+++ b/libaegisub/lua/modules/unicode.cpp
@@ -0,0 +1,46 @@
+// Copyright (c) 2014, Thomas Goyne
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+//
+// Aegisub Project http://www.aegisub.org/
+
+#include "libaegisub/lua/utils.h"
+
+#include
+
+namespace {
+using namespace agi::lua;
+
+int unicode_upper(lua_State *L) {
+ push_value(L, boost::locale::to_upper(check_string(L, 1)));
+ return 1;
+}
+
+int unicode_lower(lua_State *L) {
+ push_value(L, boost::locale::to_lower(check_string(L, 1)));
+ return 1;
+}
+
+int unicode_fold(lua_State *L) {
+ push_value(L, boost::locale::fold_case(check_string(L, 1)));
+ return 1;
+}
+}
+
+extern "C" int luaopen_unicode_impl(lua_State *L) {
+ lua_createtable(L, 0, 3);
+ set_field(L, "to_upper_case");
+ set_field(L, "to_lower_case");
+ set_field(L, "to_fold_case");
+ return 1;
+}