add picoterm.sscanf

This commit is contained in:
blueloveTH 2025-11-27 14:41:13 +08:00
parent 6f9b7943d4
commit 0b91c2968b
3 changed files with 65 additions and 0 deletions

View File

@ -6,3 +6,5 @@ def split_ansi_escaped_string(s: str) -> list[str]:
def wcwidth(c: int) -> int: ...
def wcswidth(s: str) -> int: ...
def sscanf(s: str, fmt: str, out_list: list) -> bool: ...

View File

@ -89,6 +89,56 @@ static bool picoterm_wcswidth(int argc, py_Ref argv) {
return true;
}
static bool picoterm_sscanf(int argc, py_Ref argv) {
PY_CHECK_ARGC(3);
PY_CHECK_ARG_TYPE(0, tp_str);
PY_CHECK_ARG_TYPE(1, tp_str);
PY_CHECK_ARG_TYPE(2, tp_list);
const char* input = py_tostr(py_arg(0));
const char* format = py_tostr(py_arg(1));
py_Ref output_list = py_arg(2);
py_list_clear(output_list);
const char* p1 = input;
const char* p2 = format;
while(*p1 != '\0' && *p2 != '\0') {
if(*p2 == '%') {
p2++;
if(*p2 == 'd' || *p2 == 'i') {
bool negative = false;
if(*p1 == '-') {
negative = true;
p1++;
}
const char* start = p1;
while(*p1 >= '0' && *p1 <= '9')
p1++;
c11_sv num_sv = {.data = start, .size = p1 - start};
if(num_sv.size == 0) break;
int64_t value = 0;
IntParsingResult res = c11__parse_uint(num_sv, &value, 10);
if(res != IntParsing_SUCCESS) break;
if(negative) value = -value;
py_ItemRef item = py_list_emplace(output_list);
py_newint(item, value);
p2++;
} else {
return ValueError("unsupported format specifier: %%%c", *p2);
}
} else {
if(*p1 != *p2) break;
p1++;
p2++;
}
}
py_newbool(py_retval(), *p2 == '\0');
return true;
}
void pk__add_module_picoterm() {
py_Ref mod = py_newmodule("picoterm");
@ -96,6 +146,7 @@ void pk__add_module_picoterm() {
py_bindfunc(mod, "split_ansi_escaped_string", picoterm_split_ansi_escaped_string);
py_bindfunc(mod, "wcwidth", picoterm_wcwidth);
py_bindfunc(mod, "wcswidth", picoterm_wcswidth);
py_bindfunc(mod, "sscanf", picoterm_sscanf);
}
static bool split_ansi_escaped_string(c11_sv sv, c11_vector* out_tokens) {

View File

@ -28,3 +28,15 @@ assert picoterm.wcwidth(ord('测')) == 2
assert picoterm.wcwidth(ord('👀')) == 2
assert picoterm.wcswidth("hello, 测试a测试👀测\n") == 7 + 1 + 12
text = rgb(12, 34, 56).ansi_fg("hello")
out_list = []
assert picoterm.sscanf(text, "\x1b[38;2;%d;%d;%dm", out_list)
assert out_list == [12, 34, 56]
assert picoterm.sscanf(text, "\x1b[38;2;%d;%d;%dmhello", out_list)
assert out_list == [12, 34, 56]
assert picoterm.sscanf(text, "\x1b[38;2;%d;%d;%d", out_list)
assert not picoterm.sscanf(text, "\x1b[38;2;%d;%d;%dm???", out_list)
assert not picoterm.sscanf(text, "\x1b[77;2;%d;%d;%dm", out_list)