Fix #314: Remote commands for thumbnail maintenance
[geeqie.git] / src / lua.c
1 /*
2  * Copyright (C) 2008 - 2016 The Geeqie Team
3  *
4  * Author: Klaus Ethgen
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 #include "config.h"
22
23 #ifdef HAVE_LUA
24
25 #define _XOPEN_SOURCE
26
27 #include <lua.h>
28 #include <lauxlib.h>
29 #include <lualib.h>
30
31 #include <stdio.h>
32 #include <glib.h>
33 #include <string.h>
34 #include <time.h>
35
36 #include "main.h"
37 #include "glua.h"
38 #include "ui_fileops.h"
39 #include "exif.h"
40
41 static lua_State *L; /** The LUA object needed for all operations (NOTE: That is
42                        * a upper-case variable to match the documentation!) */
43
44 static FileData *lua_check_image(lua_State *L, int index)
45 {
46         FileData **fd;
47         luaL_checktype(L, index, LUA_TUSERDATA);
48         fd = (FileData **)luaL_checkudata(L, index, "Image");
49         if (fd == NULL) luaL_typerror(L, index, "Image");
50         return *fd;
51 }
52
53 static int lua_image_get_exif(lua_State *L)
54 {
55         FileData *fd;
56         ExifData *exif;
57         ExifData **exif_data;
58
59         fd = lua_check_image(L, 1);
60         exif = exif_read_fd(fd);
61
62         exif_data = (ExifData **)lua_newuserdata(L, sizeof(ExifData *));
63         luaL_getmetatable(L, "Exif");
64         lua_setmetatable(L, -2);
65
66         *exif_data = exif;
67
68         return 1;
69 }
70
71 static int lua_image_get_path(lua_State *L)
72 {
73         FileData *fd;
74
75         fd = lua_check_image(L, 1);
76         lua_pushstring(L, fd->path);
77         return 1;
78 }
79
80 static int lua_image_get_name(lua_State *L)
81 {
82         FileData *fd;
83
84         fd = lua_check_image(L, 1);
85         lua_pushstring(L, fd->name);
86         return 1;
87 }
88
89 static int lua_image_get_extension(lua_State *L)
90 {
91         FileData *fd;
92
93         fd = lua_check_image(L, 1);
94         lua_pushstring(L, fd->extension);
95         return 1;
96 }
97
98 static int lua_image_get_date(lua_State *L)
99 {
100         FileData *fd;
101
102         fd = lua_check_image(L, 1);
103         lua_pushnumber(L, fd->date);
104         return 1;
105 }
106
107 static int lua_image_get_size(lua_State *L)
108 {
109         FileData *fd;
110
111         fd = lua_check_image(L, 1);
112         lua_pushnumber(L, fd->size);
113         return 1;
114 }
115
116 static ExifData *lua_check_exif(lua_State *L, int index)
117 {
118         ExifData **exif;
119         luaL_checktype(L, index, LUA_TUSERDATA);
120         exif = (ExifData **)luaL_checkudata(L, index, "Exif");
121         if (exif == NULL) luaL_typerror(L, index, "Exif");
122         return *exif;
123 }
124
125 /* Interface for EXIF data */
126 static int lua_exif_get_datum(lua_State *L)
127 {
128         const gchar *key;
129         gchar *value = NULL;
130         ExifData *exif;
131         struct tm tm;
132         time_t datetime;
133
134         exif = lua_check_exif(L, 1);
135         key = luaL_checkstring(L, 2);
136         if (key == (gchar*)NULL || key[0] == '\0')
137                 {
138                 lua_pushnil(L);
139                 return 1;
140                 }
141         if (!exif)
142                 {
143                 lua_pushnil(L);
144                 return 1;
145                 }
146         value = exif_get_data_as_text(exif, key);
147         if (strcmp(key, "Exif.Photo.DateTimeOriginal") == 0)
148                 {
149                 memset(&tm, 0, sizeof(tm));
150                 if (value && strptime(value, "%Y:%m:%d %H:%M:%S", &tm))
151                         {
152                         datetime = mktime(&tm);
153                         lua_pushnumber(L, datetime);
154                         return 1;
155                         }
156                 else
157                         {
158                         lua_pushnil(L);
159                         return 1;
160                         }
161                 } // if (strcmp(key, "Exif.Photo.Da...
162         lua_pushstring(L, value);
163         return 1;
164 }
165
166 /**
167  * \brief Initialize the lua interpreter.
168  */
169 void lua_init(void)
170 {
171         L = luaL_newstate();
172         luaL_openlibs(L); /* Open all libraries for lua programms */
173
174         /* Now create custom methodes to do something */
175         static const luaL_Reg meta_methods[] = {
176                         {NULL, NULL}
177         };
178
179         /* The Image metatable and methodes */
180         static const luaL_Reg image_methods[] = {
181                         {"get_path", lua_image_get_path},
182                         {"get_name", lua_image_get_name},
183                         {"get_extension", lua_image_get_extension},
184                         {"get_date", lua_image_get_date},
185                         {"get_size", lua_image_get_size},
186                         {"get_exif", lua_image_get_exif},
187                         {NULL, NULL}
188         };
189         luaL_register(L, "Image", image_methods);
190         luaL_newmetatable(L, "Image");
191         luaL_register(L, NULL, meta_methods);
192         lua_pushliteral(L, "__index");
193         lua_pushvalue(L, -3);
194         lua_settable(L, -3);
195         lua_pushliteral(L, "__metatable");
196         lua_pushvalue(L, -3);
197         lua_settable(L, -3);
198         lua_pop(L, 1);
199         lua_pop(L, 1);
200
201         /* The Exif table and methodes */
202         static const luaL_Reg exif_methods[] = {
203                         {"get_datum", lua_exif_get_datum},
204                         {NULL, NULL}
205         };
206         luaL_register(L, "Exif", exif_methods);
207         luaL_newmetatable(L, "Exif");
208         luaL_register(L, NULL, meta_methods);
209         lua_pushliteral(L, "__index");
210         lua_pushvalue(L, -3);
211         lua_settable(L, -3);
212         lua_pushliteral(L, "__metatable");
213         lua_pushvalue(L, -3);
214         lua_settable(L, -3);
215         lua_pop(L, 1);
216         lua_pop(L, 1);
217 }
218
219 /**
220  * \brief Call a lua function to get a single value.
221  */
222 gchar *lua_callvalue(FileData *fd, const gchar *file, const gchar *function)
223 {
224         gint result;
225         gchar *data = NULL;
226         gchar *dir;
227         gchar *path;
228         FileData **image_data;
229         gchar *tmp;
230         GError *error = NULL;
231
232         /* Collection Table (Dummy at the moment) */
233         lua_newtable(L);
234         lua_setglobal(L, "Collection");
235
236         /* Current Image */
237         image_data = (FileData **)lua_newuserdata(L, sizeof(FileData *));
238         luaL_getmetatable(L, "Image");
239         lua_setmetatable(L, -2);
240         lua_setglobal(L, "Image");
241
242         *image_data = fd;
243         if (file[0] == '\0')
244                 {
245                 result = luaL_dostring(L, function);
246                 }
247         else
248                 {
249                 dir = g_build_filename(get_rc_dir(), "lua", NULL);
250                 path = g_build_filename(dir, file, NULL);
251                 result = luaL_dofile(L, path);
252                 g_free(path);
253                 g_free(dir);
254                 }
255
256         if (result)
257                 {
258                 data = g_strdup_printf("Error running lua script: %s", lua_tostring(L, -1));
259                 return data;
260                 }
261         data = g_strdup(lua_tostring(L, -1));
262         tmp = g_locale_to_utf8(data, strlen(data), NULL, NULL, &error);
263         if (error)
264                 {
265                 log_printf("Error converting lua output from locale to UTF-8: %s\n", error->message);
266                 g_error_free(error);
267                 }
268         else
269                 {
270                 g_free(data);
271                 data = g_strdup(tmp);
272                 } // if (error) { ... } else
273         return data;
274 }
275
276 #endif
277 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */