1 /************************************************************************
2 * Author : Tiago Dionizio (tngd@mega.ist.utl.pt) *
3 * Library : lgzip - a gzip file access binding for Lua 5 *
4 * based on liolib.c from Lua 5.0 library *
6 * Permission is hereby granted, free of charge, to any person obtaining *
7 * a copy of this software and associated documentation files (the *
8 * "Software"), to deal in the Software without restriction, including *
9 * without limitation the rights to use, copy, modify, merge, publish, *
10 * distribute, sublicense, and/or sell copies of the Software, and to *
11 * permit persons to whom the Software is furnished to do so, subject to *
12 * the following conditions: *
14 * The above copyright notice and this permission notice shall be *
15 * included in all copies or substantial portions of the Software. *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*
20 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY *
21 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, *
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE *
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
24 ************************************************************************/
26 /************************************************************************
27 $Id: lgzip.c,v 1.2 2003/12/28 01:26:16 tngd Exp $
29 ************************************************************************/
42 ** {======================================================
44 ** =======================================================
48 #define FILEHANDLE "zlib.gzFile"
51 static int pushresult (lua_State
*L
, int i
, const char *filename
) {
53 lua_pushboolean(L
, 1);
59 lua_pushfstring(L
, "%s: %s", filename
, strerror(errno
));
61 lua_pushfstring(L
, "%s", strerror(errno
));
62 lua_pushnumber(L
, errno
);
68 static gzFile
*topfile (lua_State
*L
, int findex
) {
69 gzFile
*f
= (gzFile
*)luaL_checkudata(L
, findex
, FILEHANDLE
);
70 if (f
== NULL
) luaL_argerror(L
, findex
, "bad file");
75 static gzFile
tofile (lua_State
*L
, int findex
) {
76 gzFile
*f
= topfile(L
, findex
);
78 luaL_error(L
, "attempt to use a closed file");
85 ** When creating file handles, always creates a `closed' file handle
86 ** before opening the actual file; so, if there is a memory error, the
87 ** file is not left opened.
89 static gzFile
*newfile (lua_State
*L
) {
90 gzFile
*pf
= (gzFile
*)lua_newuserdata(L
, sizeof(gzFile
));
91 *pf
= NULL
; /* file handle is currently `closed' */
92 luaL_getmetatable(L
, FILEHANDLE
);
93 lua_setmetatable(L
, -2);
98 static int aux_close (lua_State
*L
) {
99 gzFile f
= tofile(L
, 1);
100 int ok
= (gzclose(f
) == Z_OK
);
102 *(gzFile
*)lua_touserdata(L
, 1) = NULL
; /* mark file as closed */
107 static int io_close (lua_State
*L
) {
108 return pushresult(L
, aux_close(L
), NULL
);
112 static int io_gc (lua_State
*L
) {
113 gzFile
*f
= topfile(L
, 1);
114 if (*f
!= NULL
) /* ignore closed files */
120 static int io_tostring (lua_State
*L
) {
122 gzFile
*f
= topfile(L
, 1);
124 strcpy(buff
, "closed");
126 sprintf(buff
, "%p", lua_touserdata(L
, 1));
127 lua_pushfstring(L
, "gzip file (%s)", buff
);
132 static int io_open (lua_State
*L
) {
133 const char *filename
= luaL_checkstring(L
, 1);
134 const char *mode
= luaL_optstring(L
, 2, "rb");
135 gzFile
*pf
= newfile(L
);
136 *pf
= gzopen(filename
, mode
);
137 return (*pf
== NULL
) ? pushresult(L
, 0, filename
) : 1;
141 static int io_readline (lua_State
*L
);
143 static void aux_lines (lua_State
*L
, int idx
, int close
) {
144 lua_pushliteral(L
, FILEHANDLE
);
145 lua_rawget(L
, LUA_REGISTRYINDEX
);
146 lua_pushvalue(L
, idx
);
147 lua_pushboolean(L
, close
); /* close/not close file when finished */
148 lua_pushcclosure(L
, io_readline
, 3);
152 static int f_lines (lua_State
*L
) {
153 tofile(L
, 1); /* check that it's a valid file handle */
159 static int io_lines (lua_State
*L
) {
160 const char *filename
= luaL_checkstring(L
, 1);
161 gzFile
*pf
= newfile(L
);
162 *pf
= gzopen(filename
, "rb");
163 luaL_argcheck(L
, *pf
, 1, strerror(errno
));
164 aux_lines(L
, lua_gettop(L
), 1);
170 ** {======================================================
172 ** =======================================================
176 static int test_eof (lua_State
*L
, gzFile f
) {
177 lua_pushlstring(L
, NULL
, 0);
178 return (gzeof(f
) != 1);
182 static int read_line (lua_State
*L
, gzFile f
) {
184 luaL_buffinit(L
, &b
);
187 char *p
= luaL_prepbuffer(&b
);
188 if (gzgets(f
, p
, LUAL_BUFFERSIZE
) == NULL
) { /* eof? */
189 luaL_pushresult(&b
); /* close buffer */
190 return (lua_rawlen(L
, -1) > 0); /* check whether read something */
196 luaL_addsize(&b
, l
- 1); /* do not include `eol' */
197 luaL_pushresult(&b
); /* close buffer */
198 return 1; /* read at least an `eol' */
204 static int read_chars (lua_State
*L
, gzFile f
, size_t n
) {
205 size_t rlen
; /* how much to read */
206 size_t nr
; /* number of chars actually read */
208 luaL_buffinit(L
, &b
);
209 rlen
= LUAL_BUFFERSIZE
; /* try to read that much each time */
211 char *p
= luaL_prepbuffer(&b
);
212 if (rlen
> n
) rlen
= n
; /* cannot read more than asked */
213 nr
= gzread(f
, p
, rlen
);
214 luaL_addsize(&b
, nr
);
215 n
-= nr
; /* still have to read `n' chars */
216 } while (n
> 0 && nr
== rlen
); /* until end of count or eof */
217 luaL_pushresult(&b
); /* close buffer */
218 return (n
== 0 || lua_rawlen(L
, -1) > 0);
222 static int g_read (lua_State
*L
, gzFile f
, int first
) {
223 int nargs
= lua_gettop(L
) - 1;
226 if (nargs
== 0) { /* no arguments? */
227 success
= read_line(L
, f
);
228 n
= first
+1; /* to return 1 result */
230 else { /* ensure stack space for all results and for auxlib's buffer */
231 luaL_checkstack(L
, nargs
+LUA_MINSTACK
, "too many arguments");
233 for (n
= first
; nargs
-- && success
; n
++) {
234 if (lua_type(L
, n
) == LUA_TNUMBER
) {
235 size_t l
= (size_t)lua_tonumber(L
, n
);
236 success
= (l
== 0) ? test_eof(L
, f
) : read_chars(L
, f
, l
);
239 const char *p
= lua_tostring(L
, n
);
240 luaL_argcheck(L
, p
&& p
[0] == '*', n
, "invalid option");
243 success
= read_line(L
, f
);
246 read_chars(L
, f
, ~((size_t)0)); /* read MAX_SIZE_T chars */
247 success
= 1; /* always success */
250 return luaL_argerror(L
, n
, "invalid format");
256 lua_pop(L
, 1); /* remove last result */
257 lua_pushnil(L
); /* push nil instead */
263 static int f_read (lua_State
*L
) {
264 return g_read(L
, tofile(L
, 1), 2);
268 static int io_readline (lua_State
*L
) {
269 gzFile f
= *(gzFile
*)lua_touserdata(L
, lua_upvalueindex(2));
270 if (f
== NULL
) /* file is already closed? */
271 luaL_error(L
, "file is already closed");
272 if (read_line(L
, f
)) return 1;
274 if (lua_toboolean(L
, lua_upvalueindex(3))) { /* generator created file? */
276 lua_pushvalue(L
, lua_upvalueindex(2));
277 aux_close(L
); /* close it */
283 /* }====================================================== */
286 static int g_write (lua_State
*L
, gzFile f
, int arg
) {
287 int nargs
= lua_gettop(L
) - 1;
289 for (; nargs
--; arg
++) {
290 if (lua_type(L
, arg
) == LUA_TNUMBER
) {
291 /* optimization: could be done exactly as for strings */
293 gzprintf(f
, LUA_NUMBER_FMT
, lua_tonumber(L
, arg
)) > 0;
297 const char *s
= luaL_checklstring(L
, arg
, &l
);
298 status
= status
&& (gzwrite(f
, (char*)s
, l
) == l
);
301 return pushresult(L
, status
, NULL
);
305 static int f_write (lua_State
*L
) {
306 return g_write(L
, tofile(L
, 1), 2);
310 static int f_seek (lua_State
*L
) {
311 static const int mode
[] = {SEEK_SET
, SEEK_CUR
};
312 static const char *const modenames
[] = {"set", "cur", NULL
};
313 gzFile f
= tofile(L
, 1);
314 int op
= luaL_checkoption(L
, 2, "cur", modenames
);
315 long offset
= luaL_optlong(L
, 3, 0);
316 luaL_argcheck(L
, op
!= -1, 2, "invalid mode");
317 op
= gzseek(f
, offset
, mode
[op
]);
319 return pushresult(L
, 0, NULL
); /* error */
321 lua_pushnumber(L
, op
);
327 static int f_flush (lua_State
*L
) {
328 return pushresult(L
, gzflush(tofile(L
, 1), Z_FINISH
) == Z_OK
, NULL
);
332 static const luaL_Reg iolib
[] = {
340 static const luaL_Reg flib
[] = {
348 {"__tostring", io_tostring
},
353 static void createmeta (lua_State
*L
) {
354 luaL_newmetatable(L
, FILEHANDLE
); /* create new metatable for file handles */
356 lua_pushliteral(L
, "__index");
357 lua_pushvalue(L
, -2); /* push metatable */
358 lua_rawset(L
, -3); /* metatable.__index = metatable */
359 luaL_openlib(L
, NULL
, flib
, 0);
363 /* }====================================================== */
367 LUALIB_API
int luaopen_gzip (lua_State
*L
) {
369 lua_pushvalue(L
, -1);
370 luaL_openlib(L
, "gzip", iolib
, 1);