2 * nixio - Linux I/O library for lua
4 * Copyright (C) 2009 Steven Barth <steven@midlink.org>
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
26 #include <sys/types.h>
28 #include <sys/param.h>
31 static int nixio_open(lua_State *L) {
32 const char *filename = luaL_checklstring(L, 1, NULL);
35 if (lua_isnoneornil(L, 2)) {
37 } else if (lua_isnumber(L, 2)) {
38 flags = lua_tointeger(L, 2);
39 } else if (lua_isstring(L, 2)) {
40 const char *str = lua_tostring(L, 2);
41 if (!strcmp(str, "r")) {
43 } else if (!strcmp(str, "r+")) {
45 } else if (!strcmp(str, "w")) {
46 flags = O_WRONLY | O_CREAT | O_TRUNC;
47 } else if (!strcmp(str, "w+")) {
48 flags = O_RDWR | O_CREAT | O_TRUNC;
49 } else if (!strcmp(str, "a")) {
50 flags = O_WRONLY | O_CREAT | O_APPEND;
51 } else if (!strcmp(str, "a+")) {
52 flags = O_RDWR | O_CREAT | O_APPEND;
54 return luaL_argerror(L, 2, "supported values: r, r+, w, w+, a, a+");
57 return luaL_argerror(L, 2, "open flags or string expected");
63 fd = open(filename, flags, nixio__check_mode(L, 3, 0666));
64 } while (fd == -1 && errno == EINTR);
66 return nixio__perror(L);
69 int *udata = lua_newuserdata(L, sizeof(int));
71 return luaL_error(L, "out of memory");
76 luaL_getmetatable(L, NIXIO_FILE_META);
77 lua_setmetatable(L, -2);
82 static int nixio_mkstemp(lua_State *L) {
83 const char *intemplate = luaL_checklstring(L, 1, NULL);
84 size_t len = lua_strlen(L, 1);
85 char *template = (char *)lua_newuserdata(L, 13 + len);
87 return luaL_error(L, "out of memory");
89 snprintf(template, 13 + len, "/tmp/%s.XXXXXX", intemplate);
94 fd = mkstemp(template);
95 } while (fd == -1 && errno == EINTR);
97 return nixio__perror(L);
101 int *udata = lua_newuserdata(L, sizeof(int));
103 return luaL_error(L, "out of memory");
108 luaL_getmetatable(L, NIXIO_FILE_META);
109 lua_setmetatable(L, -2);
114 static int nixio_open_flags(lua_State *L) {
116 const int j = lua_gettop(L);
117 for (int i=1; i<=j; i++) {
118 const char *flag = luaL_checkstring(L, i);
119 if (!strcmp(flag, "append")) {
121 } else if (!strcmp(flag, "creat")) {
123 } else if (!strcmp(flag, "excl")) {
125 } else if (!strcmp(flag, "nonblock") || !strcmp(flag, "ndelay")) {
129 } else if (!strcmp(flag, "sync")) {
133 } else if (!strcmp(flag, "trunc")) {
135 } else if (!strcmp(flag, "rdonly")) {
137 } else if (!strcmp(flag, "wronly")) {
139 } else if (!strcmp(flag, "rdwr")) {
142 return luaL_argerror(L, i, "supported values: append, creat, "
143 "excl, nonblock, ndelay, sync, trunc");
146 lua_pushinteger(L, mode);
150 static int nixio_dup(lua_State *L) {
151 int oldfd = nixio__checkfd(L, 1);
152 int newfd = (lua_gettop(L) > 1) ? nixio__checkfd(L, 2) : -1;
153 int stat = (newfd == -1) ? dup(oldfd) : dup2(oldfd, newfd);
156 return nixio__perror(L);
159 int *udata = lua_newuserdata(L, sizeof(int));
161 return luaL_error(L, "out of memory");
165 luaL_getmetatable(L, NIXIO_FILE_META);
166 lua_setmetatable(L, -2);
174 static int nixio_pipe(lua_State *L) {
175 int pipefd[2], *udata;
177 return nixio__perror(L);
180 luaL_getmetatable(L, NIXIO_FILE_META);
181 udata = lua_newuserdata(L, sizeof(int));
183 return luaL_error(L, "out of memory");
187 lua_pushvalue(L, -2);
188 lua_setmetatable(L, -2);
191 udata = lua_newuserdata(L, sizeof(int));
193 return luaL_error(L, "out of memory");
197 lua_pushvalue(L, -3);
198 lua_setmetatable(L, -2);
203 static int nixio_file_write(lua_State *L) {
204 int fd = nixio__checkfd(L, 1);
207 const char *data = luaL_checklstring(L, 2, &len);
209 if (lua_gettop(L) > 2) {
210 int offset = luaL_optint(L, 3, 0);
220 unsigned int wlen = luaL_optint(L, 4, len);
227 sent = write(fd, data, len);
228 } while(sent == -1 && errno == EINTR);
230 lua_pushinteger(L, sent);
233 return nixio__perror(L);
237 static int nixio_file_read(lua_State *L) {
238 int fd = nixio__checkfd(L, 1);
239 char buffer[NIXIO_BUFFERSIZE];
240 uint req = luaL_checkinteger(L, 2);
243 /* We limit the readsize to NIXIO_BUFFERSIZE */
244 req = (req > NIXIO_BUFFERSIZE) ? NIXIO_BUFFERSIZE : req;
247 readc = read(fd, buffer, req);
248 } while (readc == -1 && errno == EINTR);
251 return nixio__perror(L);
253 lua_pushlstring(L, buffer, readc);
259 static int nixio_file_seek(lua_State *L) {
260 int fd = nixio__checkfd(L, 1);
261 off_t len = (off_t)nixio__checknumber(L, 2);
263 const char *whstr = luaL_optlstring(L, 3, "set", NULL);
264 if (!strcmp(whstr, "set")) {
266 } else if (!strcmp(whstr, "cur")) {
268 } else if (!strcmp(whstr, "end")) {
271 return luaL_argerror(L, 3, "supported values: set, cur, end");
273 len = lseek(fd, len, whence);
275 return nixio__perror(L);
277 nixio__pushnumber(L, len);
282 static int nixio_file_tell(lua_State *L) {
283 int fd = nixio__checkfd(L, 1);
284 off_t pos = lseek(fd, 0, SEEK_CUR);
286 return nixio__perror(L);
288 nixio__pushnumber(L, pos);
293 static int nixio_file_stat(lua_State *L) {
295 if (fstat(nixio__checkfd(L, 1), &buf)) {
296 return nixio__perror(L);
298 nixio__push_stat(L, &buf);
299 if (lua_isstring(L, 2)) {
300 lua_getfield(L, -1, lua_tostring(L, 2));
306 static int nixio_file_sync(lua_State *L) {
307 int fd = nixio__checkfd(L, 1);
309 #if (!defined BSD && !defined __WINNT__)
310 int dataonly = lua_toboolean(L, 2);
312 stat = (dataonly) ? fdatasync(fd) : fsync(fd);
313 } while (stat == -1 && errno == EINTR);
314 return nixio__pstatus(L, !stat);
318 } while (stat == -1 && errno == EINTR);
319 return nixio__pstatus(L, !stat);
323 static int nixio_file_lock(lua_State *L) {
324 int fd = nixio__checkfd(L, 1);
325 const char *flag = luaL_checkstring(L, 2);
326 off_t len = (off_t)nixio__optnumber(L, 3, 0);
330 if (!strcmp(flag, "lock")) {
332 } else if (!strcmp(flag, "tlock")) {
334 } else if (!strcmp(flag, "ulock")) {
336 } else if (!strcmp(flag, "test")) {
339 return luaL_argerror(L, 2,
340 "supported values: lock, tlock, ulock, test");
344 stat = lockf(fd, cmd, len);
345 } while (stat == -1 && errno == EINTR);
347 return nixio__pstatus(L, !stat);
350 static int nixio_file_close(lua_State *L) {
351 int *fdp = luaL_checkudata(L, 1, NIXIO_FILE_META);
352 luaL_argcheck(L, *fdp != -1, 1, "invalid file object");
356 } while (res == -1 && errno == EINTR);
358 return nixio__pstatus(L, !res);
361 static int nixio_file__gc(lua_State *L) {
362 int *fdp = luaL_checkudata(L, 1, NIXIO_FILE_META);
367 } while (res == -1 && errno == EINTR);
374 * string representation
376 static int nixio_file__tostring(lua_State *L) {
377 lua_pushfstring(L, "nixio file %d", nixio__tofd(L, 1));
382 static const luaL_reg M[] = {
383 {"write", nixio_file_write},
384 {"read", nixio_file_read},
385 {"tell", nixio_file_tell},
386 {"seek", nixio_file_seek},
387 {"stat", nixio_file_stat},
388 {"sync", nixio_file_sync},
389 {"lock", nixio_file_lock},
390 {"close", nixio_file_close},
391 {"__gc", nixio_file__gc},
392 {"__tostring", nixio_file__tostring},
397 static const luaL_reg R[] = {
399 {"open", nixio_open},
400 {"open_flags", nixio_open_flags},
401 {"mkstemp", nixio_mkstemp},
402 {"pipe", nixio_pipe},
406 void nixio_open_file(lua_State *L) {
407 luaL_register(L, NULL, R);
409 luaL_newmetatable(L, NIXIO_FILE_META);
410 luaL_register(L, NULL, M);
411 lua_pushvalue(L, -1);
412 lua_setfield(L, -2, "__index");
414 int *uin = lua_newuserdata(L, sizeof(int));
415 int *uout = lua_newuserdata(L, sizeof(int));
416 int *uerr = lua_newuserdata(L, sizeof(int));
418 if (!uin || !uout || !uerr) {
419 luaL_error(L, "out of memory");
423 *uout = STDOUT_FILENO;
424 *uerr = STDERR_FILENO;
426 for (int i = -4; i < -1; i++) {
427 lua_pushvalue(L, -4);
428 lua_setmetatable(L, i);
431 lua_setfield(L, -5, "stderr");
432 lua_setfield(L, -4, "stdout");
433 lua_setfield(L, -3, "stdin");
434 lua_setfield(L, -2, "meta_file");