Changes in the warning system

- The warning functions get an extra parameter that tells whether
message is to be continued (instead of using end-of-lines as a signal).

- The user data for the warning function is a regular value, instead
of a writable slot inside the Lua state.
diff --git a/lapi.c b/lapi.c
index 66d7564..06396ad 100644
--- a/lapi.c
+++ b/lapi.c
@@ -1286,9 +1286,9 @@
 }
 
 
-void lua_warning (lua_State *L, const char *msg) {
+void lua_warning (lua_State *L, const char *msg, int tocont) {
   lua_lock(L);
-  luaE_warning(L, msg);
+  luaE_warning(L, msg, tocont);
   lua_unlock(L);
 }
 
diff --git a/lauxlib.c b/lauxlib.c
index abf923f..e9c02d3 100644
--- a/lauxlib.c
+++ b/lauxlib.c
@@ -987,33 +987,29 @@
 
 
 /*
-** checks whether 'message' ends with end-of-line
-** (and therefore is the last part of a warning)
+** Emit a warning. '*previoustocont' signals whether previous message
+** was to be continued by the current one.
 */
-static int islast (const char *message) {
-  size_t len = strlen(message);
-  return (len > 0 && message[len - 1] == '\n');
-}
-
-
-/*
-** Emit a warning. If '*pud' is NULL, previous message was to be
-** continued by the current one.
-*/
-static void warnf (void **pud, const char *message) {
-  if (*pud == NULL)  /* previous message was not the last? */
-    lua_writestringerror("%s", message);
-  else  /* start a new warning */
-    lua_writestringerror("Lua warning: %s", message);
-  *pud = (islast(message)) ? pud : NULL;
+static void warnf (void *ud, const char *message, int tocont) {
+  int *previoustocont = (int *)ud;
+  if (!*previoustocont)  /* previous message was the last? */
+    lua_writestringerror("%s", "Lua warning: ");  /* start a new warning */
+  lua_writestringerror("%s", message);  /* write message */
+  if (!tocont)  /* is this the last part? */
+    lua_writestringerror("%s", "\n");  /* finish message with end-of-line */
+  *previoustocont = tocont;
 }
 
 
 LUALIB_API lua_State *luaL_newstate (void) {
   lua_State *L = lua_newstate(l_alloc, NULL);
   if (L) {
+    int *previoustocont;  /* space for warning state */
     lua_atpanic(L, &panic);
-    lua_setwarnf(L, warnf, L);
+    previoustocont = (int *)lua_newuserdatauv(L, sizeof(int), 0);
+    luaL_ref(L, LUA_REGISTRYINDEX);  /* make sure it won't be collected */
+    *previoustocont = 0;  /* next message starts a new warning */
+    lua_setwarnf(L, warnf, previoustocont);
   }
   return L;
 }
diff --git a/lbaselib.c b/lbaselib.c
index 26683a1..d4b619a 100644
--- a/lbaselib.c
+++ b/lbaselib.c
@@ -45,7 +45,7 @@
 
 static int luaB_warn (lua_State *L) {
   const char *msg = luaL_checkstring(L, 1);
-  lua_warning(L, msg);
+  lua_warning(L, msg, lua_toboolean(L, 2));
   return 0;
 }
 
diff --git a/lgc.c b/lgc.c
index bf0460d..c834319 100644
--- a/lgc.c
+++ b/lgc.c
@@ -832,7 +832,7 @@
   lua_assert(!g->gcemergency);
   setgcovalue(L, &v, udata2finalize(g));
   tm = luaT_gettmbyobj(L, &v, TM_GC);
-  if (tm != NULL && ttisfunction(tm)) {  /* is there a finalizer? */
+  if (ttisfunction(tm)) {  /* is the finalizer a function? */
     int status;
     lu_byte oldah = L->allowhook;
     int running  = g->gcrunning;
@@ -850,9 +850,9 @@
       const char *msg = (ttisstring(s2v(L->top - 1)))
                         ? svalue(s2v(L->top - 1))
                         : "error object is not a string";
-      luaE_warning(L, "error in __gc metamethod (");
-      luaE_warning(L, msg);
-      luaE_warning(L, ")\n");
+      luaE_warning(L, "error in __gc metamethod (", 1);
+      luaE_warning(L, msg, 1);
+      luaE_warning(L, ")", 0);
     }
   }
 }
diff --git a/lstate.c b/lstate.c
index 6c35ea1..f5579a6 100644
--- a/lstate.c
+++ b/lstate.c
@@ -411,10 +411,10 @@
 }
 
 
-void luaE_warning (lua_State *L, const char *msg) {
+void luaE_warning (lua_State *L, const char *msg, int tocont) {
   lua_WarnFunction wf = G(L)->warnf;
   if (wf != NULL)
-    wf(&G(L)->ud_warn, msg);
+    wf(G(L)->ud_warn, msg, tocont);
 }
 
 
diff --git a/lstate.h b/lstate.h
index 11bf18f..e35f896 100644
--- a/lstate.h
+++ b/lstate.h
@@ -317,7 +317,7 @@
 LUAI_FUNC void luaE_freeCI (lua_State *L);
 LUAI_FUNC void luaE_shrinkCI (lua_State *L);
 LUAI_FUNC void luaE_enterCcall (lua_State *L);
-LUAI_FUNC void luaE_warning (lua_State *L, const char *msg);
+LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont);
 
 
 #define luaE_exitCcall(L)	((L)->nCcalls--)
