diff options
author | Daniel Kolesa <d.kolesa@samsung.com> | 2014-12-12 12:04:10 +0000 |
---|---|---|
committer | Daniel Kolesa <d.kolesa@samsung.com> | 2014-12-12 12:04:10 +0000 |
commit | 4a1bfdeb4d771f39c49f9d8fc65aa0cde2700de0 (patch) | |
tree | 9963277f3cbe4129a9dbaed21d5b1071fe8cdfe7 /src/lib/elua | |
parent | 784045df9ae73f4f74b52b5f2cc7a6254b9b7c1d (diff) |
elua: move io extensions to library
Diffstat (limited to 'src/lib/elua')
-rw-r--r-- | src/lib/elua/Elua.h | 2 | ||||
-rw-r--r-- | src/lib/elua/elua.c | 2 | ||||
-rw-r--r-- | src/lib/elua/io.c | 367 |
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 | ||
64 | EAPI void elua_state_setup_i18n(lua_State *L); | 64 | EAPI void elua_state_setup_i18n(lua_State *L); |
65 | 65 | ||
66 | EAPI 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 */ | ||
6 | static char * | ||
7 | get_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 | |||
56 | static FILE * | ||
57 | elua_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 | |||
77 | static int | ||
78 | push_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 | |||
98 | static FILE * | ||
99 | tofile(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 | |||
109 | static int | ||
110 | elua_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 | |||
118 | static int | ||
119 | elua_flush(lua_State *L) | ||
120 | { | ||
121 | return push_ret(L, fflush(tofile(L)) == 0, NULL); | ||
122 | } | ||
123 | |||
124 | static int elua_readline(lua_State *L); | ||
125 | |||
126 | static int | ||
127 | elua_lines(lua_State *L) | ||
128 | { | ||
129 | lua_pushvalue(L, 1); | ||
130 | lua_pushcclosure(L, elua_readline, 1); | ||
131 | return 1; | ||
132 | } | ||
133 | |||
134 | static int | ||
135 | read_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 | |||
146 | static int | ||
147 | test_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 | |||
155 | static int | ||
156 | read_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 | |||
181 | static int | ||
182 | read_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 | |||
201 | static int | ||
202 | elua_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 | |||
217 | static int | ||
218 | elua_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 | |||
273 | static int | ||
274 | elua_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 | |||
294 | static int | ||
295 | elua_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 | |||
306 | static int | ||
307 | elua_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 | |||
317 | static 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 | |||
329 | static FILE ** | ||
330 | elua_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 | |||
344 | EAPI int | ||
345 | elua_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 | } | ||