if _G.__IMGUI_ENV then setfenv(1, _G.__IMGUI_ENV) end -- [Roblox] shared env, see init.lua --- ImGui Sincerely -- This is a minimal Lua impl of C-like sscanf, sprintf sub-set -- Supports: -- - %x, %X, %nx, %nX (where n is a number) -- - %d, %nd (where n is a number) -- - %f, %lf (very limited) -- -- Returns items_matched instead of EOF on error local _byte = string.byte local CHAR_PERCENT = _byte'%' local CHAR_DOT = _byte'.' local CHAR_PLUS, CHAR_MINUS = _byte'+', _byte'-' local CHAR_0, CHAR_9 = _byte'0', _byte'9' local CHAR_a, CHAR_A = _byte'a', _byte'A' local CHAR_d = _byte'd' local CHAR_l = _byte'l' local CHAR_f, CHAR_F = _byte'f', _byte'F' local CHAR_x, CHAR_X = _byte'x', _byte'X' local function isspace(c) return c == 32 or c == 9 end local function isdigit(c) return c >= CHAR_0 and c <= CHAR_9 end local function isxdigit(c) return isdigit(c) or (c >= CHAR_a and c <= CHAR_f) or (c >= CHAR_A and c <= CHAR_F) end local function isdigit_under_base(c, base) if base == 10 then return isdigit(c) elseif base == 16 then return isxdigit(c) end end local function hex_digit_to_int(c) if c >= CHAR_0 and c <= CHAR_9 then return c - CHAR_0 end if c >= CHAR_a and c <= CHAR_f then return c - CHAR_a + 10 end if c >= CHAR_A and c <= CHAR_F then return c - CHAR_A + 10 end end -- we force this behavior by default local function clamp_if_overflow(spec, val) if spec == CHAR_d or spec == CHAR_x or spec == CHAR_X then if val > INT_MAX then return INT_MAX end if val < INT_MIN then return INT_MIN end end return val end --- @param buffer char[] --- @param buffer_begin int --- @param format string --- @param result table # table to store parsed values local function sscanf(buffer, buffer_begin, format, result) local p = buffer_begin local f = 1 -- format_begin local format_len = #format local assigned = 0 local items_matched = 0 while f <= format_len do repeat if isspace(_byte(format, f, f)) then while isspace(buffer[p]) do p = p + 1 end f = f + 1 break end if _byte(format, f, f) ~= CHAR_PERCENT then if buffer[p] == _byte(format, f, f) then p = p + 1 f = f + 1 else return items_matched end break end -- encountered % in fmt f = f + 1 -- %% if _byte(format, f, f) == CHAR_PERCENT then if buffer[p] == CHAR_PERCENT then p = p + 1 f = f + 1 else return items_matched end break end -- handle optional width local width = 0 while isdigit(_byte(format, f, f)) do width = width * 10 + _byte(format, f, f) - CHAR_0 f = f + 1 end if width == 0 then width = math.huge end local spec = _byte(format, f, f) local base local is_float = false if spec == CHAR_x or spec == CHAR_X then base = 16 elseif spec == CHAR_d then base = 10 elseif spec == CHAR_f or spec == CHAR_F then is_float = true elseif spec == CHAR_l then f = f + 1 if _byte(format, f, f) == CHAR_f then is_float = true -- TODO: distinguish from float? else return items_matched end else return items_matched end f = f + 1 while isspace(buffer[p]) do p = p + 1 end local val if is_float then local sign = 1 if buffer[p] == CHAR_PLUS then p = p + 1 elseif buffer[p] == CHAR_MINUS then sign = -1 p = p + 1 end -- inf, nan are not handled local p_start = p local int_part = 0 while isdigit(buffer[p]) do int_part = int_part * 10 + (buffer[p] - CHAR_0) p = p + 1 end local frac_part = 0 local frac_div = 1 if buffer[p] == CHAR_DOT then p = p + 1 while isdigit(buffer[p]) do frac_part = frac_part * 10 + (buffer[p] - CHAR_0) frac_div = frac_div * 10 p = p + 1 end end if p == p_start then return items_matched end val = sign * (int_part + frac_part / frac_div) else local sign = 1 -- optional sign if base == 10 then if buffer[p] == CHAR_PLUS then p = p + 1 width = width - 1 elseif buffer[p] == CHAR_MINUS then sign = -1 p = p + 1 width = width - 1 end end local p_start = p while width > 0 and buffer[p] and isdigit_under_base(buffer[p], base) do p = p + 1 width = width - 1 end if p == p_start then -- failed to match return items_matched end val = 0 while p_start < p do local c = buffer[p_start] p_start = p_start + 1 val = val * base + sign * hex_digit_to_int(c) local old_val = val val = clamp_if_overflow(spec, val) if old_val ~= val then break end end end result[assigned + 1] = val assigned = assigned + 1 items_matched = items_matched + 1 until true end return items_matched end local function sprintf() end return sscanf