OpenSDE Framework (without history before r20070)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

286 lines
6.5 KiB

/*
* --- T2-COPYRIGHT-NOTE-BEGIN ---
* This copyright note is auto-generated by ./scripts/Create-CopyPatch.
*
* T2 SDE: misc/lua/lzlib/lzlib.c
* Copyright (C) 2004 - 2006 The T2 SDE Project
*
* More information can be found in the files COPYING and README.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License. A copy of the
* GNU General Public License can be found in the file COPYING.
* --- T2-COPYRIGHT-NOTE-END ---
*/
// compilation: gcc --shared lzlib.c -o lzlib.so -lz
// contains some slightly addapted code pieces from lua's liolib.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <zlib.h>
#include <lua.h>
#include <lauxlib.h>
#define ZLIB_HANDLE "gzFile"
// ------------------- helper functions ------------------------
// pushes gzFile operation result string on lua stack
// first value is either true or nil (== operation failed),
// in the latter case a string containing the error message and
// the nummerical error codes (gzerror / errno) are returned
// as additional values
static int pushresult (lua_State *L, gzFile* zf, const char *filename)
{
int zlib_result;
const char* zmessage;
if ((zf) == NULL)
zlib_result = Z_ERRNO;
else
zmessage = gzerror (*zf, &zlib_result);
if (zlib_result == Z_OK) {
lua_pushboolean(L, 1);
return 1;
} else {
if (zlib_result == Z_ERRNO) // error is a file io error
zmessage = strerror(errno);
lua_pushnil(L);
if (filename)
lua_pushfstring(L, "%s: %s", filename, zmessage);
else
lua_pushfstring(L, "%s", zmessage);
lua_pushinteger(L, zlib_result);
lua_pushinteger(L, errno);
return 4;
}
}
// ensures first argument is an open zlib handle and returns it
static gzFile *tozfile (lua_State *L)
{
gzFile *zf = ((gzFile *) luaL_checkudata(L, 1, ZLIB_HANDLE));
if (*zf == NULL)
luaL_error(L, "attempt to use a closed gz file");
return zf;
}
// ----------------- poor man buffer in C ---------------------
char* content_buffer = NULL;
size_t content_buffer_length = 0;
size_t content_length = 0;
static inline void ResetBuffer ()
{
content_length = 0;
}
static inline void ExtendBufferBySize (size_t min_size)
{
if (min_size > content_buffer_length) {
if (content_buffer_length == 0)
content_buffer = malloc (min_size);
else
content_buffer = realloc (content_buffer, min_size);
content_buffer_length = min_size;
}
}
static inline void ExtendBuffer ()
{
ExtendBufferBySize ((content_buffer_length < 256) ? 256 : 2 * content_buffer_length);
// for testing: ExtendBufferBySize ((content_buffer_length < 10) ? 10 : 2 + content_buffer_length);
}
static inline void AddToBuffer (char c)
{
if (content_buffer_length == content_length)
ExtendBuffer ();
content_buffer [content_length++] = c;
}
static inline const char* FinishBuffer ()
{
AddToBuffer ('\0');
return content_buffer;
}
static inline int BufferFill ()
{
return content_length;
}
static inline int BufferFree ()
{
return (content_buffer_length - content_length);
}
// -------------------------- API ------------------------------
static int gz_open (lua_State *L)
{
const char *filename = luaL_checkstring(L, 1);
const char *mode = luaL_optstring(L, 2, "r");
gzFile* zf = (gzFile *) lua_newuserdata(L, sizeof(gzFile));
luaL_getmetatable(L, ZLIB_HANDLE);
lua_setmetatable(L, -2);
*zf = gzopen(filename, mode);
return (*zf == NULL) ? pushresult(L, NULL, filename) : 1;
}
static int gz_close (lua_State *L)
{
gzFile *zf = tozfile(L);
int result = gzclose(*zf);
*zf = NULL;
// need to emulate pushresult behavior, because gzerror
// does not work anymore after closing stream *grrrr*
if (result == Z_OK) {
lua_pushboolean (L, 1);
return 1;
} else {
const char* zmessage;
if (result == Z_ERRNO) // error is a file io error
zmessage = strerror(errno);
else
zmessage = zError(result);
lua_pushnil(L);
lua_pushfstring(L, zmessage);
lua_pushinteger(L, result);
lua_pushinteger(L, errno);
return 4;
}
}
static int __gz_lines_iterator (lua_State *L)
{
gzFile zf = (gzFile) lua_topointer (L, lua_upvalueindex(1));
int ch = '\0';
char* ret;
if (content_buffer_length == 0)
ExtendBuffer ();
else
ResetBuffer ();
#ifdef READ_LINE_ONE_BY_ONE
while ( (ch = gzgetc(zf)) != -1 && ch != '\n') {
AddToBuffer ((char) ch);
}
#else
do {
ret = gzgets (zf, content_buffer + BufferFill (), BufferFree ());
if (ret == Z_NULL)
break;
int l = strlen (content_buffer);
content_length = l;
if (l > 0) {
ch = content_buffer[l - 1];
if (ch != '\n')
ExtendBuffer ();
else
content_buffer[l-1] = '\0';
}
} while (ret && ch != '\n');
#endif
if (ch == '\n' || BufferFill () > 0) {
if (ch == '\n')
lua_pushstring (L, FinishBuffer ());
return 1;
} else {
return pushresult(L, &zf, NULL);
}
}
static int gz_lines (lua_State *L)
{
gzFile *zf = tozfile(L);
lua_pushlightuserdata (L, *zf);
lua_pushcclosure (L, __gz_lines_iterator, 1);
return 1;
}
static int gz_status (lua_State *L)
{
gzFile *zf = tozfile(L);
return pushresult (L, zf, NULL);
}
static int gz_eof (lua_State *L)
{
gzFile *zf = tozfile(L);
int eof = gzeof (*zf);
lua_pushboolean(L, eof);
if (eof == 1) {
const char* eof_reason;
int eof_reason_code;
eof_reason = gzerror (*zf, &eof_reason_code);
lua_pushboolean (L, eof_reason_code == Z_STREAM_END);
lua_pushstring (L, eof_reason);
return 3;
}
return 0;
}
// ------------------- init and registering --------------------
static const luaL_reg R[] = {
{"open", gz_open},
{"close", gz_close},
{"lines", gz_lines},
{"status", gz_status},
{"eof", gz_eof},
{NULL, NULL}
};
static const luaL_Reg zlib[] = {
{"close", gz_close},
{"lines", gz_lines},
{"status", gz_status},
{"eof", gz_eof},
{"__gc", gz_close},
{NULL, NULL}
};
static void createmeta (lua_State *L) {
luaL_newmetatable(L, ZLIB_HANDLE); /* create metatable for zlib handles */
lua_pushvalue(L, -1); /* push metatable */
lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
luaL_register(L, NULL, zlib); /* gz file methods */
}
LUALIB_API int luaopen_lzlib (lua_State *L)
{
createmeta(L);
luaL_openlib(L, "lzlib", R, 0);
lua_pushliteral(L,"version"); /** version */
lua_pushliteral(L,"pre-alpha");
lua_settable(L,-3);
return 1;
}