📄 lauxlib.c
字号:
/*
** $Id: lauxlib.c,v 1.159 2006/03/21 19:31:09 roberto Exp $
** Auxiliary functions for building PVE libraries
** See Copyright Notice in PVE.h
*/
#include <ctype.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* This file uses only the official API of PVE.
** Any function declared here could be written as an application function.
*/
#define lauxlib_c
#define PVE_LIB
#include "PVE.h"
#include "lauxlib.h"
#define FREELIST_REF 0 /* free list of references */
/* convert a stack index to positive */
#define abs_index(L, i) ((i) > 0 || (i) <= PVE_REGISTRYINDEX ? (i) : \
PVE_gettop(L) + (i) + 1)
/*
** {======================================================
** Error-report functions
** =======================================================
*/
PVELIB_API int PVEL_argerror (PVE_State *L, int narg, const char *extramsg) {
PVE_Debug ar;
if (!PVE_getstack(L, 0, &ar)) /* no stack frame? */
return PVEL_error(L, "bad argument #%d (%s)", narg, extramsg);
PVE_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 PVEL_error(L, "calling " PVE_QS " on bad self (%s)",
ar.name, extramsg);
}
if (ar.name == NULL)
ar.name = "?";
return PVEL_error(L, "bad argument #%d to " PVE_QS " (%s)",
narg, ar.name, extramsg);
}
PVELIB_API int PVEL_typerror (PVE_State *L, int narg, const char *tname) {
const char *msg = PVE_pushfstring(L, "%s expected, got %s",
tname, PVEL_typename(L, narg));
return PVEL_argerror(L, narg, msg);
}
static void tag_error (PVE_State *L, int narg, int tag) {
PVEL_typerror(L, narg, PVE_typename(L, tag));
}
PVELIB_API void PVEL_where (PVE_State *L, int level) {
PVE_Debug ar;
if (PVE_getstack(L, level, &ar)) { /* check function at level */
PVE_getinfo(L, "Sl", &ar); /* get info about it */
if (ar.currentline > 0) { /* is there info? */
PVE_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline);
return;
}
}
PVE_pushliteral(L, ""); /* else, no information available... */
}
PVELIB_API int PVEL_error (PVE_State *L, const char *fmt, ...) {
va_list argp;
va_start(argp, fmt);
PVEL_where(L, 1);
PVE_pushvfstring(L, fmt, argp);
va_end(argp);
PVE_concat(L, 2);
return PVE_error(L);
}
/* }====================================================== */
PVELIB_API int PVEL_checkoption (PVE_State *L, int narg, const char *def,
const char *const lst[]) {
const char *name = (def) ? PVEL_optstring(L, narg, def) :
PVEL_checkstring(L, narg);
int i;
for (i=0; lst[i]; i++)
if (strcmp(lst[i], name) == 0)
return i;
return PVEL_argerror(L, narg,
PVE_pushfstring(L, "invalid option " PVE_QS, name));
}
PVELIB_API int PVEL_newmetatable (PVE_State *L, const char *tname) {
PVE_getfield(L, PVE_REGISTRYINDEX, tname); /* get registry.name */
if (!PVE_isnil(L, -1)) /* name already in use? */
return 0; /* leave previous value on top, but return 0 */
PVE_pop(L, 1);
PVE_newtable(L); /* create metatable */
PVE_pushvalue(L, -1);
PVE_setfield(L, PVE_REGISTRYINDEX, tname); /* registry.name = metatable */
return 1;
}
PVELIB_API void *PVEL_checkudata (PVE_State *L, int ud, const char *tname) {
void *p = PVE_touserdata(L, ud);
if (p != NULL) { /* value is a userdata? */
if (PVE_getmetatable(L, ud)) { /* does it have a metatable? */
PVE_getfield(L, PVE_REGISTRYINDEX, tname); /* get correct metatable */
if (PVE_rawequal(L, -1, -2)) { /* does it have the correct mt? */
PVE_pop(L, 2); /* remove both metatables */
return p;
}
}
}
PVEL_typerror(L, ud, tname); /* else error */
return NULL; /* to avoid warnings */
}
PVELIB_API void PVEL_checkstack (PVE_State *L, int space, const char *mes) {
if (!PVE_checkstack(L, space))
PVEL_error(L, "stack overflow (%s)", mes);
}
PVELIB_API void PVEL_checktype (PVE_State *L, int narg, int t) {
if (PVE_type(L, narg) != t)
tag_error(L, narg, t);
}
PVELIB_API void PVEL_checkany (PVE_State *L, int narg) {
if (PVE_type(L, narg) == PVE_TNONE)
PVEL_argerror(L, narg, "value expected");
}
PVELIB_API const char *PVEL_checklstring (PVE_State *L, int narg, size_t *len) {
const char *s = PVE_tolstring(L, narg, len);
if (!s) tag_error(L, narg, PVE_TSTRING);
return s;
}
PVELIB_API const char *PVEL_optlstring (PVE_State *L, int narg,
const char *def, size_t *len) {
if (PVE_isnoneornil(L, narg)) {
if (len)
*len = (def ? strlen(def) : 0);
return def;
}
else return PVEL_checklstring(L, narg, len);
}
PVELIB_API PVE_Number PVEL_checknumber (PVE_State *L, int narg) {
PVE_Number d = PVE_tonumber(L, narg);
if (d == 0 && !PVE_isnumber(L, narg)) /* avoid extra test when d is not 0 */
tag_error(L, narg, PVE_TNUMBER);
return d;
}
PVELIB_API PVE_Number PVEL_optnumber (PVE_State *L, int narg, PVE_Number def) {
return PVEL_opt(L, PVEL_checknumber, narg, def);
}
PVELIB_API PVE_Integer PVEL_checkinteger (PVE_State *L, int narg) {
PVE_Integer d = PVE_tointeger(L, narg);
if (d == 0 && !PVE_isnumber(L, narg)) /* avoid extra test when d is not 0 */
tag_error(L, narg, PVE_TNUMBER);
return d;
}
PVELIB_API PVE_Integer PVEL_optinteger (PVE_State *L, int narg,
PVE_Integer def) {
return PVEL_opt(L, PVEL_checkinteger, narg, def);
}
PVELIB_API int PVEL_getmetafield (PVE_State *L, int obj, const char *event) {
if (!PVE_getmetatable(L, obj)) /* no metatable? */
return 0;
PVE_pushstring(L, event);
PVE_rawget(L, -2);
if (PVE_isnil(L, -1)) {
PVE_pop(L, 2); /* remove metatable and metafield */
return 0;
}
else {
PVE_remove(L, -2); /* remove only metatable */
return 1;
}
}
PVELIB_API int PVEL_callmeta (PVE_State *L, int obj, const char *event) {
obj = abs_index(L, obj);
if (!PVEL_getmetafield(L, obj, event)) /* no metafield? */
return 0;
PVE_pushvalue(L, obj);
PVE_call(L, 1, 1);
return 1;
}
PVELIB_API void (PVEL_register) (PVE_State *L, const char *libname,
const PVEL_Reg *l) {
PVEI_openlib(L, libname, l, 0);
}
static int libsize (const PVEL_Reg *l) {
int size = 0;
for (; l->name; l++) size++;
return size;
}
PVELIB_API void PVEI_openlib (PVE_State *L, const char *libname,
const PVEL_Reg *l, int nup) {
if (libname) {
int size = libsize(l);
/* check whether lib already exists */
PVEL_findtable(L, PVE_REGISTRYINDEX, "_LOADED", size);
PVE_getfield(L, -1, libname); /* get _LOADED[libname] */
if (!PVE_istable(L, -1)) { /* not found? */
PVE_pop(L, 1); /* remove previous result */
/* try global variable (and create one if it does not exist) */
if (PVEL_findtable(L, PVE_GLOBALSINDEX, libname, size) != NULL)
PVEL_error(L, "name conflict for module " PVE_QS, libname);
PVE_pushvalue(L, -1);
PVE_setfield(L, -3, libname); /* _LOADED[libname] = new table */
}
PVE_remove(L, -2); /* remove _LOADED table */
PVE_insert(L, -(nup+1)); /* move library table to below upvalues */
}
for (; l->name; l++) {
int i;
for (i=0; i<nup; i++) /* copy upvalues to the top */
PVE_pushvalue(L, -nup);
PVE_pushcclosure(L, l->func, nup);
PVE_setfield(L, -(nup+2), l->name);
}
PVE_pop(L, nup); /* remove upvalues */
}
/*
** {======================================================
** getn-setn: size for arrays
** =======================================================
*/
#if defined(PVE_COMPAT_GETN)
static int checkint (PVE_State *L, int topop) {
int n = (PVE_type(L, -1) == PVE_TNUMBER) ? PVE_tointeger(L, -1) : -1;
PVE_pop(L, topop);
return n;
}
static void getsizes (PVE_State *L) {
PVE_getfield(L, PVE_REGISTRYINDEX, "PVE_SIZES");
if (PVE_isnil(L, -1)) { /* no `size' table? */
PVE_pop(L, 1); /* remove nil */
PVE_newtable(L); /* create it */
PVE_pushvalue(L, -1); /* `size' will be its own metatable */
PVE_setmetatable(L, -2);
PVE_pushliteral(L, "kv");
PVE_setfield(L, -2, "__mode"); /* metatable(N).__mode = "kv" */
PVE_pushvalue(L, -1);
PVE_setfield(L, PVE_REGISTRYINDEX, "PVE_SIZES"); /* store in register */
}
}
PVELIB_API void PVEL_setn (PVE_State *L, int t, int n) {
t = abs_index(L, t);
PVE_pushliteral(L, "n");
PVE_rawget(L, t);
if (checkint(L, 1) >= 0) { /* is there a numeric field `n'? */
PVE_pushliteral(L, "n"); /* use it */
PVE_pushinteger(L, n);
PVE_rawset(L, t);
}
else { /* use `sizes' */
getsizes(L);
PVE_pushvalue(L, t);
PVE_pushinteger(L, n);
PVE_rawset(L, -3); /* sizes[t] = n */
PVE_pop(L, 1); /* remove `sizes' */
}
}
PVELIB_API int PVEL_getn (PVE_State *L, int t) {
int n;
t = abs_index(L, t);
PVE_pushliteral(L, "n"); /* try t.n */
PVE_rawget(L, t);
if ((n = checkint(L, 1)) >= 0) return n;
getsizes(L); /* else try sizes[t] */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -