* updated libkcddb (21.12.1 -> 21.12.2), untested
[t2-trunk.git] / misc / lua / lzlib / lzlib.c
blob10d4799bd849e6f6033dbe883c49dcd8d7b93ac9
1 /*
2 * --- T2-COPYRIGHT-NOTE-BEGIN ---
3 * This copyright note is auto-generated by ./scripts/Create-CopyPatch.
4 *
5 * T2 SDE: misc/lua/lzlib/lzlib.c
6 * Copyright (C) 2004 - 2006 The T2 SDE Project
7 *
8 * More information can be found in the files COPYING and README.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2 of the License. A copy of the
13 * GNU General Public License can be found in the file COPYING.
14 * --- T2-COPYRIGHT-NOTE-END ---
16 // compilation: gcc --shared lzlib.c -o lzlib.so -lz
17 // contains some slightly addapted code pieces from lua's liolib.c
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <errno.h>
23 #include <zlib.h>
24 #include <lua.h>
25 #include <lauxlib.h>
27 #define ZLIB_HANDLE "gzFile"
29 // ------------------- helper functions ------------------------
31 // pushes gzFile operation result string on lua stack
33 // first value is either true or nil (== operation failed),
34 // in the latter case a string containing the error message and
35 // the nummerical error codes (gzerror / errno) are returned
36 // as additional values
38 static int pushresult (lua_State *L, gzFile* zf, const char *filename)
40 int zlib_result;
41 const char* zmessage;
42 if ((zf) == NULL)
43 zlib_result = Z_ERRNO;
44 else
45 zmessage = gzerror (*zf, &zlib_result);
47 if (zlib_result == Z_OK) {
48 lua_pushboolean(L, 1);
49 return 1;
50 } else {
52 if (zlib_result == Z_ERRNO) // error is a file io error
53 zmessage = strerror(errno);
55 lua_pushnil(L);
57 if (filename)
58 lua_pushfstring(L, "%s: %s", filename, zmessage);
59 else
60 lua_pushfstring(L, "%s", zmessage);
62 lua_pushinteger(L, zlib_result);
63 lua_pushinteger(L, errno);
65 return 4;
69 // ensures first argument is an open zlib handle and returns it
70 static gzFile *tozfile (lua_State *L)
72 gzFile *zf = ((gzFile *) luaL_checkudata(L, 1, ZLIB_HANDLE));
74 if (*zf == NULL)
75 luaL_error(L, "attempt to use a closed gz file");
76 return zf;
79 // ----------------- poor man buffer in C ---------------------
81 char* content_buffer = NULL;
82 size_t content_buffer_length = 0;
83 size_t content_length = 0;
85 static inline void ResetBuffer ()
87 content_length = 0;
90 static inline void ExtendBufferBySize (size_t min_size)
92 if (min_size > content_buffer_length) {
93 if (content_buffer_length == 0)
94 content_buffer = malloc (min_size);
95 else
96 content_buffer = realloc (content_buffer, min_size);
97 content_buffer_length = min_size;
101 static inline void ExtendBuffer ()
103 ExtendBufferBySize ((content_buffer_length < 256) ? 256 : 2 * content_buffer_length);
104 // for testing: ExtendBufferBySize ((content_buffer_length < 10) ? 10 : 2 + content_buffer_length);
107 static inline void AddToBuffer (char c)
109 if (content_buffer_length == content_length)
110 ExtendBuffer ();
111 content_buffer [content_length++] = c;
114 static inline const char* FinishBuffer ()
116 AddToBuffer ('\0');
117 return content_buffer;
120 static inline int BufferFill ()
122 return content_length;
125 static inline int BufferFree ()
127 return (content_buffer_length - content_length);
130 // -------------------------- API ------------------------------
132 static int gz_open (lua_State *L)
134 const char *filename = luaL_checkstring(L, 1);
135 const char *mode = luaL_optstring(L, 2, "r");
137 gzFile* zf = (gzFile *) lua_newuserdata(L, sizeof(gzFile));
138 luaL_getmetatable(L, ZLIB_HANDLE);
139 lua_setmetatable(L, -2);
141 *zf = gzopen(filename, mode);
143 return (*zf == NULL) ? pushresult(L, NULL, filename) : 1;
146 static int gz_close (lua_State *L)
148 gzFile *zf = tozfile(L);
149 int result = gzclose(*zf);
150 *zf = NULL;
152 // need to emulate pushresult behavior, because gzerror
153 // does not work anymore after closing stream *grrrr*
155 if (result == Z_OK) {
156 lua_pushboolean (L, 1);
157 return 1;
158 } else {
159 const char* zmessage;
160 if (result == Z_ERRNO) // error is a file io error
161 zmessage = strerror(errno);
162 else
163 zmessage = zError(result);
165 lua_pushnil(L);
166 lua_pushfstring(L, zmessage);
167 lua_pushinteger(L, result);
168 lua_pushinteger(L, errno);
169 return 4;
174 static int __gz_lines_iterator (lua_State *L)
176 gzFile zf = (gzFile) lua_topointer (L, lua_upvalueindex(1));
177 int ch = '\0';
178 char* ret;
180 if (content_buffer_length == 0)
181 ExtendBuffer ();
182 else
183 ResetBuffer ();
185 #ifdef READ_LINE_ONE_BY_ONE
187 while ( (ch = gzgetc(zf)) != -1 && ch != '\n') {
188 AddToBuffer ((char) ch);
191 #else
193 do {
194 ret = gzgets (zf, content_buffer + BufferFill (), BufferFree ());
195 if (ret == Z_NULL)
196 break;
197 int l = strlen (content_buffer);
198 content_length = l;
199 if (l > 0) {
200 ch = content_buffer[l - 1];
201 if (ch != '\n')
202 ExtendBuffer ();
203 else
204 content_buffer[l-1] = '\0';
206 } while (ret && ch != '\n');
208 #endif
210 if (ch == '\n' || BufferFill () > 0) {
211 if (ch == '\n')
213 lua_pushstring (L, FinishBuffer ());
214 return 1;
215 } else {
216 return pushresult(L, &zf, NULL);
221 static int gz_lines (lua_State *L)
223 gzFile *zf = tozfile(L);
224 lua_pushlightuserdata (L, *zf);
225 lua_pushcclosure (L, __gz_lines_iterator, 1);
226 return 1;
229 static int gz_status (lua_State *L)
231 gzFile *zf = tozfile(L);
232 return pushresult (L, zf, NULL);
235 static int gz_eof (lua_State *L)
237 gzFile *zf = tozfile(L);
238 int eof = gzeof (*zf);
239 lua_pushboolean(L, eof);
240 if (eof == 1) {
241 const char* eof_reason;
242 int eof_reason_code;
243 eof_reason = gzerror (*zf, &eof_reason_code);
244 lua_pushboolean (L, eof_reason_code == Z_STREAM_END);
245 lua_pushstring (L, eof_reason);
246 return 3;
248 return 0;
251 // ------------------- init and registering --------------------
253 static const luaL_reg R[] = {
254 {"open", gz_open},
255 {"close", gz_close},
256 {"lines", gz_lines},
257 {"status", gz_status},
258 {"eof", gz_eof},
259 {NULL, NULL}
262 static const luaL_Reg zlib[] = {
263 {"close", gz_close},
264 {"lines", gz_lines},
265 {"status", gz_status},
266 {"eof", gz_eof},
267 {"__gc", gz_close},
268 {NULL, NULL}
271 static void createmeta (lua_State *L) {
272 luaL_newmetatable(L, ZLIB_HANDLE); /* create metatable for zlib handles */
273 lua_pushvalue(L, -1); /* push metatable */
274 lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
275 luaL_register(L, NULL, zlib); /* gz file methods */
278 LUALIB_API int luaopen_lzlib (lua_State *L)
280 createmeta(L);
281 luaL_openlib(L, "lzlib", R, 0);
282 lua_pushliteral(L,"version"); /** version */
283 lua_pushliteral(L,"pre-alpha");
284 lua_settable(L,-3);
285 return 1;