summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorDaniel Kolesa <d.kolesa@samsung.com>2014-12-12 12:04:10 +0000
committerDaniel Kolesa <d.kolesa@samsung.com>2014-12-12 12:04:10 +0000
commit4a1bfdeb4d771f39c49f9d8fc65aa0cde2700de0 (patch)
tree9963277f3cbe4129a9dbaed21d5b1071fe8cdfe7 /src/lib
parent784045df9ae73f4f74b52b5f2cc7a6254b9b7c1d (diff)
elua: move io extensions to library
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/elua/Elua.h2
-rw-r--r--src/lib/elua/elua.c2
-rw-r--r--src/lib/elua/io.c367
3 files changed, 369 insertions, 2 deletions
diff --git a/src/lib/elua/Elua.h b/src/lib/elua/Elua.h
index 7b8387eae0..bba00e9030 100644
--- a/src/lib/elua/Elua.h
+++ b/src/lib/elua/Elua.h
@@ -63,6 +63,8 @@ EAPI int elua_shutdown(void);
63 63
64EAPI void elua_state_setup_i18n(lua_State *L); 64EAPI void elua_state_setup_i18n(lua_State *L);
65 65
66EAPI int elua_io_popen(lua_State *L);
67
66#endif 68#endif
67 69
68#ifdef __cplusplus 70#ifdef __cplusplus
diff --git a/src/lib/elua/elua.c b/src/lib/elua/elua.c
index ea23bc6cdc..f4411ae1e9 100644
--- a/src/lib/elua/elua.c
+++ b/src/lib/elua/elua.c
@@ -1,5 +1,3 @@
1#include <Eina.h>
2
3#include "Elua.h" 1#include "Elua.h"
4#include "elua_private.h" 2#include "elua_private.h"
5 3
diff --git a/src/lib/elua/io.c b/src/lib/elua/io.c
new file mode 100644
index 0000000000..4b73a3b789
--- /dev/null
+++ b/src/lib/elua/io.c
@@ -0,0 +1,367 @@
1#include "Elua.h"
2#include "elua_private.h"
3
4/* expand fname to full path name (so that PATH is ignored) plus turn
5 * stuff into a command, and also verify whether the path exists */
6static char *
7get_cmdline_from_argv(const char *fname, const char **argv)
8{
9 Eina_Strbuf *buf;
10 char *ret;
11 char pbuf[PATH_MAX];
12 const char *arg = NULL;
13
14 FILE *testf = fopen(fname, "r");
15 if (!testf)
16 return NULL;
17
18 fclose(testf);
19
20 /* for windows, we have realpath in evil, no need for GetFullPathName */
21 if (!realpath(fname, pbuf))
22 return NULL;
23
24 buf = eina_strbuf_new();
25 eina_strbuf_append_char(buf, '"');
26 eina_strbuf_append(buf, pbuf);
27 eina_strbuf_append_char(buf, '"');
28
29 while ((arg = *(argv++)))
30 {
31 char c;
32 eina_strbuf_append_char(buf, ' ');
33 eina_strbuf_append_char(buf, '"');
34
35 while ((c = *(arg++)))
36 {
37#ifndef _WIN32
38 if (c == '"' || c == '$') eina_strbuf_append_char(buf, '\\');
39 eina_strbuf_append_char(buf, c);
40#else
41 if (c == '"') eina_strbuf_append_char(buf, '\\');
42 else if (c == '%') eina_strbuf_append_char(buf, '"');
43 eina_strbuf_append_char(buf, c);
44 if (c == '%') eina_strbuf_append_char(buf, '"');
45#endif
46 }
47
48 eina_strbuf_append_char(buf, '"');
49 }
50
51 ret = strdup(eina_strbuf_string_get(buf));
52 eina_strbuf_free(buf);
53 return ret;
54}
55
56static FILE *
57elua_popen_c(const char *path, const char *md, const char *argv[])
58{
59 FILE *ret;
60
61 char *cmdline = get_cmdline_from_argv(path, argv);
62 if (!cmdline) return NULL;
63
64#ifndef _WIN32
65 ret = popen(cmdline, md);
66#else
67 ret = _popen(cmdline, md);
68#endif
69
70 free(cmdline);
71
72 if (!ret) return NULL;
73
74 return ret;
75}
76
77static int
78push_ret(lua_State *L, int i, const char *fname)
79{
80 int en = errno;
81 if (i)
82 {
83 lua_pushboolean(L, 1);
84 return 1;
85 }
86 else
87 {
88 lua_pushnil(L);
89 if (fname)
90 lua_pushfstring(L, "%s: %s", fname, strerror(en));
91 else
92 lua_pushfstring(L, "%s", strerror(en));
93 lua_pushinteger(L, en);
94 return 3;
95 }
96}
97
98static FILE *
99tofile(lua_State *L)
100{
101 FILE **f = (FILE**)luaL_checkudata(L, 1, "ELUA_FILE*");
102 if (!*f)
103 {
104 luaL_error(L, "attempt to use a closed file");
105 }
106 return *f;
107}
108
109static int
110elua_close(lua_State *L)
111{
112 FILE **f = (FILE**)luaL_checkudata(L, 1, "ELUA_FILE*");
113 int ok = (fclose(*f) == 0);
114 if (ok) *f = NULL;
115 return push_ret(L, ok, NULL);
116}
117
118static int
119elua_flush(lua_State *L)
120{
121 return push_ret(L, fflush(tofile(L)) == 0, NULL);
122}
123
124static int elua_readline(lua_State *L);
125
126static int
127elua_lines(lua_State *L)
128{
129 lua_pushvalue(L, 1);
130 lua_pushcclosure(L, elua_readline, 1);
131 return 1;
132}
133
134static int
135read_number(lua_State *L, FILE *f)
136{
137 lua_Number d;
138 if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1)
139 {
140 lua_pushnumber(L, d);
141 return 1;
142 }
143 return 0;
144}
145
146static int
147test_eof(lua_State *L, FILE *f)
148{
149 int c = getc(f);
150 ungetc(c, f);
151 lua_pushlstring(L, NULL, 0);
152 return (c != EOF);
153}
154
155static int
156read_line(lua_State *L, FILE *f)
157{
158 luaL_Buffer b;
159 luaL_buffinit(L, &b);
160 for (;;)
161 {
162 size_t l;
163 char *p = luaL_prepbuffer(&b);
164 if (fgets(p, LUAL_BUFFERSIZE, f) == NULL)
165 {
166 luaL_pushresult(&b);
167 return (lua_strlen(L, -1) > 0);
168 }
169 l = strlen(p);
170 if (!l || p[l - 1] != '\n')
171 luaL_addsize(&b, l);
172 else
173 {
174 luaL_addsize(&b, l - 1);
175 luaL_pushresult(&b);
176 return 1;
177 }
178 }
179}
180
181static int
182read_chars(lua_State *L, FILE *f, size_t n)
183{
184 size_t rlen;
185 size_t nr;
186 luaL_Buffer b;
187 luaL_buffinit(L, &b);
188 rlen = LUAL_BUFFERSIZE;
189 do
190 {
191 char *p = luaL_prepbuffer(&b);
192 if (rlen > n) rlen = n;
193 nr = fread(p, sizeof(char), rlen, f);
194 luaL_addsize(&b, nr);
195 n -= nr;
196 } while (n > 0 && nr == rlen);
197 luaL_pushresult(&b);
198 return (n == 0 || lua_strlen(L, -1) > 0);
199}
200
201static int
202elua_readline(lua_State *L)
203{
204 FILE *f = *(FILE**)lua_touserdata(L, lua_upvalueindex(1));
205 int success;
206 if (!f)
207 {
208 luaL_error(L, "file is already closed");
209 return 0; /* shut up coverity; luaL_error does a longjmp */
210 }
211 success = read_line(L, f);
212 if (ferror(f))
213 return luaL_error(L, "%s", strerror(errno));
214 return success;
215}
216
217static int
218elua_read(lua_State *L)
219{
220 FILE *f = tofile(L);
221 int nargs = lua_gettop(L) - 1;
222 int first = 2;
223 int success, n;
224 clearerr(f);
225 if (!nargs)
226 {
227 success = read_line(L, f);
228 n = first + 1;
229 }
230 else
231 {
232 luaL_checkstack(L, nargs + LUA_MINSTACK, "too many arguments");
233 success = 1;
234 for (n = first; nargs-- && success; ++n)
235 {
236 if (lua_type(L, n) == LUA_TNUMBER)
237 {
238 size_t l = (size_t)lua_tointeger(L, n);
239 success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l);
240 }
241 else
242 {
243 const char *p = lua_tostring(L, n);
244 luaL_argcheck(L, p && p[0] == '*', n, "invalid option");
245 switch (p[1])
246 {
247 case 'n':
248 success = read_number(L, f);
249 break;
250 case 'l':
251 success = read_line(L, f);
252 break;
253 case 'a':
254 read_chars(L, f, ~((size_t)0));
255 success = 1;
256 break;
257 default:
258 return luaL_argerror(L, n, "invalid format");
259 }
260 }
261 }
262 }
263 if (ferror(f))
264 return push_ret(L, 0, NULL);
265 if (!success)
266 {
267 lua_pop(L, 1);
268 lua_pushnil(L);
269 }
270 return n - first;
271}
272
273static int
274elua_write(lua_State *L)
275{
276 FILE *f = tofile(L);
277 int nargs = lua_gettop(L) - 1;
278 int status = 1, arg = 2;
279 for (; nargs--; ++arg)
280 {
281 if (lua_type(L, arg) == LUA_TNUMBER)
282 status = status && (fprintf(f, LUA_NUMBER_FMT,
283 lua_tonumber(L, arg)) > 0);
284 else
285 {
286 size_t l;
287 const char *s = luaL_checklstring(L, arg, &l);
288 status = status && (fwrite(s, sizeof(char), l, f) == l);
289 }
290 }
291 return push_ret(L, status, NULL);
292}
293
294static int
295elua_fgc(lua_State *L)
296{
297 FILE **f = (FILE**)luaL_checkudata(L, 1, "ELUA_FILE*");
298 if (*f)
299 {
300 fclose(*f);
301 *f = NULL;
302 }
303 return 0;
304}
305
306static int
307elua_ftostring(lua_State *L)
308{
309 FILE *f = *((FILE**)luaL_checkudata(L, 1, "ELUA_FILE*"));
310 if (!f)
311 lua_pushliteral(L, "file (closed)");
312 else
313 lua_pushfstring(L, "file (%p)", f);
314 return 1;
315}
316
317static const luaL_reg elua_popenlib[] =
318{
319 { "close" , elua_close },
320 { "flush" , elua_flush },
321 { "lines" , elua_lines },
322 { "read" , elua_read },
323 { "write" , elua_write },
324 { "__gc" , elua_fgc },
325 { "__tostring", elua_ftostring },
326 { NULL , NULL }
327};
328
329static FILE **
330elua_newfile(lua_State *L)
331{
332 FILE **f = (FILE**)lua_newuserdata(L, sizeof(FILE*));
333 *f = NULL;
334 if (luaL_newmetatable(L, "ELUA_FILE*"))
335 {
336 lua_pushvalue(L, -1);
337 lua_setfield (L, -2, "__index");
338 luaL_register(L, NULL, elua_popenlib);
339 }
340 lua_setmetatable(L, -2);
341 return f;
342}
343
344EAPI int
345elua_io_popen(lua_State *L)
346{
347 const char *fname = luaL_checkstring(L, 1);
348 const char *mode = luaL_optstring(L, 2, "r");
349 int nargs = lua_gettop(L) - 2;
350 FILE **pf = elua_newfile(L);
351 if (nargs > 0)
352 {
353 const char **argv = (const char**)alloca((nargs + 1) * sizeof(char*));
354 memset(argv, 0, (nargs + 1) * sizeof(char*));
355 for (; nargs; --nargs)
356 {
357 argv[nargs - 1] = lua_tostring(L, nargs + 2);
358 }
359 *pf = elua_popen_c(fname, mode, argv);
360 }
361 else
362 {
363 const char *argv = NULL;
364 *pf = elua_popen_c(fname, mode, &argv);
365 }
366 return (!*pf) ? push_ret(L, 0, fname) : 1;
367}