nixio next
[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
26
27 static int nixio_file(lua_State *L) {
28         const char *filename = luaL_checklstring(L, 1, NULL);
29         const char *mode = luaL_optlstring(L, 2, "r", NULL);
30
31         FILE *file = fopen(filename, mode);
32         if (!file) {
33                 return nixio__perror(L);
34         }
35
36         FILE **udata = lua_newuserdata(L, sizeof(FILE**));
37         *udata = file;
38
39         luaL_getmetatable(L, NIXIO_FILE_META);
40         lua_setmetatable(L, -2);
41
42         return 1;
43 }
44
45 static int nixio_pipe(lua_State *L) {
46         int pipefd[2];
47         FILE **udata;
48         if (pipe(pipefd)) {
49                 return nixio__perror(L);
50         }
51
52         luaL_getmetatable(L, NIXIO_FILE_META);
53         udata = lua_newuserdata(L, sizeof(FILE**));
54         if (!(*udata = fdopen(pipefd[0], "r"))) {
55                 return nixio__perror(L);
56         }
57         lua_pushvalue(L, -2);
58         lua_setmetatable(L, -2);
59
60
61         udata = lua_newuserdata(L, sizeof(FILE**));
62         if (!(*udata = fdopen(pipefd[1], "w"))) {
63                 return nixio__perror(L);
64         }
65         lua_pushvalue(L, -3);
66         lua_setmetatable(L, -2);
67
68         return 2;
69 }
70
71 static int nixio_file_write(lua_State *L) {
72         FILE *fp = nixio__checkfile(L);
73         size_t len, written;
74         const char *data = luaL_checklstring(L, 2, &len);
75         written = fwrite(data, sizeof(char), len, fp);
76         if (written < 0) {
77                 return nixio__perror(L);
78         } else {
79                 return written;
80         }
81 }
82
83
84 /* Some code borrowed from Lua 5.1.4 liolib.c */
85 static int nixio_file_read(lua_State *L) {
86         FILE *f = nixio__checkfile(L);
87         size_t n = (size_t)luaL_checkinteger(L, 2);
88         luaL_argcheck(L, 2, n >= 0, "invalid length");
89
90         if (n == 0) {
91                 if (feof(f)) {
92                         return 0;
93                 } else {
94                         lua_pushliteral(L, "");
95                         return 1;
96                 }
97         }
98
99         size_t rlen;  /* how much to read */
100         size_t nr;  /* number of chars actually read */
101         luaL_Buffer b;
102         luaL_buffinit(L, &b);
103         rlen = LUAL_BUFFERSIZE;  /* try to read that much each time */
104
105         do {
106                 char *p = luaL_prepbuffer(&b);
107                 if (rlen > n) rlen = n;  /* cannot read more than asked */
108                         nr = fread(p, sizeof(char), rlen, f);
109                         luaL_addsize(&b, nr);
110                         n -= nr;  /* still have to read `n' chars */
111         } while (n > 0 && nr == rlen);  /* until end of count or eof */
112         luaL_pushresult(&b);  /* close buffer */
113         return (n == 0 || lua_objlen(L, -1) > 0);
114 }
115
116 static int nixio_file_seek(lua_State *L) {
117         FILE *f = nixio__checkfile(L);
118         off_t len = (off_t)luaL_checknumber(L, 2);
119         int whence;
120         const char *whstr = luaL_optlstring(L, 3, "set", NULL);
121         if (!strcmp(whstr, "set")) {
122                 whence = SEEK_SET;
123         } else if (!strcmp(whstr, "cur")) {
124                 whence = SEEK_CUR;
125         } else if (!strcmp(whstr, "end")) {
126                 whence = SEEK_END;
127         } else {
128                 return luaL_argerror(L, 3, "supported values: set, cur, end");
129         }
130         return nixio__pstatus(L, !fseeko(f, len, whence));
131 }
132
133 static int nixio_file_tell(lua_State *L) {
134         FILE *f = nixio__checkfile(L);
135         off_t pos = ftello(f);
136         if (pos < 0) {
137                 return nixio__perror(L);
138         } else {
139                 lua_pushnumber(L, (lua_Number)pos);
140                 return 1;
141         }
142 }
143
144 static int nixio_file_flush(lua_State *L) {
145         FILE *f = nixio__checkfile(L);
146         return nixio__pstatus(L, !fflush(f));
147 }
148
149 static int nixio_file_close(lua_State *L) {
150         FILE **fpp = (FILE**)luaL_checkudata(L, 1, NIXIO_FILE_META);
151         luaL_argcheck(L, *fpp, 1, "invalid file object");
152         int res = fclose(*fpp);
153         *fpp = NULL;
154         return nixio__pstatus(L, !res);
155 }
156
157 static int nixio_file__gc(lua_State *L) {
158         FILE **fpp = (FILE**)luaL_checkudata(L, 1, NIXIO_FILE_META);
159         if (*fpp) {
160                 fclose(*fpp);
161                 *fpp = NULL;
162         }
163         return 0;
164 }
165
166 /**
167  * string representation
168  */
169 static int nixio_file__tostring(lua_State *L) {
170         lua_pushfstring(L, "nixio file %d", nixio__tofd(L, 1));
171         return 1;
172 }
173
174 /* method table */
175 static const luaL_reg M[] = {
176         {"write",               nixio_file_write},
177         {"read",                nixio_file_read},
178         {"tell",                nixio_file_tell},
179         {"seek",                nixio_file_seek},
180         {"flush",               nixio_file_flush},
181         {"close",               nixio_file_close},
182         {"__gc",                nixio_file__gc},
183         {"__tostring",  nixio_file__tostring},
184         {NULL,                  NULL}
185 };
186
187 /* module table */
188 static const luaL_reg R[] = {
189         {"open",                nixio_file},
190         {"pipe",                nixio_pipe},
191         {NULL,                  NULL}
192 };
193
194 void nixio_open_file(lua_State *L) {
195         luaL_register(L, NULL, R);
196
197         luaL_newmetatable(L, NIXIO_FILE_META);
198         luaL_register(L, NULL, M);
199         lua_pushvalue(L, -1);
200         lua_setfield(L, -2, "__index");
201         lua_pop(L, 1);
202 }