diff --git a/ltests.c b/ltests.c
index 2337538..40de229 100644
--- a/ltests.c
+++ b/ltests.c
@@ -63,11 +63,8 @@
 }
 
 
-static void badexit (const char *fmt, ...) {
-  va_list argp;
-  va_start(argp, fmt);
-  vfprintf(stderr, fmt, argp);
-  va_end(argp);
+static void badexit (const char *fmt, const char *s) {
+  fprintf(stderr, fmt, s);
   /* avoid assertion failures when exiting */
   l_memcontrol.numblocks = l_memcontrol.total = 0;
   exit(EXIT_FAILURE);
@@ -81,52 +78,35 @@
 }
 
 
-static int islast (const char *message) {
-  size_t len = strlen(message);
-  return (len > 0 && message[len - 1] == '\n');
-}
-
-
 /*
 ** Warning function for tests. Fist, it concatenates all parts of
 ** a warning in buffer 'buff'. Then:
-** messages starting with '#' are shown on standard output (used to
+** - messages starting with '#' are shown on standard output (used to
 ** test explicit warnings);
-** messages containing '@' are stored in global '_WARN' (used to test
+** - messages containing '@' are stored in global '_WARN' (used to test
 ** errors that generate warnings);
-** other messages abort the tests (they represent real warning conditions;
-** the standard tests should not generate these conditions unexpectedly).
+** - other messages abort the tests (they represent real warning
+** conditions; the standard tests should not generate these conditions
+** unexpectedly).
 */
-static void warnf (void **pud, const char *msg) {
-  static char buff[200];  /* should be enough for tests... */
-  static int cont = 0;  /* message to be continued */
-  if (cont) {  /* continuation? */
-    if (strlen(msg) >= sizeof(buff) - strlen(buff))
-      badexit("warnf-buffer overflow");
-    strcat(buff, msg);  /* add new message to current warning */
-  }
-  else {  /* new warning */
-    if (strlen(msg) >= sizeof(buff))
-      badexit("warnf-buffer overflow");
-    strcpy(buff, msg);  /* start a new warning */
-  }
-  if (!islast(msg))  /* message not finished yet? */
-    cont = 1;  /* wait for more */
-  else {  /* handle message */
-    cont = 0;  /* prepare for next message */
+static void warnf (void *ud, const char *msg, int tocont) {
+  static char buff[200] = "";  /* should be enough for tests... */
+  if (strlen(msg) >= sizeof(buff) - strlen(buff))
+    badexit("%s", "warnf-buffer overflow");
+  strcat(buff, msg);  /* add new message to current warning */
+  if (!tocont) {  /* message finished? */
     if (buff[0] == '#')  /* expected warning? */
-      printf("Expected Lua warning: %s", buff);  /* print it */
+      printf("Expected Lua warning: %s\n", buff);  /* print it */
     else if (strchr(buff, '@') != NULL) {  /* warning for test purposes? */
-      lua_State *L = cast(lua_State *, *pud);
+      lua_State *L = cast(lua_State *, ud);
       lua_unlock(L);
       lua_pushstring(L, buff);
       lua_setglobal(L, "_WARN");  /* assign message to global '_WARN' */
       lua_lock(L);
-      return;
     }
-    else {  /* a real warning; should not happen during tests */
+    else  /* a real warning; should not happen during tests */
       badexit("Unexpected warning in test mode: %s\naborting...\n", buff);
-    }
+    buff[0] = '\0';  /* prepare buffer for next warning */
   }
 }
 
@@ -1466,9 +1446,13 @@
       const char *msg = getstring;
       printf("%s\n", msg);
     }
+    else if EQ("warningC") {
+      const char *msg = getstring;
+      lua_warning(L1, msg, 1);
+    }
     else if EQ("warning") {
       const char *msg = getstring;
-      lua_warning(L1, msg);
+      lua_warning(L1, msg, 0);
     }
     else if EQ("pushbool") {
       lua_pushboolean(L1, getnum);
diff --git a/lua.h b/lua.h
index b777624..09611db 100644
--- a/lua.h
+++ b/lua.h
@@ -128,7 +128,7 @@
 /*
 ** Type for warning functions
 */
-typedef void (*lua_WarnFunction) (void **pud, const char *msg);
+typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont);
 
 
 
@@ -309,7 +309,7 @@
 ** Warning-related functions
 */
 LUA_API void (lua_setwarnf) (lua_State *L, lua_WarnFunction f, void *ud);
-LUA_API void (lua_warning)  (lua_State *L, const char *msg);
+LUA_API void (lua_warning)  (lua_State *L, const char *msg, int tocont);
 
 
 /*
diff --git a/manual/manual.of b/manual/manual.of
index b47fd86..63e78f9 100644
--- a/manual/manual.of
+++ b/manual/manual.of
@@ -4061,7 +4061,7 @@
 
 Sets the @x{warning function} to be used by Lua to emit warnings
 @see{lua_WarnFunction}.
-The @id{ud} parameter initializes the slot @id{pud} passed to
+The @id{ud} parameter sets the value @id{ud} passed to
 the warning function.
 
 }
@@ -4325,25 +4325,24 @@
 }
 
 @APIEntry{
-typedef void (*lua_WarnFunction) (void **pud, const char *msg);|
+typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont);|
 
 The type of @x{warning function}s, called by Lua to emit warnings.
-The first parameter is the address of a writable slot,
-constant for a given Lua state and
-initialized by @Lid{lua_setwarnf}.
+The first parameter is an opaque pointer
+set by @Lid{lua_setwarnf}.
 The second parameter is the warning message.
-This function should assume that
-a message not ending with an end-of-line will be
-continued by the message in the next call.
+The third parameter is a boolean that
+indicates whether the message is
+to be continued by the message in the next call.
 
 }
 
 @APIEntry{
-void lua_warning (lua_State *L, const char *msg);|
+void lua_warning (lua_State *L, const char *msg, int tocont);|
 @apii{0,0,-}
 
 Emits a warning with the given message.
-A message not ending with an end-of-line should be
+A message in a call with @id{tocont} true should be
 continued in another call to this function.
 
 }
@@ -6275,11 +6274,12 @@
 
 }
 
-@LibEntry{warn (message)|
+@LibEntry{warn (message [, tocont])|
 
 Emits a warning with the given message.
-Note that messages not ending with an end-of-line
-are assumed to be continued by the message in the next call.
+A message in a call with @id{tocont} true should be
+continued in another call to this function.
+The default for @id{tocont} is false.
 
 }
 
diff --git a/testes/all.lua b/testes/all.lua
index 506afad..8d727b6 100644
--- a/testes/all.lua
+++ b/testes/all.lua
@@ -6,7 +6,7 @@
 local version = "Lua 5.4"
 if _VERSION ~= version then
   warn(string.format(
-   "This test suite is for %s, not for %s\nExiting tests\n", version, _VERSION))
+   "This test suite is for %s, not for %s\nExiting tests", version, _VERSION))
   return
 end
 
@@ -190,16 +190,16 @@
 dofile('files.lua')
 
 if #msgs > 0 then
-  warn("#tests not performed:\n  ")
+  warn("#tests not performed:", true)
   for i=1,#msgs do
-    warn(msgs[i]); warn("\n  ")
+    warn("\n  ", true); warn(msgs[i], true)
   end
   warn("\n")
 end
 
 print("(there should be two warnings now)")
-warn("#This is "); warn("an expected"); warn(" warning\n")
-warn("#This is"); warn(" another one\n")
+warn("#This is ", true); warn("an expected", true); warn(" warning")
+warn("#This is", true); warn(" another one")
 
 -- no test module should define 'debug'
 assert(debug == nil)
diff --git a/testes/api.lua b/testes/api.lua
index d034ea8..08672e8 100644
--- a/testes/api.lua
+++ b/testes/api.lua
@@ -114,13 +114,11 @@
 
 -- testing warnings
 T.testC([[
-  warning "#This shold be a"
-  warning " single "
-  warning "warning
-"
-  warning "#This should be "
-  warning "another one
-"
+  warningC "#This shold be a"
+  warningC " single "
+  warning "warning"
+  warningC "#This should be "
+  warning "another one"
 ]])
 
 
diff --git a/testes/gc.lua b/testes/gc.lua
index 05bf564..91e78a4 100644
--- a/testes/gc.lua
+++ b/testes/gc.lua
@@ -18,6 +18,8 @@
 assert(collectgarbage("incremental") == "incremental")
 
 
+local function nop () end
+
 local function gcinfo ()
   return collectgarbage"count" * 1024
 end
@@ -388,7 +390,7 @@
   collectgarbage()
   for i = 1, 10 do assert(s[i]) end
 
-  getmetatable(u).__gc = false
+  getmetatable(u).__gc = nil
 
 end
 print '+'
@@ -604,8 +606,8 @@
   collectgarbage("stop")
   local x = T.newuserdata(0)
   local y = T.newuserdata(0)
-  debug.setmetatable(y, {__gc = true})   -- bless the new udata before...
-  debug.setmetatable(x, {__gc = true})   -- ...the old one
+  debug.setmetatable(y, {__gc = nop})   -- bless the new udata before...
+  debug.setmetatable(x, {__gc = nop})   -- ...the old one
   assert(T.gccolor(y) == "white")
   T.checkmemory()
   collectgarbage("restart")
@@ -631,6 +633,7 @@
   assert(T.totalmem("thread") == t + 1)
 end
 
+
 -- create an object to be collected when state is closed
 do
   local setmetatable,assert,type,print,getmetatable =
@@ -650,7 +653,7 @@
 
 -- create several objects to raise errors when collected while closing state
 if T then
-  local error, assert, warn, find = error, assert, warn, string.find
+  local error, assert, find = error, assert, string.find
   local n = 0
   local lastmsg
   local mt = {__gc = function (o)