eabbad0ea78ca2bb4b835e2788b83e7c4e588e11
[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 int lua_image_get_marks(lua_State *L)
117 {
118         FileData *fd;
119
120         fd = lua_check_image(L, 1);
121         lua_pushnumber(L, fd->marks);
122         return 1;
123 }
124
125 static ExifData *lua_check_exif(lua_State *L, int index)
126 {
127         ExifData **exif;
128         luaL_checktype(L, index, LUA_TUSERDATA);
129         exif = (ExifData **)luaL_checkudata(L, index, "Exif");
130         if (exif == NULL) luaL_typerror(L, index, "Exif");
131         return *exif;
132 }
133
134 /* Interface for EXIF data */
135 static int lua_exif_get_datum(lua_State *L)
136 {
137         const gchar *key;
138         gchar *value = NULL;
139         ExifData *exif;
140         struct tm tm;
141         time_t datetime;
142
143         exif = lua_check_exif(L, 1);
144         key = luaL_checkstring(L, 2);
145         if (key == (gchar*)NULL || key[0] == '\0')
146                 {
147                 lua_pushnil(L);
148                 return 1;
149                 }
150         if (!exif)
151                 {
152                 lua_pushnil(L);
153                 return 1;
154                 }
155         value = exif_get_data_as_text(exif, key);
156         if (strcmp(key, "Exif.Photo.DateTimeOriginal") == 0)
157                 {
158                 memset(&tm, 0, sizeof(tm));
159                 if (value && strptime(value, "%Y:%m:%d %H:%M:%S", &tm))
160                         {
161                         datetime = mktime(&tm);
162                         lua_pushnumber(L, datetime);
163                         return 1;
164                         }
165                 else
166                         {
167                         lua_pushnil(L);
168                         return 1;
169                         }
170                 }
171         else if (strcmp(key, "Exif.Photo.DateTimeDigitized") == 0)
172                 {
173                 memset(&tm, 0, sizeof(tm));
174                 if (value && strptime(value, "%Y:%m:%d %H:%M:%S", &tm))
175                         {
176                         datetime = mktime(&tm);
177                         lua_pushnumber(L, datetime);
178                         return 1;
179                         }
180                 else
181                         {
182                         lua_pushnil(L);
183                         return 1;
184                         }
185                 }
186         lua_pushstring(L, value);
187         return 1;
188 }
189
190 /**
191  * \brief Initialize the lua interpreter.
192  */
193 void lua_init(void)
194 {
195         L = luaL_newstate();
196         luaL_openlibs(L); /* Open all libraries for lua programms */
197
198         /* Now create custom methodes to do something */
199         static const luaL_Reg meta_methods[] = {
200                         {NULL, NULL}
201         };
202
203         /* The Image metatable and methodes */
204         static const luaL_Reg image_methods[] = {
205                         {"get_path", lua_image_get_path},
206                         {"get_name", lua_image_get_name},
207                         {"get_extension", lua_image_get_extension},
208                         {"get_date", lua_image_get_date},
209                         {"get_size", lua_image_get_size},
210                         {"get_exif", lua_image_get_exif},
211                         {"get_marks", lua_image_get_marks},
212                         {NULL, NULL}
213         };
214         luaL_register(L, "Image", image_methods);
215         luaL_newmetatable(L, "Image");
216         luaL_register(L, NULL, meta_methods);
217         lua_pushliteral(L, "__index");
218         lua_pushvalue(L, -3);
219         lua_settable(L, -3);
220         lua_pushliteral(L, "__metatable");
221         lua_pushvalue(L, -3);
222         lua_settable(L, -3);
223         lua_pop(L, 1);
224         lua_pop(L, 1);
225
226         /* The Exif table and methodes */
227         static const luaL_Reg exif_methods[] = {
228                         {"get_datum", lua_exif_get_datum},
229                         {NULL, NULL}
230         };
231         luaL_register(L, "Exif", exif_methods);
232         luaL_newmetatable(L, "Exif");
233         luaL_register(L, NULL, meta_methods);
234         lua_pushliteral(L, "__index");
235         lua_pushvalue(L, -3);
236         lua_settable(L, -3);
237         lua_pushliteral(L, "__metatable");
238         lua_pushvalue(L, -3);
239         lua_settable(L, -3);
240         lua_pop(L, 1);
241         lua_pop(L, 1);
242 }
243
244 /**
245  * \brief Call a lua function to get a single value.
246  */
247 gchar *lua_callvalue(FileData *fd, const gchar *file, const gchar *function)
248 {
249         gint result;
250         gchar *data = NULL;
251         gchar *dir;
252         gchar *path;
253         FileData **image_data;
254         gchar *tmp;
255         GError *error = NULL;
256
257         /* Collection Table (Dummy at the moment) */
258         lua_newtable(L);
259         lua_setglobal(L, "Collection");
260
261         /* Current Image */
262         image_data = (FileData **)lua_newuserdata(L, sizeof(FileData *));
263         luaL_getmetatable(L, "Image");
264         lua_setmetatable(L, -2);
265         lua_setglobal(L, "Image");
266
267         *image_data = fd;
268         if (file[0] == '\0')
269                 {
270                 result = luaL_dostring(L, function);
271                 }
272         else
273                 {
274                 dir = g_build_filename(get_rc_dir(), "lua", NULL);
275                 path = g_build_filename(dir, file, NULL);
276                 result = luaL_dofile(L, path);
277                 g_free(path);
278                 g_free(dir);
279                 }
280
281         if (result)
282                 {
283                 data = g_strdup_printf("Error running lua script: %s", lua_tostring(L, -1));
284                 return data;
285                 }
286         data = g_strdup(lua_tostring(L, -1));
287         tmp = g_locale_to_utf8(data, strlen(data), NULL, NULL, &error);
288         if (error)
289                 {
290                 log_printf("Error converting lua output from locale to UTF-8: %s\n", error->message);
291                 g_error_free(error);
292                 }
293         else
294                 {
295                 g_free(data);
296                 data = g_strdup(tmp);
297                 } // if (error) { ... } else
298         return data;
299 }
300
301 #endif
302 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */