4c18eed8b1c573131326303cee1f91b75d98c55a
[project/luci.git] / libs / nixio / src / file.c
1 /*
2  * nixio - Linux I/O library for lua
3  *
4  *   Copyright (C) 2009 Steven Barth <steven@midlink.org>
5  *
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
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  */
18
19 #include "nixio.h"
20 #include <errno.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <sys/file.h>
26
27
28 static int nixio_file(lua_State *L) {
29         const char *filename = luaL_checklstring(L, 1, NULL);
30         const char *mode = luaL_optlstring(L, 2, "r", NULL);
31
32         FILE *file = fopen(filename, mode);
33         if (!file) {
34                 return nixio__perror(L);
35         }
36
37         FILE **udata = lua_newuserdata(L, sizeof(FILE*));
38         if (!udata) {
39                 return luaL_error(L, "out of memory");
40         }
41
42         *udata = file;
43
44         luaL_getmetatable(L, NIXIO_FILE_META);
45         lua_setmetatable(L, -2);
46
47         return 1;
48 }
49
50 static int nixio_pipe(lua_State *L) {
51         int pipefd[2];
52         FILE **udata;
53         if (pipe(pipefd)) {
54                 return nixio__perror(L);
55         }
56
57         luaL_getmetatable(L, NIXIO_FILE_META);
58         udata = lua_newuserdata(L, sizeof(FILE*));
59         if (!udata) {
60                 return luaL_error(L, "out of memory");
61         }
62
63         if (!(*udata = fdopen(pipefd[0], "r"))) {
64                 return nixio__perror(L);
65         }
66         lua_pushvalue(L, -2);
67         lua_setmetatable(L, -2);
68
69
70         udata = lua_newuserdata(L, sizeof(FILE**));
71         if (!(*udata = fdopen(pipefd[1], "w"))) {
72                 return nixio__perror(L);
73         }
74         lua_pushvalue(L, -3);
75         lua_setmetatable(L, -2);
76
77         return 2;
78 }
79
80 static int nixio_file_write(lua_State *L) {
81         FILE *fp = nixio__checkfile(L);
82         size_t len, written;
83         const char *data = luaL_checklstring(L, 2, &len);
84         written = fwrite(data, sizeof(char), len, fp);
85         if (written < 0) {
86                 return nixio__perror(L);
87         } else {
88                 lua_pushnumber(L, written);
89                 return 1;
90         }
91 }
92
93
94 /* Some code borrowed from Lua 5.1.4 liolib.c */
95 static int nixio_file_read(lua_State *L) {
96         FILE *f = nixio__checkfile(L);
97         size_t n = (size_t)luaL_checkinteger(L, 2);
98         luaL_argcheck(L, 2, n >= 0, "invalid length");
99
100         if (n == 0) {
101                 if (feof(f)) {
102                         return 0;
103                 } else {
104                         lua_pushliteral(L, "");
105                         return 1;
106                 }
107         }
108
109         size_t rlen;  /* how much to read */
110         size_t nr;  /* number of chars actually read */
111         luaL_Buffer b;
112         luaL_buffinit(L, &b);
113         rlen = LUAL_BUFFERSIZE;  /* try to read that much each time */
114
115         do {
116                 char *p = luaL_prepbuffer(&b);
117                 if (rlen > n) rlen = n;  /* cannot read more than asked */
118                         nr = fread(p, sizeof(char), rlen, f);
119                         luaL_addsize(&b, nr);
120                         n -= nr;  /* still have to read `n' chars */
121         } while (n > 0 && nr == rlen);  /* until end of count or eof */
122         luaL_pushresult(&b);  /* close buffer */
123         return (n == 0 || lua_objlen(L, -1) > 0);
124 }
125
126 static int nixio_file_seek(lua_State *L) {
127         FILE *f = nixio__checkfile(L);
128         off_t len = (off_t)luaL_checknumber(L, 2);
129         int whence;
130         const char *whstr = luaL_optlstring(L, 3, "set", NULL);
131         if (!strcmp(whstr, "set")) {
132                 whence = SEEK_SET;
133         } else if (!strcmp(whstr, "cur")) {
134                 whence = SEEK_CUR;
135         } else if (!strcmp(whstr, "end")) {
136                 whence = SEEK_END;
137         } else {
138                 return luaL_argerror(L, 3, "supported values: set, cur, end");
139         }
140         return nixio__pstatus(L, !fseeko(f, len, whence));
141 }
142
143 static int nixio_file_tell(lua_State *L) {
144         FILE *f = nixio__checkfile(L);
145         off_t pos = ftello(f);
146         if (pos < 0) {
147                 return nixio__perror(L);
148         } else {
149                 lua_pushnumber(L, (lua_Number)pos);
150                 return 1;
151         }
152 }
153
154 static int nixio_file_flush(lua_State *L) {
155         FILE *f = nixio__checkfile(L);
156         return nixio__pstatus(L, !fflush(f));
157 }
158
159 static int nixio_file_lock(lua_State *L) {
160         int fd = fileno(nixio__checkfile(L));
161
162         const int j = lua_gettop(L);
163         int flags = 0;
164         for (int i=2; i<=j; i++) {
165                 const char *flag = luaL_checkstring(L, i);
166                 if (!strcmp(flag, "sh")) {
167                         flags |= LOCK_SH;
168                 } else if (!strcmp(flag, "ex")) {
169                         flags |= LOCK_EX;
170                 } else if (!strcmp(flag, "un")) {
171                         flags |= LOCK_UN;
172                 } else if (!strcmp(flag, "nb")) {
173                         flags |= LOCK_NB;
174                 } else {
175                         return luaL_argerror(L, i, "supported values: sh, ex, un, nb");
176                 }
177         }
178
179         return nixio__pstatus(L, flock(fd, flags));
180 }
181
182 static int nixio_file_close(lua_State *L) {
183         FILE **fpp = (FILE**)luaL_checkudata(L, 1, NIXIO_FILE_META);
184         luaL_argcheck(L, *fpp, 1, "invalid file object");
185         int res = fclose(*fpp);
186         *fpp = NULL;
187         return nixio__pstatus(L, !res);
188 }
189
190 static int nixio_file__gc(lua_State *L) {
191         FILE **fpp = (FILE**)luaL_checkudata(L, 1, NIXIO_FILE_META);
192         if (*fpp) {
193                 fclose(*fpp);
194                 *fpp = NULL;
195         }
196         return 0;
197 }
198
199 /**
200  * string representation
201  */
202 static int nixio_file__tostring(lua_State *L) {
203         lua_pushfstring(L, "nixio file %d", nixio__tofd(L, 1));
204         return 1;
205 }
206
207 /* method table */
208 static const luaL_reg M[] = {
209         {"write",               nixio_file_write},
210         {"read",                nixio_file_read},
211         {"tell",                nixio_file_tell},
212         {"seek",                nixio_file_seek},
213         {"flush",               nixio_file_flush},
214         {"lock",                nixio_file_lock},
215         {"close",               nixio_file_close},
216         {"__gc",                nixio_file__gc},
217         {"__tostring",  nixio_file__tostring},
218         {NULL,                  NULL}
219 };
220
221 /* module table */
222 static const luaL_reg R[] = {
223         {"open",                nixio_file},
224         {"pipe",                nixio_pipe},
225         {NULL,                  NULL}
226 };
227
228 void nixio_open_file(lua_State *L) {
229         luaL_register(L, NULL, R);
230
231         luaL_newmetatable(L, NIXIO_FILE_META);
232         luaL_register(L, NULL, M);
233         lua_pushvalue(L, -1);
234         lua_setfield(L, -2, "__index");
235         lua_pop(L, 1);
236 }