lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Hi All,

I've made a patch to lua that I thought may come in handy for embedded
use cases. It essentially adds a lua_State argument to

- lua_writestring
- lua_writestringerror
- lua_writeline

and subsequently modifies all occurrences of the api in the source
code to add the state. For a standard lua installation this doesn't
change anything. Now the writestring methods could access lua state to
make more flexible output handling.

My use case is when spawning many independent lua states that write
output to a string instead of stdout/stderr. I have a custom callback
that is stored in the registry that is accessed inside of my
lua_writestring and lua_writestringerror functions.

The only area I'm not sure on is passing NULL when lua state fails to allocate:
l_message(NULL, argv[0], "cannot create state: not enough memory");

Maybe it would be best to make a separate API call in the patch
instead of using l_message? That way users don't have to do a NULL
check.

diff -urN lua/src/lauxlib.c lua_new/src/lauxlib.c
--- lua/src/lauxlib.c    2022-01-13 03:24:40.000000000 -0800
+++ lua_new/src/lauxlib.c    2023-02-18 17:22:23.000000000 -0800
@@ -1022,7 +1022,7 @@
 static int panic (lua_State *L) {
   const char *msg = lua_tostring(L, -1);
   if (msg == NULL) msg = "error object is not a string";
-  lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n",
+  lua_writestringerror(L, "PANIC: unprotected error in call to Lua API (%s)\n",
                         msg);
   return 0;  /* return to Lua to abort */
 }
@@ -1067,11 +1067,11 @@
 */
 static void warnfcont (void *ud, const char *message, int tocont) {
   lua_State *L = (lua_State *)ud;
-  lua_writestringerror("%s", message);  /* write message */
+  lua_writestringerror(L, "%s", message);  /* write message */
   if (tocont)  /* not the last part? */
     lua_setwarnf(L, warnfcont, L);  /* to be continued */
   else {  /* last part */
-    lua_writestringerror("%s", "\n");  /* finish message with end-of-line */
+    lua_writestringerror(L, "%s", "\n");  /* finish message with end-of-line */
     lua_setwarnf(L, warnfon, L);  /* next call is a new message */
   }
 }
@@ -1080,7 +1080,7 @@
 static void warnfon (void *ud, const char *message, int tocont) {
   if (checkcontrol((lua_State *)ud, message, tocont))  /* control message? */
     return;  /* nothing else to be done */
-  lua_writestringerror("%s", "Lua warning: ");  /* start a new warning */
+  lua_writestringerror((lua_State *)ud, "%s", "Lua warning: ");  /*
start a new warning */
   warnfcont(ud, message, tocont);  /* finish processing */
 }

diff -urN lua/src/lauxlib.h lua_new/src/lauxlib.h
--- lua/src/lauxlib.h    2022-01-13 03:24:40.000000000 -0800
+++ lua_new/src/lauxlib.h    2023-02-18 17:23:24.000000000 -0800
@@ -257,18 +257,19 @@

 /* print a string */
 #if !defined(lua_writestring)
-#define lua_writestring(s,l)   fwrite((s), sizeof(char), (l), stdout)
+#define lua_writestring(L,s,l)  \
+        ((void)L, fwrite((s), sizeof(char), (l), stdout))
 #endif

 /* print a newline and flush the output */
 #if !defined(lua_writeline)
-#define lua_writeline()        (lua_writestring("\n", 1), fflush(stdout))
+#define lua_writeline(L)        (lua_writestring(L, "\n", 1), fflush(stdout))
 #endif

 /* print an error message */
 #if !defined(lua_writestringerror)
-#define lua_writestringerror(s,p) \
-        (fprintf(stderr, (s), (p)), fflush(stderr))
+#define lua_writestringerror(L,s,p) \
+        ((void)L, fprintf(stderr, (s), (p)), fflush(stderr))
 #endif

 /* }================================================================== */
diff -urN lua/src/lbaselib.c lua_new/src/lbaselib.c
--- lua/src/lbaselib.c    2022-01-13 03:24:40.000000000 -0800
+++ lua_new/src/lbaselib.c    2023-02-18 17:01:13.000000000 -0800
@@ -28,11 +28,11 @@
     size_t l;
     const char *s = luaL_tolstring(L, i, &l);  /* convert it to string */
     if (i > 1)  /* not the first element? */
-      lua_writestring("\t", 1);  /* add a tab before it */
-    lua_writestring(s, l);  /* print it */
+      lua_writestring(L, "\t", 1);  /* add a tab before it */
+    lua_writestring(L, s, l);  /* print it */
     lua_pop(L, 1);  /* pop result */
   }
-  lua_writeline();
+  lua_writeline(L);
   return 0;
 }

