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