2014-02-22 05:44:00 +00:00
|
|
|
/* common.c */
|
|
|
|
/* See Copyright Notice in the file LICENSE */
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "lua.h"
|
|
|
|
#include "lauxlib.h"
|
|
|
|
#include "lrexlib.h"
|
|
|
|
|
|
|
|
#define N_ALIGN sizeof(int)
|
|
|
|
|
|
|
|
/* the table must be on Lua stack top */
|
|
|
|
int get_int_field (lua_State *L, const char* field)
|
|
|
|
{
|
|
|
|
int val;
|
|
|
|
lua_getfield (L, -1, field);
|
|
|
|
val = (int) lua_tointeger (L, -1);
|
|
|
|
lua_pop (L, 1);
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* the table must be on Lua stack top */
|
|
|
|
void set_int_field (lua_State *L, const char* field, int val)
|
|
|
|
{
|
|
|
|
lua_pushinteger (L, val);
|
|
|
|
lua_setfield (L, -2, field);
|
|
|
|
}
|
|
|
|
|
|
|
|
void *Lmalloc(lua_State *L, size_t size) {
|
|
|
|
void *ud;
|
|
|
|
lua_Alloc lalloc = lua_getallocf(L, &ud);
|
|
|
|
return lalloc(ud, NULL, 0, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
void *Lrealloc(lua_State *L, void *p, size_t osize, size_t nsize) {
|
|
|
|
void *ud;
|
|
|
|
lua_Alloc lalloc = lua_getallocf(L, &ud);
|
|
|
|
return lalloc(ud, p, osize, nsize);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Lfree(lua_State *L, void *p, size_t osize) {
|
|
|
|
void *ud;
|
|
|
|
lua_Alloc lalloc = lua_getallocf(L, &ud);
|
|
|
|
lalloc(ud, p, osize, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function fills a table with string-number pairs.
|
|
|
|
The table can be passed as the 1-st lua-function parameter,
|
|
|
|
otherwise it is created. The return value is the filled table.
|
|
|
|
*/
|
|
|
|
int get_flags (lua_State *L, const flag_pair **arrs) {
|
|
|
|
const flag_pair *p;
|
|
|
|
const flag_pair **pp;
|
|
|
|
int nparams = lua_gettop(L);
|
|
|
|
|
|
|
|
if(nparams == 0)
|
|
|
|
lua_newtable(L);
|
|
|
|
else {
|
|
|
|
if(!lua_istable(L, 1))
|
|
|
|
luaL_argerror(L, 1, "not a table");
|
|
|
|
if(nparams > 1)
|
|
|
|
lua_pushvalue(L, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
for(pp=arrs; *pp; ++pp) {
|
|
|
|
for(p=*pp; p->key; ++p) {
|
|
|
|
lua_pushstring(L, p->key);
|
|
|
|
lua_pushinteger(L, p->val);
|
|
|
|
lua_rawset(L, -3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *get_flag_key (const flag_pair *fp, int val) {
|
|
|
|
for (; fp->key; ++fp) {
|
|
|
|
if (fp->val == val)
|
|
|
|
return fp->key;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Classes */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* class TFreeList
|
|
|
|
* ***************
|
|
|
|
* Simple array of pointers to TBuffer's.
|
|
|
|
* The array has fixed capacity (not expanded automatically).
|
|
|
|
*/
|
|
|
|
|
|
|
|
void freelist_init (TFreeList *fl) {
|
|
|
|
fl->top = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void freelist_add (TFreeList *fl, TBuffer *buf) {
|
|
|
|
fl->list[fl->top++] = buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
void freelist_free (TFreeList *fl) {
|
|
|
|
while (fl->top > 0)
|
|
|
|
buffer_free (fl->list[--fl->top]);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* class TBuffer
|
|
|
|
* *************
|
|
|
|
* Auto-extensible array of characters for building long strings incrementally.
|
|
|
|
* * Differs from luaL_Buffer in that:
|
|
|
|
* * its operations do not change Lua stack top position
|
|
|
|
* * buffer_addvalue does not extract the value from Lua stack
|
|
|
|
* * buffer_pushresult does not have to be the last operation
|
|
|
|
* * Uses TFreeList class:
|
|
|
|
* * for inserting itself into a TFreeList instance for future clean-up
|
|
|
|
* * calls freelist_free prior to calling luaL_error.
|
|
|
|
* * Has specialized "Z-operations" for maintaining mixed string/integer
|
|
|
|
* array: bufferZ_addlstring, bufferZ_addnum and bufferZ_next.
|
|
|
|
* * if the array is intended to be "mixed", then the methods
|
|
|
|
* buffer_addlstring and buffer_addvalue must not be used
|
|
|
|
* (the application will crash on bufferZ_next).
|
|
|
|
* * conversely, if the array is not intended to be "mixed",
|
|
|
|
* then the method bufferZ_next must not be used.
|
|
|
|
*/
|
|
|
|
|
|
|
|
enum { ID_NUMBER, ID_STRING };
|
|
|
|
|
|
|
|
void buffer_init (TBuffer *buf, size_t sz, lua_State *L, TFreeList *fl) {
|
2014-03-10 08:32:50 +00:00
|
|
|
buf->arr = (char *)Lmalloc(L, sz);
|
2014-02-22 05:44:00 +00:00
|
|
|
if (!buf->arr) {
|
|
|
|
freelist_free (fl);
|
|
|
|
luaL_error (L, "malloc failed");
|
|
|
|
}
|
|
|
|
buf->size = sz;
|
|
|
|
buf->top = 0;
|
|
|
|
buf->L = L;
|
|
|
|
buf->freelist = fl;
|
|
|
|
freelist_add (fl, buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
void buffer_free (TBuffer *buf) {
|
|
|
|
Lfree(buf->L, buf->arr, buf->size);
|
|
|
|
}
|
|
|
|
|
|
|
|
void buffer_clear (TBuffer *buf) {
|
|
|
|
buf->top = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void buffer_pushresult (TBuffer *buf) {
|
|
|
|
lua_pushlstring (buf->L, buf->arr, buf->top);
|
|
|
|
}
|
|
|
|
|
|
|
|
void buffer_addbuffer (TBuffer *trg, TBuffer *src) {
|
|
|
|
buffer_addlstring (trg, src->arr, src->top);
|
|
|
|
}
|
|
|
|
|
|
|
|
void buffer_addlstring (TBuffer *buf, const void *src, size_t sz) {
|
|
|
|
size_t newtop = buf->top + sz;
|
|
|
|
if (newtop > buf->size) {
|
|
|
|
char *p = (char*) Lrealloc (buf->L, buf->arr, buf->size, 2 * newtop); /* 2x expansion */
|
|
|
|
if (!p) {
|
|
|
|
freelist_free (buf->freelist);
|
|
|
|
luaL_error (buf->L, "realloc failed");
|
|
|
|
}
|
|
|
|
buf->arr = p;
|
|
|
|
buf->size = 2 * newtop;
|
|
|
|
}
|
|
|
|
if (src)
|
|
|
|
memcpy (buf->arr + buf->top, src, sz);
|
|
|
|
buf->top = newtop;
|
|
|
|
}
|
|
|
|
|
|
|
|
void buffer_addvalue (TBuffer *buf, int stackpos) {
|
|
|
|
size_t len;
|
|
|
|
const char *p = lua_tolstring (buf->L, stackpos, &len);
|
|
|
|
buffer_addlstring (buf, p, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
void bufferZ_addlstring (TBuffer *buf, const void *src, size_t len) {
|
|
|
|
int n;
|
|
|
|
size_t header[2] = { ID_STRING };
|
|
|
|
header[1] = len;
|
|
|
|
buffer_addlstring (buf, header, sizeof (header));
|
|
|
|
buffer_addlstring (buf, src, len);
|
|
|
|
n = len % N_ALIGN;
|
|
|
|
if (n) buffer_addlstring (buf, NULL, N_ALIGN - n);
|
|
|
|
}
|
|
|
|
|
|
|
|
void bufferZ_addnum (TBuffer *buf, size_t num) {
|
|
|
|
size_t header[2] = { ID_NUMBER };
|
|
|
|
header[1] = num;
|
|
|
|
buffer_addlstring (buf, header, sizeof (header));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 1. When called repeatedly on the same TBuffer, its existing data
|
|
|
|
is discarded and overwritten by the new data.
|
|
|
|
2. The TBuffer's array is never shrunk by this function.
|
|
|
|
*/
|
|
|
|
void bufferZ_putrepstring (TBuffer *BufRep, int reppos, int nsub) {
|
|
|
|
char dbuf[] = { 0, 0 };
|
|
|
|
size_t replen;
|
|
|
|
const char *p = lua_tolstring (BufRep->L, reppos, &replen);
|
|
|
|
const char *end = p + replen;
|
|
|
|
BufRep->top = 0;
|
|
|
|
while (p < end) {
|
|
|
|
const char *q;
|
|
|
|
for (q = p; q < end && *q != '%'; ++q)
|
|
|
|
{}
|
|
|
|
if (q != p)
|
|
|
|
bufferZ_addlstring (BufRep, p, q - p);
|
|
|
|
if (q < end) {
|
|
|
|
if (++q < end) { /* skip % */
|
|
|
|
if (isdigit (*q)) {
|
|
|
|
int num;
|
|
|
|
*dbuf = *q;
|
|
|
|
num = (int) strtol (dbuf, NULL, 10);
|
|
|
|
if (num == 1 && nsub == 0)
|
|
|
|
num = 0;
|
|
|
|
else if (num > nsub) {
|
|
|
|
freelist_free (BufRep->freelist);
|
|
|
|
luaL_error (BufRep->L, "invalid capture index");
|
|
|
|
}
|
|
|
|
bufferZ_addnum (BufRep, num);
|
|
|
|
}
|
|
|
|
else bufferZ_addlstring (BufRep, q, 1);
|
|
|
|
}
|
|
|
|
p = q + 1;
|
|
|
|
}
|
|
|
|
else break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
The intended use of this function is as follows:
|
|
|
|
size_t iter = 0;
|
|
|
|
while (bufferZ_next (buf, &iter, &num, &str)) {
|
|
|
|
if (str) do_something_with_string (str, num);
|
|
|
|
else do_something_with_number (num);
|
|
|
|
}
|
|
|
|
*******************************************************************************
|
|
|
|
*/
|
|
|
|
int bufferZ_next (TBuffer *buf, size_t *iter, size_t *num, const char **str) {
|
|
|
|
if (*iter < buf->top) {
|
|
|
|
size_t *ptr_header = (size_t*)(buf->arr + *iter);
|
|
|
|
*num = ptr_header[1];
|
|
|
|
*iter += 2 * sizeof (size_t);
|
|
|
|
*str = NULL;
|
|
|
|
if (*ptr_header == ID_STRING) {
|
|
|
|
int n;
|
|
|
|
*str = buf->arr + *iter;
|
|
|
|
*iter += *num;
|
|
|
|
n = *iter % N_ALIGN;
|
|
|
|
if (n) *iter += (N_ALIGN - n);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if LUA_VERSION_NUM > 501
|
|
|
|
int luaL_typerror (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);
|
|
|
|
}
|
|
|
|
#endif
|