Skip to main content

luaur_analysis/functions/
parse_format_string.rs

1use crate::records::builtin_types::BuiltinTypes;
2use crate::type_aliases::type_id::TypeId;
3use alloc::vec::Vec;
4use core::ffi::c_char;
5use core::ptr::NonNull;
6use core::slice;
7
8pub fn parse_format_string(
9    builtin_types: NonNull<BuiltinTypes>,
10    data: *const c_char,
11    size: usize,
12) -> Vec<TypeId> {
13    let options = b"cdiouxXeEfgGqs*";
14    let data_slice = unsafe { slice::from_raw_parts(data as *const u8, size) };
15    let mut result = Vec::new();
16    let builtin_types = unsafe { builtin_types.as_ref() };
17
18    let mut i = 0;
19    while i < size {
20        if data_slice[i] == b'%' {
21            i += 1;
22
23            if i < size && data_slice[i] == b'%' {
24                i += 1;
25                continue;
26            }
27
28            while i < size
29                && !(data_slice[i] > 0
30                    && (data_slice[i].is_ascii_alphabetic() || data_slice[i] == b'*'))
31            {
32                i += 1;
33            }
34
35            if i == size {
36                break;
37            }
38
39            let c = data_slice[i];
40            if c == b'q' || c == b's' {
41                result.push(builtin_types.stringType);
42            } else if c == b'*' {
43                result.push(builtin_types.unknownType);
44            } else if options.contains(&c) {
45                result.push(builtin_types.numberType);
46            } else {
47                result.push(builtin_types.error_recovery_type(builtin_types.anyType));
48            }
49        }
50        i += 1;
51    }
52
53    result
54}