Lua TeamLua 5.3.0-rc1396021811 years agoHistory
972 lines · 27.7 KB · C
RawDownload
/*** $Id: lauxlib.c,v 1.279 2014/12/14 18:32:26 roberto Exp $** Auxiliary functions for building Lua libraries** See Copyright Notice in lua.h*/ #define lauxlib_c#define LUA_LIB #include "lprefix.h"  #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	12	/* size of the first part of the stack */#define LEVELS2	10	/* 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** (registry._LOADED).*/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, "_LOADED");  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 countlevels (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 numlevels = countlevels(L1);  int mark = (numlevels > LEVELS1 + LEVELS2) ? LEVELS1 : 0;  if (msg) lua_pushfstring(L, "%s\n", msg);  lua_pushliteral(L, "stack traceback:");  while (lua_getstack(L1, level++, &ar)) {    if (level == mark) {  /* too many levels? */      lua_pushliteral(L, "\n\t...");  /* add a '...' */      level = numlevels - LEVELS2;  /* 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));}  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_pushliteral(L, "");  /* else, no information available... */}  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))  /* name already in use? */    return 0;  /* leave previous value on top, but return 0 */  lua_pop(L, 1);  lua_newtable(L);  /* 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));}  LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) {  /* keep some extra space to run error routines, if needed */  const int extra = LUA_MINSTACK;  if (!lua_checkstack(L, space + extra)) {    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** =======================================================*/ /*** 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 */    newbuff = (char *)lua_newuserdata(L, newsize * sizeof(char));    /* move content to new buffer */    memcpy(newbuff, B->b, B->n * sizeof(char));    if (buffonstack(B))      lua_remove(L, -2);  /* remove old buffer */    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) {  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))    lua_remove(L, -2);  /* remove old buffer */}  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))

Lines 1–500 of 972.