@@ -770,6 +770,35 @@ pub const Lua = opaque {
770770 }
771771 }
772772
773+ /// Pushes onto the stack a formatted string and returns a pointer to this string. Memory allocation is handled
774+ /// by Lua via garbage collection, callers do NOT own the returned slice.
775+ ///
776+ /// String format specifiers are restricted to the following options:
777+ /// * '%%' - Insert a literal '%' character in the string.
778+ /// * '%s' - Insert a zero-terminated string,
779+ /// * '%f' - Insert a `Lua.Number`, usually an `f64`,
780+ /// * '%p' - Insert a pointer-width ineger formatted as hexadecimal,
781+ /// * '%d' - Insert a `Lua.Integer`, usually an `i64`, and
782+ /// * '%c' - Insert a single character represented by a number.
783+ ///
784+ /// **Usage of this function is discouraged**, consider instead using Zig `std.fmt` primitives in combination with
785+ /// `lua.pushString()` or `lua.pushLString()`.
786+ ///
787+ /// From: `const char *lua_pushfstring(lua_State *L, const char *fmt, ...);`
788+ /// Refer to: https://www.lua.org/manual/5.1/manual.html#lua_pushfstring
789+ /// Stack Behavior: `[-0, +1, m]`
790+ pub fn pushFString (lua : * Lua , comptime format : []const u8 , args : anytype ) [:0 ]const u8 {
791+ const string : ? [* :0 ]const u8 = @call (.auto , c .lua_pushfstring , .{ asState (lua ), format .ptr } ++ args );
792+ if (string ) | s | {
793+ // NOTE: This seems dangerous. I don't really like this solution, but it doesn't look like there is any other option.
794+ // We are making a strong assumption that Lua returns a well-behaved zero-terminated string.
795+ const len = std .mem .indexOfSentinel (u8 , 0 , s );
796+ return s [0.. len :0 ];
797+ } else {
798+ std .debug .panic ("Received unexpected NULL response from lua.pushFString(\" {s}, ...\" )" , .{format });
799+ }
800+ }
801+
773802 fn typeIsNotString (t : Lua.Type ) NotStringError {
774803 return switch (t ) {
775804 .number , .string = > unreachable ,
@@ -1703,6 +1732,16 @@ test "slices strings" {
17031732 lua .pop (1 );
17041733}
17051734
1735+ test "string formatting with pushFString" {
1736+ const lua = try Lua .init (std .testing .allocator );
1737+ defer lua .deinit ();
1738+
1739+ const expected : [:0 ]const u8 = "abc%_FOO_42" ;
1740+ const actual = lua .pushFString ("abc%%_%s_%d" , .{ "FOO" , @as (i32 , 42 ) });
1741+
1742+ try std .testing .expectEqualSlices (u8 , expected , actual );
1743+ }
1744+
17061745test "slices strings to terminated strings" {
17071746 const lua = try Lua .init (std .testing .allocator );
17081747 defer lua .deinit ();
0 commit comments