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 }