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 }