Skip to main content

luaur_vm/functions/
byteoffset.rs

1use crate::functions::lua_l_checkinteger::lua_l_checkinteger;
2use crate::functions::lua_l_checklstring::lua_l_checklstring;
3use crate::functions::lua_l_error_l::lua_l_error_l;
4use crate::functions::lua_l_optinteger::lua_l_optinteger;
5use crate::functions::lua_pushinteger::lua_pushinteger;
6use crate::functions::lua_pushnil::lua_pushnil;
7use crate::functions::u_posrelat::u_posrelat;
8use crate::macros::iscont::iscont;
9use crate::macros::lua_l_argcheck::luaL_argcheck;
10use crate::type_aliases::lua_state::lua_State;
11use core::ffi::c_int;
12
13#[no_mangle]
14pub unsafe fn byteoffset(L: *mut lua_State) -> c_int {
15    let mut len: usize = 0;
16    let s = lua_l_checklstring(L, 1, &mut len);
17    let mut n = lua_l_checkinteger(L, 2);
18    let mut posi = if n >= 0 { 1 } else { len as i32 + 1 };
19    posi = u_posrelat(lua_l_optinteger(L, 3, posi), len);
20    luaL_argcheck!(
21        L,
22        1 <= posi && posi <= len as i32 + 1,
23        3,
24        "position out of range"
25    );
26    posi -= 1;
27
28    if n == 0 {
29        // find beginning of current byte sequence
30        while posi > 0 && iscont(s.add(posi as usize)) {
31            posi -= 1;
32        }
33    } else {
34        if iscont(s.add(posi as usize)) {
35            lua_l_error_l(
36                L,
37                c"initial position is a continuation byte".as_ptr(),
38                core::format_args!("initial position is a continuation byte"),
39            );
40        }
41        if n < 0 {
42            while n < 0 && posi > 0 {
43                // move back
44                loop {
45                    // find beginning of previous character
46                    posi -= 1;
47                    if !(posi > 0 && iscont(s.add(posi as usize))) {
48                        break;
49                    }
50                }
51                n += 1;
52            }
53        } else {
54            n -= 1; // do not move for 1st character
55            while n > 0 && posi < len as i32 {
56                loop {
57                    // find beginning of next character
58                    posi += 1;
59                    if !iscont(s.add(posi as usize)) {
60                        break;
61                    }
62                } // (cannot pass final '\0')
63                n -= 1;
64            }
65        }
66    }
67
68    if n == 0 {
69        // did it find given character?
70        lua_pushinteger(L, posi + 1);
71    } else {
72        // no such character
73        lua_pushnil(L);
74    }
75    1
76}