lua_pushfstring should support the "%.*s" format

"[email protected]" <[email protected]> Wed, 24 Jun 2026 05:31:11 -0700 (PDT)
Newsgroups gmane.comp.lang.lua.general
Message-ID <[email protected]>
Hi,

Cheap substrings, embedded \0s, strings with explicit length - I'd like 
that.
Can we have this merged? (and having e.g. "%.3f" would be nice too)

Thanks,
Z

-- 
You received this message because you are subscribed to the Google Groups "lua-l" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To view this discussion visit https://groups.google.com/d/msgid/lua-l/0b3c33e3-a35e-4c4e-afea-677f391d38f3n%40googlegroups.com.
pushfstring_with_string_length.patch (text/x-patch, 1.9 KB)
--- a/src/lobject.c
+++ b/src/lobject.c
@@ -596,16 +596,31 @@
 const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
   BuffFS buff;  /* holds last part of the result */
   const char *e;  /* points to next '%' */
   initbuff(L, &buff);
   while ((e = strchr(fmt, '%')) != NULL) {
+    int prec = -1;
     addstr2buff(&buff, fmt, ct_diff2sz(e - fmt));  /* add 'fmt' up to '%' */
-    switch (*(e + 1)) {  /* conversion specifier */
-      case 's': {  /* zero-terminated string */
+
+    fmt = e + 1;  /* skip '%' */
+    if (*fmt == '.') {  /* precision specifier */
+      fmt++;
+      if (*fmt == '*') {
+        fmt++;
+        prec = va_arg(argp, int);
+      } else {
+        char *tmp;
+        prec = strtol(fmt, &tmp, 10);
+        fmt = tmp;
+      }
+    }
+
+    switch (*fmt++) {  /* conversion specifier */
+      case 's': {  /* string */
         const char *s = va_arg(argp, char *);
         if (s == NULL) s = "(null)";
-        addstr2buff(&buff, s, strlen(s));
+        addstr2buff(&buff, s, prec >= 0 ? (size_t)prec : strlen(s));
         break;
       }
       case 'c': {  /* an 'int' as a character */
         char c = cast_char(va_arg(argp, int));
         addstr2buff(&buff, &c, sizeof(char));
@@ -641,20 +656,16 @@
         unsigned long arg = va_arg(argp, unsigned long);
         int len = luaO_utf8esc(bf, cast(l_uint32, arg));
         addstr2buff(&buff, bf + UTF8BUFFSZ - len, cast_uint(len));
         break;
       }
-      case '%': {
-        addstr2buff(&buff, "%", 1);
-        break;
-      }
+      case '%': e++;  /* fall-thru */
       default: {
-        addstr2buff(&buff, e, 2);  /* keep unknown format in the result */
+        addstr2buff(&buff, e, ct_diff2sz(fmt - e));  /* add format to result */
         break;
       }
     }
-    fmt = e + 2;  /* skip '%' and the specifier */
   }
   addstr2buff(&buff, fmt, strlen(fmt));  /* rest of 'fmt' */
   return clearbuff(&buff);  /* empty buffer into a new string */
 }