958 lines · 26.9 KB · C
RawDownload
/*** $Id: lauxlib.c,v 1.244 2012/05/31 20:28:45 roberto Exp $** Auxiliary functions for building Lua libraries** See Copyright Notice in lua.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.*/ #define lauxlib_c#define LUA_LIB #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 */}  static int pushglobalfuncname (lua_State *L, lua_Debug *ar) {  int top = lua_gettop(L);  lua_getinfo(L, "f", ar);  /* push function */  lua_pushglobaltable(L);  if (findfield(L, top + 1, 2)) {    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 (*ar->namewhat != '\0')  /* is there a name? */    lua_pushfstring(L, "function " LUA_QS, ar->name);  else if (*ar->what == 'm')  /* main? */      lua_pushfstring(L, "main chunk");  else if (*ar->what == 'C') {    if (pushglobalfuncname(L, ar)) {      lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1));      lua_remove(L, -2);  /* remove name */    }    else      lua_pushliteral(L, "?");  }  else    lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined);}  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 narg, const char *extramsg) {  lua_Debug ar;  if (!lua_getstack(L, 0, &ar))  /* no stack frame? */    return luaL_error(L, "bad argument #%d (%s)", narg, extramsg);  lua_getinfo(L, "n", &ar);  if (strcmp(ar.namewhat, "method") == 0) {    narg--;  /* do not count `self' */    if (narg == 0)  /* error is in the self argument itself? */      return luaL_error(L, "calling " LUA_QS " on bad self", ar.name);  }  if (ar.name == NULL)    ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?";  return luaL_error(L, "bad argument #%d to " LUA_QS " (%s)",                        narg, ar.name, extramsg);}  static int typeerror (lua_State *L, int narg, const char *tname) {  const char *msg = lua_pushfstring(L, "%s expected, got %s",                                    tname, luaL_typename(L, narg));  return luaL_argerror(L, narg, msg);}  static void tag_error (lua_State *L, int narg, int tag) {  typeerror(L, narg, 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_pushfstring(L, "%s", strerror(en));    lua_pushinteger(L, en);    return 3;  }}  #if !defined(inspectstat)	/* { */ #if defined(LUA_USE_POSIX) #include <sys/wait.h> /*** use appropriate macros to interpret 'pclose' return status*/#define inspectstat(stat,what)  \   if (WIFEXITED(stat)) { stat = WEXITSTATUS(stat); } \   else if (WIFSIGNALED(stat)) { stat = WTERMSIG(stat); what = "signal"; } #else #define 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 {    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) {  luaL_getmetatable(L, tname);  /* try to get metatable */  if (!lua_isnil(L, -1))  /* name already in use? */    return 0;  /* leave previous value on top, but return 0 */  lua_pop(L, 1);  lua_newtable(L);  /* create metatable */  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 narg, const char *def,                                 const char *const lst[]) {  const char *name = (def) ? luaL_optstring(L, narg, def) :                             luaL_checkstring(L, narg);  int i;  for (i=0; lst[i]; i++)    if (strcmp(lst[i], name) == 0)      return i;  return luaL_argerror(L, narg,                       lua_pushfstring(L, "invalid option " LUA_QS, 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 narg, int t) {  if (lua_type(L, narg) != t)    tag_error(L, narg, t);}  LUALIB_API void luaL_checkany (lua_State *L, int narg) {  if (lua_type(L, narg) == LUA_TNONE)    luaL_argerror(L, narg, "value expected");}  LUALIB_API const char *luaL_checklstring (lua_State *L, int narg, size_t *len) {  const char *s = lua_tolstring(L, narg, len);  if (!s) tag_error(L, narg, LUA_TSTRING);  return s;}  LUALIB_API const char *luaL_optlstring (lua_State *L, int narg,                                        const char *def, size_t *len) {  if (lua_isnoneornil(L, narg)) {    if (len)      *len = (def ? strlen(def) : 0);    return def;  }  else return luaL_checklstring(L, narg, len);}  LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) {  int isnum;  lua_Number d = lua_tonumberx(L, narg, &isnum);  if (!isnum)    tag_error(L, narg, LUA_TNUMBER);  return d;}  LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) {  return luaL_opt(L, luaL_checknumber, narg, def);}  LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) {  int isnum;  lua_Integer d = lua_tointegerx(L, narg, &isnum);  if (!isnum)    tag_error(L, narg, LUA_TNUMBER);  return d;}  LUALIB_API lua_Unsigned luaL_checkunsigned (lua_State *L, int narg) {  int isnum;  lua_Unsigned d = lua_tounsignedx(L, narg, &isnum);  if (!isnum)    tag_error(L, narg, LUA_TNUMBER);  return d;}  LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg,                                                      lua_Integer def) {  return luaL_opt(L, luaL_checkinteger, narg, def);}  LUALIB_API lua_Unsigned luaL_optunsigned (lua_State *L, int narg,                                                        lua_Unsigned def) {  return luaL_opt(L, luaL_checkunsigned, narg, 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 bit 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))    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;}

Lines 1–500 of 958.