Skip to main content

luaur_vm/functions/
str_split.rs

1use crate::functions::lua_createtable::lua_createtable;
2use crate::functions::lua_l_checklstring::lua_l_checklstring;
3use crate::functions::lua_l_optlstring::lua_l_optlstring;
4use crate::functions::lua_pushinteger::lua_pushinteger;
5use crate::functions::lua_pushlstring::lua_pushlstring;
6use crate::functions::lua_settable::lua_settable;
7use crate::type_aliases::lua_state::lua_State;
8use core::ffi::{c_char, c_int};
9
10#[no_mangle]
11pub unsafe fn str_split(l: *mut lua_State) -> c_int {
12    extern "C" {
13        fn memcmp(s1: *const core::ffi::c_void, s2: *const core::ffi::c_void, n: usize) -> c_int;
14    }
15
16    let mut haystack_len: usize = 0;
17    let haystack = lua_l_checklstring(l, 1, &mut haystack_len);
18    let mut needle_len: usize = 0;
19    let needle = lua_l_optlstring(l, 2, c",".as_ptr() as *const c_char, &mut needle_len);
20
21    let begin = haystack;
22    let end = haystack.add(haystack_len);
23    let mut span_start = begin;
24    let mut num_matches = 0;
25
26    lua_createtable(l, 0, 0);
27
28    let mut iter = begin;
29    if needle_len == 0 {
30        iter = iter.add(1);
31    }
32
33    // Don't iterate the last needleLen - 1 bytes of the string - they are
34    // impossible to be splits and would let us memcmp past the end of the
35    // buffer.
36    while iter <= end.offset(-(needle_len as isize)) {
37        // Use of memcmp here instead of strncmp is so that we allow embedded
38        // nulls to be used in either of the haystack or the needle strings.
39        if memcmp(
40            iter as *const core::ffi::c_void,
41            needle as *const core::ffi::c_void,
42            needle_len,
43        ) == 0
44        {
45            num_matches += 1;
46            lua_pushinteger(l, num_matches);
47            lua_pushlstring(l, span_start, iter.offset_from(span_start) as usize);
48            lua_settable(l, -3);
49
50            span_start = iter.add(needle_len);
51            if needle_len > 0 {
52                iter = iter.add(needle_len - 1);
53            }
54        }
55        iter = iter.add(1);
56    }
57
58    if needle_len > 0 {
59        num_matches += 1;
60        lua_pushinteger(l, num_matches);
61        lua_pushlstring(l, span_start, end.offset_from(span_start) as usize);
62        lua_settable(l, -3);
63    }
64
65    1
66}