diff -urN lua/src/ldblib.c lua_new/src/ldblib.c
--- lua/src/ldblib.c    2022-01-13 03:24:41.000000000 -0800
+++ lua_new/src/ldblib.c    2023-02-18 17:01:13.000000000 -0800
@@ -420,13 +420,13 @@
 static int db_debug (lua_State *L) {
   for (;;) {
     char buffer[250];
-    lua_writestringerror("%s", "lua_debug> ");
+    lua_writestringerror(L, "%s", "lua_debug> ");
     if (fgets(buffer, sizeof(buffer), stdin) == NULL ||
         strcmp(buffer, "cont\n") == 0)
       return 0;
     if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
         lua_pcall(L, 0, 0, 0))
-      lua_writestringerror("%s\n", luaL_tolstring(L, -1, NULL));
+      lua_writestringerror(L, "%s\n", luaL_tolstring(L, -1, NULL));
     lua_settop(L, 0);  /* remove eventual returns */
   }
 }
diff -urN lua/src/lua.c lua_new/src/lua.c
--- lua/src/lua.c    2022-01-13 03:24:43.000000000 -0800
+++ lua_new/src/lua.c    2023-02-18 17:02:12.000000000 -0800
@@ -80,13 +80,13 @@
 }


-static void print_usage (const char *badoption) {
-  lua_writestringerror("%s: ", progname);
+static void print_usage (lua_State *L, const char *badoption) {
+  lua_writestringerror(L, "%s: ", progname);
   if (badoption[1] == 'e' || badoption[1] == 'l')
-    lua_writestringerror("'%s' needs argument\n", badoption);
+    lua_writestringerror(L, "'%s' needs argument\n", badoption);
   else
-    lua_writestringerror("unrecognized option '%s'\n", badoption);
-  lua_writestringerror(
+    lua_writestringerror(L, "unrecognized option '%s'\n", badoption);
+  lua_writestringerror(L,
   "usage: %s [options] [script [args]]\n"
   "Available options are:\n"
   "  -e stat   execute string 'stat'\n"
@@ -107,9 +107,9 @@
 ** Prints an error message, adding the program name in front of it
 ** (if present)
 */
-static void l_message (const char *pname, const char *msg) {
-  if (pname) lua_writestringerror("%s: ", pname);
-  lua_writestringerror("%s\n", msg);
+static void l_message (lua_State *L, const char *pname, const char *msg) {
+  if (pname) lua_writestringerror(L, "%s: ", pname);
+  lua_writestringerror(L, "%s\n", msg);
 }


@@ -121,7 +121,7 @@
 static int report (lua_State *L, int status) {
   if (status != LUA_OK) {
     const char *msg = lua_tostring(L, -1);
-    l_message(progname, msg);
+    l_message(L, progname, msg);
     lua_pop(L, 1);  /* remove message */
   }
   return status;
@@ -164,9 +164,9 @@
 }


-static void print_version (void) {
-  lua_writestring(LUA_COPYRIGHT, strlen(LUA_COPYRIGHT));
-  lua_writeline();
+static void print_version (lua_State *L) {
+  lua_writestring(L, LUA_COPYRIGHT, strlen(LUA_COPYRIGHT));
+  lua_writeline(L);
 }


@@ -571,7 +571,7 @@
     lua_getglobal(L, "print");
     lua_insert(L, 1);
     if (lua_pcall(L, n, 0, 0) != LUA_OK)
-      l_message(progname, lua_pushfstring(L, "error calling 'print' (%s)",
+      l_message(L, progname, lua_pushfstring(L, "error calling 'print' (%s)",
                                              lua_tostring(L, -1)));
   }
 }
@@ -593,7 +593,7 @@
     else report(L, status);
   }
   lua_settop(L, 0);  /* clear stack */
-  lua_writeline();
+  lua_writeline(L);
   progname = oldprogname;
 }

@@ -612,11 +612,11 @@
   luaL_checkversion(L);  /* check that interpreter has correct version */
   if (argv[0] && argv[0][0]) progname = argv[0];
   if (args == has_error) {  /* bad arg? */
-    print_usage(argv[script]);  /* 'script' has index of bad arg. */
+    print_usage(L, argv[script]);  /* 'script' has index of bad arg. */
     return 0;
   }
   if (args & has_v)  /* option '-v'? */
-    print_version();
+    print_version(L);
   if (args & has_E) {  /* option '-E'? */
     lua_pushboolean(L, 1);  /* signal for libraries to ignore env. vars. */
     lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
@@ -637,7 +637,7 @@
     doREPL(L);  /* do read-eval-print loop */
   else if (script == argc && !(args & (has_e | has_v))) {  /* no arguments? */
     if (lua_stdin_is_tty()) {  /* running in interactive mode? */
-      print_version();
+      print_version(L);
       doREPL(L);  /* do read-eval-print loop */
     }
     else dofile(L, NULL);  /* executes stdin as a file */
@@ -651,7 +651,7 @@
   int status, result;
   lua_State *L = luaL_newstate();  /* create state */
   if (L == NULL) {
-    l_message(argv[0], "cannot create state: not enough memory");
+    l_message(NULL, argv[0], "cannot create state: not enough memory");
     return EXIT_FAILURE;
   }
   lua_pushcfunction(L, &pmain);  /* to call 'pmain' in protected mode */