Sfoglia il codice sorgente

add `picoterm.sscanf`

blueloveTH 3 mesi fa
parent
commit
0b91c2968b
3 ha cambiato i file con 65 aggiunte e 0 eliminazioni
  1. 2 0
      include/typings/picoterm.pyi
  2. 51 0
      src/modules/picoterm.c
  3. 12 0
      tests/92_picoterm.py

+ 2 - 0
include/typings/picoterm.pyi

@@ -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: ...

+ 51 - 0
src/modules/picoterm.c

@@ -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) {

+ 12 - 0
tests/92_picoterm.py

@@ -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)