diff options
author | Daniel Kolesa <d.kolesa@samsung.com> | 2014-12-12 13:39:57 +0000 |
---|---|---|
committer | Daniel Kolesa <d.kolesa@samsung.com> | 2014-12-12 13:39:57 +0000 |
commit | 09869589c9528afef7544753b7229d2cd944cbec (patch) | |
tree | a8b656ed25561ded5102a437ced93e046fef1ff3 /src/lib/elua | |
parent | 4a1bfdeb4d771f39c49f9d8fc65aa0cde2700de0 (diff) |
elua: move caching into the library
Diffstat (limited to 'src/lib/elua')
-rw-r--r-- | src/lib/elua/Elua.h | 2 | ||||
-rw-r--r-- | src/lib/elua/cache.c | 212 |
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); | |||
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); | 66 | EAPI int elua_io_popen(lua_State *L); |
67 | EAPI int elua_io_loadfile(lua_State *L, const char *fname); | ||
68 | EAPI 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 | |||
12 | static Eina_File * | ||
13 | check_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 | } | ||
33 | generate: | ||
34 | *bc = EINA_TRUE; | ||
35 | return eina_file_open(fname, EINA_FALSE); | ||
36 | } | ||
37 | |||
38 | static Eina_File * | ||
39 | open_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 | |||
53 | static int | ||
54 | writef(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 | |||
60 | static FILE * | ||
61 | bc_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 | |||
87 | static void | ||
88 | write_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 | |||
112 | static const char * | ||
113 | getf(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 | |||
121 | static int | ||
122 | elua_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 | |||
135 | typedef struct Map_Stream | ||
136 | { | ||
137 | char *fmap; | ||
138 | size_t flen; | ||
139 | } Map_Stream; | ||
140 | |||
141 | static const char * | ||
142 | getf_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 | |||
152 | EAPI int | ||
153 | elua_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 | |||
187 | static int | ||
188 | loadfile(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 | |||
207 | EAPI void | ||
208 | elua_io_register(lua_State *L) | ||
209 | { | ||
210 | lua_pushcfunction(L, loadfile); | ||
211 | lua_setglobal(L, "loadfile"); | ||
212 | } | ||