text: /*
  ** $Id: lauxlib.c,v 1.289.1.1 2017/04/19 17:20:42 roberto Exp $
  ** Auxiliary functions for building Lua libraries
  ** See Copyright Notice in lua.h
  */
  
  #define lauxlib_c
  #define LUA_LIB
  
  
  #include <errno.h>
  #include <stdarg.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  
  
  /*
  ** This file uses only the official API of Lua.
  ** Any function declared here could be written as an application function.
  */
  
  #include "lua.h"
  
  #include "lauxlib.h"
  
  
  /*
  ** {======================================================
  ** Traceback
  ** =======================================================
  */
  
  
  #define LEVELS1    10    /* size of the first part of the stack */
  #define LEVELS2    11    /* size of the second part of the stack */
  
  
  /*
  ** search for 'objidx' in table at index -1.
  ** return 1 + string at top if find a good name.
  */
  static int findfield(lua_State *L, int objidx, int level) {
      if (level == 0 || !lua_istable(L, -1))
          return 0;  /* not found */
      lua_pushnil(L);  /* start 'next' loop */
      while (lua_next(L, -2)) {  /* for each pair in table */
          if (lua_type(L, -2) == LUA_TSTRING) {  /* ignore non-string keys */
              if (lua_rawequal(L, objidx, -1)) {  /* found object? */
                  lua_pop(L, 1);  /* remove value (but keep name) */
                  return 1;
              } else if (findfield(L, objidx, level - 1)) {  /* try recursively */
                  lua_remove(L, -2);  /* remove table (but keep name) */
                  lua_pushliteral(L, ".");
                  lua_insert(L, -2);  /* place '.' between the two names */
                  lua_concat(L, 3);
                  return 1;
              }
          }
          lua_pop(L, 1);  /* remove value */
      }
      return 0;  /* not found */
  }
  
  
  /*
  ** Search for a name for a function in all loaded modules
  */
  static int pushglobalfuncname(lua_State *L, lua_Debug *ar) {
      int top = lua_gettop(L);
      lua_getinfo(L, "f", ar);  /* push function */
      lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
      if (findfield(L, top + 1, 2)) {
          const char *name = lua_tostring(L, -1);
          if (strncmp(name, "_G.", 3) == 0) {  /* name start with '_G.'? */
              lua_pushstring(L, name + 3);  /* push name without prefix */
              lua_remove(L, -2);  /* remove original name */
          }
          lua_copy(L, -1, top + 1);  /* move name to proper place */
          lua_pop(L, 2);  /* remove pushed values */
          return 1;
      } else {
          lua_settop(L, top);  /* remove function and global table */
          return 0;
      }
  }
  
  
  static void pushfuncname(lua_State *L, lua_Debug *ar) {
      if (pushglobalfuncname(L, ar)) {  /* try first a global name */
          lua_pushfstring(L, "function '%s'", lua_tostring(L, -1));
          lua_remove(L, -2);  /* remove name */
      } else if (*ar->namewhat != '\0')  /* is there a name from code? */
          lua_pushfstring(L, "%s '%s'", ar->namewhat, ar->name);  /* use it */
      else if (*ar->what == 'm')  /* main? */
          lua_pushliteral(L, "main chunk");
      else if (*ar->what != 'C')  /* for Lua functions, use <file:line> */
          lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined);
      else  /* nothing left... */
          lua_pushliteral(L, "?");
  }
  
  
  static int lastlevel(lua_State *L) {
      lua_Debug ar;
      int li = 1, le = 1;
      /* find an upper bound */
      while (lua_getstack(L, le, &ar)) {
          li = le;
          le *= 2;
      }
      /* do a binary search */
      while (li < le) {
          int m = (li + le) / 2;
          if (lua_getstack(L, m, &ar)) li = m + 1;
          else le = m;
      }
      return le - 1;
  }
  
  
  LUALIB_API void luaL_traceback(lua_State *L, lua_State *L1,
                                 const char *msg, int level) {
      lua_Debug ar;
      int top = lua_gettop(L);
      int last = lastlevel(L1);
      int n1 = (last - level > LEVELS1 + LEVELS2) ? LEVELS1 : -1;
      if (msg)
          lua_pushfstring(L, "%s\n", msg);
      luaL_checkstack(L, 10, NULL);
      lua_pushliteral(L, "stack traceback:");
      while (lua_getstack(L1, level++, &ar)) {
          if (n1-- == 0) {  /* too many levels? */
              lua_pushliteral(L, "\n\t...");  /* add a '...' */
              level = last - LEVELS2 + 1;  /* and skip to last ones */
          } else {
              lua_getinfo(L1, "Slnt", &ar);
              lua_pushfstring(L, "\n\t%s:", ar.short_src);
              if (ar.currentline > 0)
                  lua_pushfstring(L, "%d:", ar.currentline);
              lua_pushliteral(L, " in ");
              pushfuncname(L, &ar);
              if (ar.istailcall)
                  lua_pushliteral(L, "\n\t(...tail calls...)");
              lua_concat(L, lua_gettop(L) - top);
          }
      }
      lua_concat(L, lua_gettop(L) - top);
  }
  
  /* }====================================================== */
  
  
  /*
  ** {======================================================
  ** Error-report functions
  ** =======================================================
  */
  
  LUALIB_API int luaL_argerror(lua_State *L, int arg, const char *extramsg) {
      lua_Debug ar;
      if (!lua_getstack(L, 0, &ar))  /* no stack frame? */
          return luaL_error(L, "bad argument #%d (%s)", arg, extramsg);
      lua_getinfo(L, "n", &ar);
      if (strcmp(ar.namewhat, "method") == 0) {
          arg--;  /* do not count 'self' */
          if (arg == 0)  /* error is in the self argument itself? */
              return luaL_error(L, "calling '%s' on bad self (%s)",
                                ar.name, extramsg);
      }
      if (ar.name == NULL)
          ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?";
      return luaL_error(L, "bad argument #%d to '%s' (%s)",
                        arg, ar.name, extramsg);
  }
  
  
  static int typeerror(lua_State *L, int arg, const char *tname) {
      const char *msg;
      const char *typearg;  /* name for the type of the actual argument */
      if (luaL_getmetafield(L, arg, "__name") == LUA_TSTRING)
          typearg = lua_tostring(L, -1);  /* use the given type name */
      else if (lua_type(L, arg) == LUA_TLIGHTUSERDATA)
          typearg = "light userdata";  /* special name for messages */
      else
          typearg = luaL_typename(L, arg);  /* standard name */
      msg = lua_pushfstring(L, "%s expected, got %s", tname, typearg);
      return luaL_argerror(L, arg, msg);
  }
  
  
  static void tag_error(lua_State *L, int arg, int tag) {
      typeerror(L, arg, lua_typename(L, tag));
  }
  
  
  /*
  ** The use of 'lua_pushfstring' ensures this function does not
  ** need reserved stack space when called.
  */
  LUALIB_API void luaL_where(lua_State *L, int level) {
      lua_Debug ar;
      if (lua_getstack(L, level, &ar)) {  /* check function at level */
          lua_getinfo(L, "Sl", &ar);  /* get info about it */
          if (ar.currentline > 0) {  /* is there info? */
              lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline);
              return;
          }
      }
      lua_pushfstring(L, "");  /* else, no information available... */
  }
  
  
  /*
  ** Again, the use of 'lua_pushvfstring' ensures this function does
  ** not need reserved stack space when called. (At worst, it generates
  ** an error with "stack overflow" instead of the given message.)
  */
  LUALIB_API int luaL_error(lua_State *L, const char *fmt, ...) {
      va_list argp;
      va_start(argp, fmt);
      luaL_where(L, 1);
      lua_pushvfstring(L, fmt, argp);
      va_end(argp);
      lua_concat(L, 2);
      return lua_error(L);
  }
  
  
  LUALIB_API int luaL_fileresult(lua_State *L, int stat, const char *fname) {
      int en = errno;  /* calls to Lua API may change this value */
      if (stat) {
          lua_pushboolean(L, 1);
          return 1;
      } else {
          lua_pushnil(L);
          if (fname)
              lua_pushfstring(L, "%s: %s", fname, strerror(en));
          else
              lua_pushstring(L, strerror(en));
          lua_pushinteger(L, en);
          return 3;
      }
  }
  
  
  #if !defined(l_inspectstat)    /* { */
  
  #if defined(LUA_USE_POSIX)
  
  #include <sys/wait.h>
  
  /*
  ** use appropriate macros to interpret 'pclose' return status
  */
  #define l_inspectstat(stat, what)  \
     if (WIFEXITED(stat)) { stat = WEXITSTATUS(stat); } \
     else if (WIFSIGNALED(stat)) { stat = WTERMSIG(stat); what = "signal"; }
  
  #else
  
  #define l_inspectstat(stat,what)  /* no op */
  
  #endif
  
  #endif                /* } */
  
  
  LUALIB_API int luaL_execresult(lua_State *L, int stat) {
      const char *what = "exit";  /* type of termination */
      if (stat == -1)  /* error? */
          return luaL_fileresult(L, 0, NULL);
      else {
          l_inspectstat(stat, what);  /* interpret result */
          if (*what == 'e' && stat == 0)  /* successful termination? */
              lua_pushboolean(L, 1);
          else
              lua_pushnil(L);
          lua_pushstring(L, what);
          lua_pushinteger(L, stat);
          return 3;  /* return true/nil,what,code */
      }
  }
  
  /* }====================================================== */
  
  
  /*
  ** {======================================================
  ** Userdata's metatable manipulation
  ** =======================================================
  */
  
  LUALIB_API int luaL_newmetatable(lua_State *L, const char *tname) {
      if (luaL_getmetatable(L, tname) != LUA_TNIL)  /* name already in use? */
          return 0;  /* leave previous value on top, but return 0 */
      lua_pop(L, 1);
      lua_createtable(L, 0, 2);  /* create metatable */
      lua_pushstring(L, tname);
      lua_setfield(L, -2, "__name");  /* metatable.__name = tname */
      lua_pushvalue(L, -1);
      lua_setfield(L, LUA_REGISTRYINDEX, tname);  /* registry.name = metatable */
      return 1;
  }
  
  
  LUALIB_API void luaL_setmetatable(lua_State *L, const char *tname) {
      luaL_getmetatable(L, tname);
      lua_setmetatable(L, -2);
  }
  
  
  LUALIB_API void *luaL_testudata(lua_State *L, int ud, const char *tname) {
      void *p = lua_touserdata(L, ud);
      if (p != NULL) {  /* value is a userdata? */
          if (lua_getmetatable(L, ud)) {  /* does it have a metatable? */
              luaL_getmetatable(L, tname);  /* get correct metatable */
              if (!lua_rawequal(L, -1, -2))  /* not the same? */
                  p = NULL;  /* value is a userdata with wrong metatable */
              lua_pop(L, 2);  /* remove both metatables */
              return p;
          }
      }
      return NULL;  /* value is not a userdata with a metatable */
  }
  
  
  LUALIB_API void *luaL_checkudata(lua_State *L, int ud, const char *tname) {
      void *p = luaL_testudata(L, ud, tname);
      if (p == NULL) typeerror(L, ud, tname);
      return p;
  }
  
  /* }====================================================== */
  
  
  /*
  ** {======================================================
  ** Argument check functions
  ** =======================================================
  */
  
  LUALIB_API int luaL_checkoption(lua_State *L, int arg, const char *def,
                                  const char *const lst[]) {
      const char *name = (def) ? luaL_optstring(L, arg, def) :
                         luaL_checkstring(L, arg);
      int i;
      for (i = 0; lst[i]; i++)
          if (strcmp(lst[i], name) == 0)
              return i;
      return luaL_argerror(L, arg,
                           lua_pushfstring(L, "invalid option '%s'", name));
  }
  
  
  /*
  ** Ensures the stack has at least 'space' extra slots, raising an error
  ** if it cannot fulfill the request. (The error handling needs a few
  ** extra slots to format the error message. In case of an error without
  ** this extra space, Lua will generate the same 'stack overflow' error,
  ** but without 'msg'.)
  */
  LUALIB_API void luaL_checkstack(lua_State *L, int space, const char *msg) {
      if (!lua_checkstack(L, space)) {
          if (msg)
              luaL_error(L, "stack overflow (%s)", msg);
          else
              luaL_error(L, "stack overflow");
      }
  }
  
  
  LUALIB_API void luaL_checktype(lua_State *L, int arg, int t) {
      if (lua_type(L, arg) != t)
          tag_error(L, arg, t);
  }
  
  
  LUALIB_API void luaL_checkany(lua_State *L, int arg) {
      if (lua_type(L, arg) == LUA_TNONE)
          luaL_argerror(L, arg, "value expected");
  }
  
  
  LUALIB_API const char *luaL_checklstring(lua_State *L, int arg, size_t *len) {
      const char *s = lua_tolstring(L, arg, len);
      if (!s) tag_error(L, arg, LUA_TSTRING);
      return s;
  }
  
  
  LUALIB_API const char *luaL_optlstring(lua_State *L, int arg,
                                         const char *def, size_t *len) {
      if (lua_isnoneornil(L, arg)) {
          if (len)
              *len = (def ? strlen(def) : 0);
          return def;
      } else return luaL_checklstring(L, arg, len);
  }
  
  
  LUALIB_API lua_Number luaL_checknumber(lua_State *L, int arg) {
      int isnum;
      lua_Number d = lua_tonumberx(L, arg, &isnum);
      if (!isnum)
          tag_error(L, arg, LUA_TNUMBER);
      return d;
  }
  
  
  LUALIB_API lua_Number luaL_optnumber(lua_State *L, int arg, lua_Number def) {
      return luaL_opt(L, luaL_checknumber, arg, def);
  }
  
  
  static void interror(lua_State *L, int arg) {
      if (lua_isnumber(L, arg))
          luaL_argerror(L, arg, "number has no integer representation");
      else
          tag_error(L, arg, LUA_TNUMBER);
  }
  
  
  LUALIB_API lua_Integer luaL_checkinteger(lua_State *L, int arg) {
      int isnum;
      lua_Integer d = lua_tointegerx(L, arg, &isnum);
      if (!isnum) {
          interror(L, arg);
      }
      return d;
  }
  
  
  LUALIB_API lua_Integer luaL_optinteger(lua_State *L, int arg,
                                         lua_Integer def) {
      return luaL_opt(L, luaL_checkinteger, arg, def);
  }
  
  /* }====================================================== */
  
  
  /*
  ** {======================================================
  ** Generic Buffer manipulation
  ** =======================================================
  */
  
  /* userdata to box arbitrary data */
  typedef struct UBox {
      void *box;
      size_t bsize;
  } UBox;
  
  
  static void *resizebox(lua_State *L, int idx, size_t newsize) {
      void *ud;
      lua_Alloc allocf = lua_getallocf(L, &ud);
      UBox *box = (UBox *) lua_touserdata(L, idx);
      void *temp = allocf(ud, box->box, box->bsize, newsize);
      if (temp == NULL && newsize > 0) {  /* allocation error? */
          resizebox(L, idx, 0);  /* free buffer */
          luaL_error(L, "not enough memory for buffer allocation");
      }
      box->box = temp;
      box->bsize = newsize;
      return temp;
  }
  
  
  static int boxgc(lua_State *L) {
      resizebox(L, 1, 0);
      return 0;
  }
  
  
  static void *newbox(lua_State *L, size_t newsize) {
      UBox *box = (UBox *) lua_newuserdata(L, sizeof(UBox));
      box->box = NULL;
      box->bsize = 0;
      if (luaL_newmetatable(L, "LUABOX")) {  /* creating metatable? */
          lua_pushcfunction(L, boxgc);
          lua_setfield(L, -2, "__gc");  /* metatable.__gc = boxgc */
      }
      lua_setmetatable(L, -2);
      return resizebox(L, -1, newsize);
  }
  
  
  /*
  ** check whether buffer is using a userdata on the stack as a temporary
  ** buffer
  */
  #define buffonstack(B)    ((B)->b != (B)->initb)
  
  
  /*
  ** returns a pointer to a free area with at least 'sz' bytes
  */
  LUALIB_API char *luaL_prepbuffsize(luaL_Buffer *B, size_t sz) {
      lua_State *L = B->L;
      if (B->size - B->n < sz) {  /* not enough space? */
          char *newbuff;
          size_t newsize = B->size * 2;  /* double buffer size */
          if (newsize - B->n < sz)  /* not big enough? */
              newsize = B->n + sz;
          if (newsize < B->n || newsize - B->n < sz)
              luaL_error(L, "buffer too large");
          /* create larger buffer */
          if (buffonstack(B))
              newbuff = (char *) resizebox(L, -1, newsize);
          else {  /* no buffer yet */
              newbuff = (char *) newbox(L, newsize);
              memcpy(newbuff, B->b, B->n * sizeof(char));  /* copy original content */
          }
          B->b = newbuff;
          B->size = newsize;
      }
      return &B->b[B->n];
  }
  
  
  LUALIB_API void luaL_addlstring(luaL_Buffer *B, const char *s, size_t l) {
      if (l > 0) {  /* avoid 'memcpy' when 's' can be NULL */
          char *b = luaL_prepbuffsize(B, l);
          memcpy(b, s, l * sizeof(char));
          luaL_addsize(B, l);
      }
  }
  
  
  LUALIB_API void luaL_addstring(luaL_Buffer *B, const char *s) {
      luaL_addlstring(B, s, strlen(s));
  }
  
  
  LUALIB_API void luaL_pushresult(luaL_Buffer *B) {
      lua_State *L = B->L;
      lua_pushlstring(L, B->b, B->n);
      if (buffonstack(B)) {
          resizebox(L, -2, 0);  /* delete old buffer */
          lua_remove(L, -2);  /* remove its header from the stack */
      }
  }
  
  
  LUALIB_API void luaL_pushresultsize(luaL_Buffer *B, size_t sz) {
      luaL_addsize(B, sz);
      luaL_pushresult(B);
  }
  
  
  LUALIB_API void luaL_addvalue(luaL_Buffer *B) {
      lua_State *L = B->L;
      size_t l;
      const char *s = lua_tolstring(L, -1, &l);
      if (buffonstack(B))
          lua_insert(L, -2);  /* put value below buffer */
      luaL_addlstring(B, s, l);
      lua_remove(L, (buffonstack(B)) ? -2 : -1);  /* remove value */
  }
  
  
  LUALIB_API void luaL_buffinit(lua_State *L, luaL_Buffer *B) {
      B->L = L;
      B->b = B->initb;
      B->n = 0;
      B->size = LUAL_BUFFERSIZE;
  }
  
  
  LUALIB_API char *luaL_buffinitsize(lua_State *L, luaL_Buffer *B, size_t sz) {
      luaL_buffinit(L, B);
      return luaL_prepbuffsize(B, sz);
  }
  
  /* }====================================================== */
  
  
  /*
  ** {======================================================
  ** Reference system
  ** =======================================================
  */
  
  /* index of free-list header */
  #define freelist    0
  
  
  LUALIB_API int luaL_ref(lua_State *L, int t) {
      int ref;
      if (lua_isnil(L, -1)) {
          lua_pop(L, 1);  /* remove from stack */
          return LUA_REFNIL;  /* 'nil' has a unique fixed reference */
      }
      t = lua_absindex(L, t);
      lua_rawgeti(L, t, freelist);  /* get first free element */
      ref = (int) lua_tointeger(L, -1);  /* ref = t[freelist] */
      lua_pop(L, 1);  /* remove it from stack */
      if (ref != 0) {  /* any free element? */
          lua_rawgeti(L, t, ref);  /* remove it from list */
          lua_rawseti(L, t, freelist);  /* (t[freelist] = t[ref]) */
      } else  /* no free elements */
          ref = (int) lua_rawlen(L, t) + 1;  /* get a new reference */
      lua_rawseti(L, t, ref);
      return ref;
  }
  
  
  LUALIB_API void luaL_unref(lua_State *L, int t, int ref) {
      if (ref >= 0) {
          t = lua_absindex(L, t);
          lua_rawgeti(L, t, freelist);
          lua_rawseti(L, t, ref);  /* t[ref] = t[freelist] */
          lua_pushinteger(L, ref);
          lua_rawseti(L, t, freelist);  /* t[freelist] = ref */
      }
  }
  
  /* }====================================================== */
  
  
  /*
  ** {======================================================
  ** Load functions
  ** =======================================================
  */
  
  typedef struct LoadF {
      int n;  /* number of pre-read characters */
      FILE *f;  /* file being read */
      char buff[BUFSIZ];  /* area for reading file */
  } LoadF;
  
  
  static const char *getF(lua_State *L, void *ud, size_t *size) {
      LoadF *lf = (LoadF *) ud;
      (void) L;  /* not used */
      if (lf->n > 0) {  /* are there pre-read characters to be read? */
          *size = lf->n;  /* return them (chars already in buffer) */
          lf->n = 0;  /* no more pre-read characters */
      } else {  /* read a block from file */
          /* 'fread' can return > 0 *and* set the EOF flag. If next call to
             'getF' called 'fread', it might still wait for user input.
             The next check avoids this problem. */
          if (feof(lf->f)) return NULL;
          *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f);  /* read block */
      }
      return lf->buff;
  }
  
  
  static int errfile(lua_State *L, const char *what, int fnameindex) {
      const char *serr = strerror(errno);
      const char *filename = lua_tostring(L, fnameindex) + 1;
      lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr);
      lua_remove(L, fnameindex);
      return LUA_ERRFILE;
  }
  
  
  static int skipBOM(LoadF *lf) {
      const char *p = "\xEF\xBB\xBF";  /* UTF-8 BOM mark */
      int c;
      lf->n = 0;
      do {
          c = getc(lf->f);
          if (c == EOF || c != *(const unsigned char *) p++) return c;
          lf->buff[lf->n++] = c;  /* to be read by the parser */
      } while (*p != '\0');
      lf->n = 0;  /* prefix matched; discard it */
      return getc(lf->f);  /* return next character */
  }
  
  
  /*
  ** reads the first character of file 'f' and skips an optional BOM mark
  ** in its beginning plus its first line if it starts with '#'. Returns
  ** true if it skipped the first line.  In any case, '*cp' has the
  ** first "valid" character of the file (after the optional BOM and
  ** a first-line comment).
  */
  static int skipcomment(LoadF *lf, int *cp) {
      int c = *cp = skipBOM(lf);
      if (c == '#') {  /* first line is a comment (Unix exec. file)? */
          do {  /* skip first line */
              c = getc(lf->f);
          } while (c != EOF && c != '\n');
          *cp = getc(lf->f);  /* skip end-of-line, if present */
          return 1;  /* there was a comment */
      } else return 0;  /* no comment */
  }
  
  
  LUALIB_API int luaL_loadfilex(lua_State *L, const char *filename,
                                const char *mode) {
      LoadF lf;
      int status, readstatus;
      int c;
      int fnameindex = lua_gettop(L) + 1;  /* index of filename on the stack */
      if (filename == NULL) {
          lua_pushliteral(L, "=stdin");
          lf.f = stdin;
      } else {
          lua_pushfstring(L, "@%s", filename);
          lf.f = fopen(filename, "r");
          if (lf.f == NULL) return errfile(L, "open", fnameindex);
      }
      if (skipcomment(&lf, &c))  /* read initial portion */
          lf.buff[lf.n++] = '\n';  /* add line to correct line numbers */
      if (c == LUA_SIGNATURE[0] && filename) {  /* binary file? */
          lf.f = freopen(filename, "rb", lf.f);  /* reopen in binary mode */
          if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
          skipcomment(&lf, &c);  /* re-read initial portion */
      }
      if (c != EOF)
          lf.buff[lf.n++] = c;  /* 'c' is the first character of the stream */
      status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode);
      readstatus = ferror(lf.f);
      if (filename) fclose(lf.f);  /* close file (even in case of errors) */
      if (readstatus) {
          lua_settop(L, fnameindex);  /* ignore results from 'lua_load' */
          return errfile(L, "read", fnameindex);
      }
      lua_remove(L, fnameindex);
      return status;
  }
  
  
  typedef struct LoadS {
      const char *s;
      size_t size;
  } LoadS;
  
  
  static const char *getS(lua_State *L, void *ud, size_t *size) {
      LoadS *ls = (LoadS *) ud;
      (void) L;  /* not used */
      if (ls->size == 0) return NULL;
      *size = ls->size;
      ls->size = 0;
      return ls->s;
  }
  
  
  LUALIB_API int luaL_loadbufferx(lua_State *L, const char *buff, size_t size,
                                  const char *name, const char *mode) {
      LoadS ls;
      ls.s = buff;
      ls.size = size;
      return lua_load(L, getS, &ls, name, mode);
  }
  
  
  LUALIB_API int luaL_loadstring(lua_State *L, const char *s) {
      return luaL_loadbuffer(L, s, strlen(s), s);
  }
  
  /* }====================================================== */
  
  
  
  LUALIB_API int luaL_getmetafield(lua_State *L, int obj, const char *event) {
      if (!lua_getmetatable(L, obj))  /* no metatable? */
          return LUA_TNIL;
      else {
          int tt;
          lua_pushstring(L, event);
          tt = lua_rawget(L, -2);
          if (tt == LUA_TNIL)  /* is metafield nil? */
              lua_pop(L, 2);  /* remove metatable and metafield */
          else
              lua_remove(L, -2);  /* remove only metatable */
          return tt;  /* return metafield type */
      }
  }
  
  
  LUALIB_API int luaL_callmeta(lua_State *L, int obj, const char *event) {
      obj = lua_absindex(L, obj);
      if (luaL_getmetafield(L, obj, event) == LUA_TNIL)  /* no metafield? */
          return 0;
      lua_pushvalue(L, obj);
      lua_call(L, 1, 1);
      return 1;
  }
  
  
  LUALIB_API lua_Integer luaL_len(lua_State *L, int idx) {
      lua_Integer l;
      int isnum;
      lua_len(L, idx);
      l = lua_tointegerx(L, -1, &isnum);
      if (!isnum)
          luaL_error(L, "object length is not an integer");
      lua_pop(L, 1);  /* remove object */
      return l;
  }
  
  
  LUALIB_API const char *luaL_tolstring(lua_State *L, int idx, size_t *len) {
      if (luaL_callmeta(L, idx, "__tostring")) {  /* metafield? */
          if (!lua_isstring(L, -1))
              luaL_error(L, "'__tostring' must return a string");
      } else {
          switch (lua_type(L, idx)) {
              case LUA_TNUMBER: {
                  if (lua_isinteger(L, idx))
                      lua_pushfstring(L, "%I", (LUAI_UACINT) lua_tointeger(L, idx));
                  else
                      lua_pushfstring(L, "%f", (LUAI_UACNUMBER) lua_tonumber(L, idx));
                  break;
              }
              case LUA_TSTRING:
                  lua_pushvalue(L, idx);
                  break;
              case LUA_TBOOLEAN:
                  lua_pushstring(L, (lua_toboolean(L, idx) ? "true" : "false"));
                  break;
              case LUA_TNIL:
                  lua_pushliteral(L, "nil");
                  break;
              default: {
                  int tt = luaL_getmetafield(L, idx, "__name");  /* try name */
                  const char *kind = (tt == LUA_TSTRING) ? lua_tostring(L, -1) :
                                     luaL_typename(L, idx);
                  lua_pushfstring(L, "%s: %p", kind, lua_topointer(L, idx));
                  if (tt != LUA_TNIL)
                      lua_remove(L, -2);  /* remove '__name' */
                  break;
              }
          }
      }
      return lua_tolstring(L, -1, len);
  }
  
  
  /*
  ** {======================================================
  ** Compatibility with 5.1 module functions
  ** =======================================================
  */
  #if defined(LUA_COMPAT_MODULE)
  
  static const char *luaL_findtable(lua_State *L, int idx,
                                    const char *fname, int szhint) {
      const char *e;
      if (idx) lua_pushvalue(L, idx);
      do {
          e = strchr(fname, '.');
          if (e == NULL) e = fname + strlen(fname);
          lua_pushlstring(L, fname, e - fname);
          if (lua_rawget(L, -2) == LUA_TNIL) {  /* no such field? */
              lua_pop(L, 1);  /* remove this nil */
              lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */
              lua_pushlstring(L, fname, e - fname);
              lua_pushvalue(L, -2);
              lua_settable(L, -4);  /* set new table into field */
          } else if (!lua_istable(L, -1)) {  /* field has a non-table value? */
              lua_pop(L, 2);  /* remove table and value */
              return fname;  /* return problematic part of the name */
          }
          lua_remove(L, -2);  /* remove previous table */
          fname = e + 1;
      } while (*e == '.');
      return NULL;
  }
  
  
  /*
  ** Count number of elements in a luaL_Reg list.
  */
  static int libsize(const luaL_Reg *l) {
      int size = 0;
      for (; l && l->name; l++) size++;
      return size;
  }
  
  
  /*
  ** Find or create a module table with a given name. The function
  ** first looks at the LOADED table and, if that fails, try a
  ** global variable with that name. In any case, leaves on the stack
  ** the module table.
  */
  LUALIB_API void luaL_pushmodule(lua_State *L, const char *modname,
                                  int sizehint) {
      luaL_findtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE, 1);
      if (lua_getfield(L, -1, modname) != LUA_TTABLE) {  /* no LOADED[modname]? */
          lua_pop(L, 1);  /* remove previous result */
          /* try global variable (and create one if it does not exist) */
          lua_pushglobaltable(L);
          if (luaL_findtable(L, 0, modname, sizehint) != NULL)
              luaL_error(L, "name conflict for module '%s'", modname);
          lua_pushvalue(L, -1);
          lua_setfield(L, -3, modname);  /* LOADED[modname] = new table */
      }
      lua_remove(L, -2);  /* remove LOADED table */
  }
  
  
  LUALIB_API void luaL_openlib(lua_State *L, const char *libname,
                               const luaL_Reg *l, int nup) {
      luaL_checkversion(L);
      if (libname) {
          luaL_pushmodule(L, libname, libsize(l));  /* get/create library table */
          lua_insert(L, -(nup + 1));  /* move library table to below upvalues */
      }
      if (l)
          luaL_setfuncs(L, l, nup);
      else
          lua_pop(L, nup);  /* remove upvalues */
  }
  
  #endif
  /* }====================================================== */
  
  /*
  ** set functions from list 'l' into table at top - 'nup'; each
  ** function gets the 'nup' elements at the top as upvalues.
  ** Returns with only the table at the stack.
  */
  LUALIB_API void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup) {
      luaL_checkstack(L, nup, "too many upvalues");
      for (; l->name != NULL; l++) {  /* fill the table with given functions */
          int i;
          for (i = 0; i < nup; i++)  /* copy upvalues to the top */
              lua_pushvalue(L, -nup);
          lua_pushcclosure(L, l->func, nup);  /* closure with those upvalues */
          lua_setfield(L, -(nup + 2), l->name);
      }
      lua_pop(L, nup);  /* remove upvalues */
  }
  
  
  /*
  ** ensure that stack[idx][fname] has a table and push that table
  ** into the stack
  */
  LUALIB_API int luaL_getsubtable(lua_State *L, int idx, const char *fname) {
      if (lua_getfield(L, idx, fname) == LUA_TTABLE)
          return 1;  /* table already there */
      else {
          lua_pop(L, 1);  /* remove previous result */
          idx = lua_absindex(L, idx);
          lua_newtable(L);
          lua_pushvalue(L, -1);  /* copy to be left at top */
          lua_setfield(L, idx, fname);  /* assign new table to field */
          return 0;  /* false, because did not find table there */
      }
  }
  
  
  /*
  ** Stripped-down 'require': After checking "loaded" table, calls 'openf'
  ** to open a module, registers the result in 'package.loaded' table and,
  ** if 'glb' is true, also registers the result in the global table.
  ** Leaves resulting module on the top.
  */
  LUALIB_API void luaL_requiref(lua_State *L, const char *modname,
                                lua_CFunction openf, int glb) {
      luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
      lua_getfield(L, -1, modname);  /* LOADED[modname] */
      if (!lua_toboolean(L, -1)) {  /* package not already loaded? */
          lua_pop(L, 1);  /* remove field */
          lua_pushcfunction(L, openf);
          lua_pushstring(L, modname);  /* argument to open function */
          lua_call(L, 1, 1);  /* call 'openf' to open module */
          lua_pushvalue(L, -1);  /* make copy of module (call result) */
          lua_setfield(L, -3, modname);  /* LOADED[modname] = module */
      }
      lua_remove(L, -2);  /* remove LOADED table */
      if (glb) {
          lua_pushvalue(L, -1);  /* copy of module */
          lua_setglobal(L, modname);  /* _G[modname] = module */
      }
  }
  
  
  LUALIB_API const char *luaL_gsub(lua_State *L, const char *s, const char *p,
                                   const char *r) {
      const char *wild;
      size_t l = strlen(p);
      luaL_Buffer b;
      luaL_buffinit(L, &b);
      while ((wild = strstr(s, p)) != NULL) {
          luaL_addlstring(&b, s, wild - s);  /* push prefix */
          luaL_addstring(&b, r);  /* push replacement in place of pattern */
          s = wild + l;  /* continue after 'p' */
      }
      luaL_addstring(&b, s);  /* push last suffix */
      luaL_pushresult(&b);
      return lua_tostring(L, -1);
  }
  
  
  static void *l_alloc(void *ud, void *ptr, size_t osize, size_t nsize) {
      (void) ud;
      (void) osize;  /* not used */
      if (nsize == 0) {
          free(ptr);
          return NULL;
      } else
          return realloc(ptr, nsize);
  }
  
  
  static int panic(lua_State *L) {
      lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n",
                           lua_tostring(L, -1));
      return 0;  /* return to Lua to abort */
  }
  
  
  LUALIB_API lua_State *luaL_newstate(void) {
      lua_State *L = lua_newstate(l_alloc, NULL);
      if (L) lua_atpanic(L, &panic);
      return L;
  }
  
  
  LUALIB_API void luaL_checkversion_(lua_State *L, lua_Number ver, size_t sz) {
      const lua_Number *v = lua_version(L);
      if (sz != LUAL_NUMSIZES)  /* check numeric types */
          luaL_error(L, "core and library have incompatible numeric types");
      if (v != lua_version(NULL))
          luaL_error(L, "multiple Lua VMs detected");
      else if (*v != ver)
          luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f",
                     (LUAI_UACNUMBER) ver, (LUAI_UACNUMBER) *v);
  }
  
  