2 * --- T2-COPYRIGHT-NOTE-BEGIN ---
3 * This copyright note is auto-generated by ./scripts/Create-CopyPatch.
5 * T2 SDE: misc/lua/lzlib/lzlib.c
6 * Copyright (C) 2004 - 2006 The T2 SDE Project
8 * More information can be found in the files COPYING and README.
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
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
)
43 zlib_result
= Z_ERRNO
;
45 zmessage
= gzerror (*zf
, &zlib_result
);
47 if (zlib_result
== Z_OK
) {
48 lua_pushboolean(L
, 1);
52 if (zlib_result
== Z_ERRNO
) // error is a file io error
53 zmessage
= strerror(errno
);
58 lua_pushfstring(L
, "%s: %s", filename
, zmessage
);
60 lua_pushfstring(L
, "%s", zmessage
);
62 lua_pushinteger(L
, zlib_result
);
63 lua_pushinteger(L
, errno
);
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
));
75 luaL_error(L
, "attempt to use a closed gz file");
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 ()
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
);
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
)
111 content_buffer
[content_length
++] = c
;
114 static inline const char* FinishBuffer ()
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
);
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);
159 const char* zmessage
;
160 if (result
== Z_ERRNO
) // error is a file io error
161 zmessage
= strerror(errno
);
163 zmessage
= zError(result
);
166 lua_pushfstring(L
, zmessage
);
167 lua_pushinteger(L
, result
);
168 lua_pushinteger(L
, errno
);
174 static int __gz_lines_iterator (lua_State
*L
)
176 gzFile zf
= (gzFile
) lua_topointer (L
, lua_upvalueindex(1));
180 if (content_buffer_length
== 0)
185 #ifdef READ_LINE_ONE_BY_ONE
187 while ( (ch
= gzgetc(zf
)) != -1 && ch
!= '\n') {
188 AddToBuffer ((char) ch
);
194 ret
= gzgets (zf
, content_buffer
+ BufferFill (), BufferFree ());
197 int l
= strlen (content_buffer
);
200 ch
= content_buffer
[l
- 1];
204 content_buffer
[l
-1] = '\0';
206 } while (ret
&& ch
!= '\n');
210 if (ch
== '\n' || BufferFill () > 0) {
213 lua_pushstring (L
, FinishBuffer ());
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);
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
);
241 const char* eof_reason
;
243 eof_reason
= gzerror (*zf
, &eof_reason_code
);
244 lua_pushboolean (L
, eof_reason_code
== Z_STREAM_END
);
245 lua_pushstring (L
, eof_reason
);
251 // ------------------- init and registering --------------------
253 static const luaL_reg R
[] = {
257 {"status", gz_status
},
262 static const luaL_Reg zlib
[] = {
265 {"status", gz_status
},
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
)
281 luaL_openlib(L
, "lzlib", R
, 0);
282 lua_pushliteral(L
,"version"); /** version */
283 lua_pushliteral(L
,"pre-alpha");