summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorDaniel Kolesa <d.kolesa@samsung.com>2014-12-12 13:39:57 +0000
committerDaniel Kolesa <d.kolesa@samsung.com>2014-12-12 13:39:57 +0000
commit09869589c9528afef7544753b7229d2cd944cbec (patch)
treea8b656ed25561ded5102a437ced93e046fef1ff3 /src/lib
parent4a1bfdeb4d771f39c49f9d8fc65aa0cde2700de0 (diff)
elua: move caching into the library
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/elua/Elua.h2
-rw-r--r--src/lib/elua/cache.c212
2 files changed, 214 insertions, 0 deletions
diff --git a/src/lib/elua/Elua.h b/src/lib/elua/Elua.h
index bba00e9030..80a8a894a4 100644
--- a/src/lib/elua/Elua.h
+++ b/src/lib/elua/Elua.h
@@ -64,6 +64,8 @@ EAPI int elua_shutdown(void);
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); 66EAPI int elua_io_popen(lua_State *L);
67EAPI int elua_io_loadfile(lua_State *L, const char *fname);
68EAPI void elua_io_register(lua_State *L);
67 69
68#endif 70#endif
69 71
diff --git a/src/lib/elua/cache.c b/src/lib/elua/cache.c
new file mode 100644
index 0000000000..e272843c69
--- /dev/null
+++ b/src/lib/elua/cache.c
@@ -0,0 +1,212 @@
1#include "Elua.h"
2#include "elua_private.h"
3
4#include <sys/types.h>
5#include <sys/stat.h>
6#include <sys/mman.h>
7#include <fcntl.h>
8#include <unistd.h>
9
10/* bytecode caching */
11
12static Eina_File *
13check_bc(Eina_File *of, const char *fname, Eina_Bool *bc)
14{
15 if (of)
16 {
17 struct stat bc_stat, sc_stat;
18 /* original file doesn't exist, only bytecode does, use bytecode */
19 if (stat(fname, &sc_stat) < 0)
20 return of;
21 if (stat(eina_file_filename_get(of), &bc_stat) < 0)
22 {
23 /* what? */
24 eina_file_close(of);
25 goto generate;
26 }
27 /* bytecode is newer than original file, use bytecode */
28 if (bc_stat.st_mtime > sc_stat.st_mtime)
29 return of;
30 /* bytecode is not new enough; trigger regeneration */
31 eina_file_close(of);
32 }
33generate:
34 *bc = EINA_TRUE;
35 return eina_file_open(fname, EINA_FALSE);
36}
37
38static Eina_File *
39open_src(const char *fname, Eina_Bool *bc)
40{
41 Eina_File *f = NULL;
42 const char *ext = strstr(fname, ".lua");
43 if (ext && !ext[4])
44 {
45 char buf[PATH_MAX];
46 snprintf(buf, sizeof(buf), "%sc", fname);
47 f = check_bc(eina_file_open(buf, EINA_FALSE), fname, bc);
48 }
49 if (!f) f = eina_file_open(fname, EINA_FALSE);
50 return f;
51}
52
53static int
54writef(lua_State *L EINA_UNUSED, const void *p, size_t size, void *ud)
55{
56 FILE *f = ud;
57 return ferror(f) || (fwrite(p, 1, size, f) != size);
58}
59
60static FILE *
61bc_tmp_open(const char *fname, char *buf, size_t buflen)
62{
63 int fd;
64#ifndef _WIN32
65 mode_t old_umask;
66#endif
67 char *fs = strrchr(fname, '/'), *bs = strrchr(fname, '\\');
68 if (!fs && !bs)
69 snprintf(buf, buflen, "./XXXXXX");
70 else
71 {
72 char *ss = (fs > bs) ? fs : bs;
73 snprintf(buf, buflen, "%.*sXXXXXX", (int)(ss - fname + 1), fname);
74 }
75#ifndef _WIN32
76 old_umask = umask(S_IRWXG|S_IRWXO);
77#endif
78 fd = mkstemp(buf);
79#ifndef _WIN32
80 umask(old_umask);
81#endif
82 if (fd < 0)
83 return NULL;
84 return fdopen(fd, "w");
85}
86
87static void
88write_bc(lua_State *L, const char *fname)
89{
90 FILE *f;
91 char buf[PATH_MAX];
92 if ((f = bc_tmp_open(fname, buf, sizeof(buf))))
93 {
94 char buf2[PATH_MAX];
95 if (lua_dump(L, writef, f))
96 {
97 fclose(f);
98 /* there really is nothing to handle here */
99 (void)!!remove(buf);
100 }
101 else fclose(f);
102 snprintf(buf2, sizeof(buf2), "%sc", fname);
103 if (rename(buf, buf2))
104 {
105 /* a futile attempt at cleanup */
106 (void)!!remove(buf);
107 (void)!!remove(buf2);
108 }
109 }
110}
111
112static const char *
113getf(lua_State *L EINA_UNUSED, void *ud, size_t *size)
114{
115 char *buff = *((char**)ud);
116 if (feof(stdin)) return NULL;
117 *size = fread(buff, 1, LUAL_BUFFERSIZE, stdin);
118 return (*size > 0) ? buff : NULL;
119}
120
121static int
122elua_loadstdin(lua_State *L)
123{
124 char buff[LUAL_BUFFERSIZE];
125 int status = lua_load(L, getf, &buff, "=stdin");
126 if (ferror(stdin))
127 {
128 lua_pop(L, 1);
129 lua_pushfstring(L, "cannot read stdin: %s", strerror(errno));
130 return LUA_ERRFILE;
131 }
132 return status;
133}
134
135typedef struct Map_Stream
136{
137 char *fmap;
138 size_t flen;
139} Map_Stream;
140
141static const char *
142getf_map(lua_State *L EINA_UNUSED, void *ud, size_t *size)
143{
144 Map_Stream *s = ud;
145 const char *fmap = s->fmap;
146 *size = s->flen;
147 /* gotta null it - tell luajit to terminate reading */
148 s->fmap = NULL;
149 return fmap;
150}
151
152EAPI int
153elua_io_loadfile(lua_State *L, const char *fname)
154{
155 Map_Stream s;
156 int status;
157 Eina_File *f;
158 const char *chname;
159 Eina_Bool bcache = EINA_FALSE;
160 if (!fname)
161 {
162 return elua_loadstdin(L);
163 }
164 if (!(f = open_src(fname, &bcache)))
165 {
166 lua_pushfstring(L, "cannot open %s: %s", fname, strerror(errno));
167 return LUA_ERRFILE;
168 }
169 chname = lua_pushfstring(L, "@%s", fname);
170 s.flen = eina_file_size_get(f);
171 if (!(s.fmap = eina_file_map_all(f, EINA_FILE_RANDOM)))
172 {
173 lua_pushfstring(L, "cannot read %s: %s", chname + 1, strerror(errno));
174 lua_remove(L, -2);
175 return LUA_ERRFILE;
176 }
177 status = lua_load(L, getf_map, &s, chname);
178 eina_file_map_free(f, s.fmap);
179 eina_file_close(f);
180 if (!status && bcache) write_bc(L, fname);
181 lua_remove(L, -2);
182 return status;
183}
184
185/* lua function */
186
187static int
188loadfile(lua_State *L)
189{
190 const char *fname = luaL_optstring(L, 1, NULL);
191 int status = elua_io_loadfile(L, fname),
192 hasenv = (lua_gettop(L) >= 3);
193 if (!status)
194 {
195 if (hasenv)
196 {
197 lua_pushvalue(L, 3);
198 lua_setfenv(L, -2);
199 }
200 return 1;
201 }
202 lua_pushnil(L);
203 lua_insert(L, -2);
204 return 2;
205}
206
207EAPI void
208elua_io_register(lua_State *L)
209{
210 lua_pushcfunction(L, loadfile);
211 lua_setglobal(L, "loadfile");
212}