diff configmix/_speedups.c @ 656:2b1c7a68f913

Enable indexed access to lists in the configuration using an access path string representation like "~NNN~"
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 30 May 2022 09:31:29 +0200
parents 999cfca55d25
children 193a616e0b3c
line wrap: on
line diff
--- a/configmix/_speedups.c	Sun May 29 15:32:54 2022 +0200
+++ b/configmix/_speedups.c	Mon May 30 09:31:29 2022 +0200
@@ -75,6 +75,54 @@
 }
 
 
+static
+int
+_dec2num(PyObject *s, Py_ssize_t start, Py_ssize_t end, Py_ssize_t *result)
+{
+    Py_ssize_t i;
+    Py_UCS4 c;
+    Py_ssize_t r = 0;
+    int sign = 0;
+
+    for (i=start; i<=end; i++) {
+        /* Overflow error check */
+        if (r > 3275) {
+            PyErr_SetString(PyExc_OverflowError, "index too large");
+            return -1;
+        }
+        r *= 10;
+        c = PyUnicode_ReadChar(s, i);
+        if ((c >= 48) && (c <= 57)) {    /* 0 - 9 */
+            r += (c - 48);
+        }
+        else {
+            if (i == start) {
+                /* check for number sign (but only at the first index) */
+                if (c == 0x2d) {
+                    sign = -1;
+                    continue;
+                }
+                else {
+                    if (c == 0x2b) {
+                        sign = 1;
+                        continue;
+                    }
+                }
+            }
+            PyErr_Format(PyExc_ValueError, "invalid base-10 literal: %c", (int)c);
+            return -1;
+        }
+    }
+    if (sign >= 0) {
+        *result = r;
+    }
+    else {
+        *result = -r;
+    }
+    return 0;  /* success */
+}
+
+
 #if defined(Py_LIMITED_API)
 
 static
@@ -292,6 +340,19 @@
     if (s_len == 0) {
         return Py_NewRef(s);
     }
+    if (s_len > 2) {
+        /* Check for ~NNN~ syntax */
+        c = PyUnicode_ReadChar(s, 0);
+        if (c == 0x7e) {
+            c = PyUnicode_ReadChar(s, s_len - 1);
+            if (c == 0x7e) {
+                if (_dec2num(s, 1, s_len - 2, &i) == 0) {
+                    return PyLong_FromSsize_t(i);
+                }
+                PyErr_Clear();
+            }
+        }
+    }
     find = PyUnicode_FindChar(s, '%', 0, s_len, 1);
     if (find == -2) {
         return NULL;
@@ -429,6 +490,11 @@
 
     s_len = PyUnicode_GetLength(s);
     if (s_len < 0) {
+        if (PyObject_IsInstance(s, (PyObject *)&PyLong_Type)) {
+            PyErr_Clear();
+            return PyUnicode_FromFormat("~%S~", s);
+        }
+        PyErr_SetString(PyExc_TypeError, "given object has no len()");
         return NULL;
     }
     if (s_len == 0) {
@@ -449,6 +515,7 @@
         case 0x7d:
         case 0x5b:
         case 0x5d:
+        case 0x7e:
             need_quoting = 1;
             i = s_len;   /* break the for-loop */
             break;
@@ -1638,7 +1705,7 @@
     PyUnicode_InternInPlace(&(sstate->EMPTY_STR));
 
     sstate->QUOTE_MAP = Py_BuildValue(
-        "{IsIsIsIsIsIsIsIsIsIsIs}",
+        "{IsIsIsIsIsIsIsIsIsIsIsIs}",
         0x25, "%x25",     /* QUOTE: % */
         0x2e, "%x2e",     /* DOT: . */
         0x3a, "%x3a",     /* NS_SEPARATOR: : */
@@ -1649,7 +1716,8 @@
         0x7b, "%x7b",
         0x7d, "%x7d",
         0x5b, "%x5b",
-        0x5d, "%x5d");
+        0x5d, "%x5d",
+        0x7e, "%x7e");    /* tilde ~ */
     if (sstate->QUOTE_MAP == NULL) {
         return -1;
     }