Aegisub/automation/include/aegisub/unicode.moon

107 lines
3.5 KiB
Plaintext

-- Copyright (c) 2007, Niels Martin Hansen, Rodrigo Braz Monteiro
-- All rights reserved.
--
-- Redistribution and use in source and binary forms, with or without
-- modification, are permitted provided that the following conditions are met:
--
-- * Redistributions of source code must retain the above copyright notice,
-- this list of conditions and the following disclaimer.
-- * Redistributions in binary form must reproduce the above copyright notice,
-- this list of conditions and the following disclaimer in the documentation
-- and/or other materials provided with the distribution.
-- * Neither the name of the Aegisub Group nor the names of its contributors
-- may be used to endorse or promote products derived from this software
-- without specific prior written permission.
--
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-- POSSIBILITY OF SUCH DAMAGE.
-- Unicode (UTF-8) support functions for Aegisub Automation 4 Lua
-- http://www.ietf.org/rfc/rfc2279.txt
impl = require 'aegisub.__unicode_impl'
check = require 'aegisub.argcheck'
ffi = require 'ffi'
ffi_util = require 'aegisub.ffi'
err_buff = ffi.new 'char *[1]'
conv_func = (f) -> check'string' (str) ->
err_buff[0] = nil
result = f str, err_buff
errmsg = ffi_util.string err_buff[0]
if errmsg
error errmsg, 2
ffi_util.string result
local unicode
unicode =
-- Return the number of bytes occupied by the character starting at the i'th byte in s
charwidth: check'string ?number' (s, i) ->
b = s\byte i or 1
-- FIXME, something in karaskel results in this case, shouldn't happen
-- What would "proper" behaviour be? Zero? Or just explode?
if not b then 1
elseif b < 128 then 1
elseif b < 224 then 2
elseif b < 240 then 3
else 4
-- Returns an iterator function for iterating over the characters in s
chars: check'string' (s) ->
curchar, i = 0, 1
->
return if i > s\len()
j = i
curchar += 1
i += unicode.charwidth s, i
s\sub(j, i - 1), curchar
-- Returns the number of characters in s
-- Runs in O(s:len()) time!
len: check'string' (s) ->
n = 0
n += 1 for c in unicode.chars s
n
-- Get codepoint of first char in s
codepoint: check'string' (s) ->
-- Basic case, ASCII
b = s\byte 1
return b if b < 128
-- Use a naive decoding algorithm, and assume input is valid
local res, w
if b < 224 then
-- prefix byte is 110xxxxx
res = b - 192
w = 2
elseif b < 240 then
-- prefix byte is 11100000
res = b - 224
w = 3
else
res = b - 240
w = 4
for i = 2, w
res = res*64 + s\byte(i) - 128
res
to_upper_case: conv_func impl.to_upper_case
to_lower_case: conv_func impl.to_lower_case
to_fold_case: conv_func impl.to_fold_case
return unicode