comparison scid/theme.c @ 30:43333d18e4b8

scid: document theme
author David Demelier <markand@malikania.fr>
date Thu, 04 Aug 2022 14:54:43 +0200
parents 695637f1d8a7
children 081e1c258e64
comparison
equal deleted inserted replaced
29:695637f1d8a7 30:43333d18e4b8
1 /*
2 * theme.c -- theme management
3 *
4 * Copyright (c) 2021 David Demelier <markand@malikania.fr>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
1 #include <assert.h> 19 #include <assert.h>
2 #include <errno.h> 20 #include <errno.h>
3 #include <limits.h> 21 #include <limits.h>
4 #include <string.h> 22 #include <string.h>
5 23
12 #include "theme.h" 30 #include "theme.h"
13 #include "util.h" 31 #include "util.h"
14 32
15 #define SIGNATURE DUK_HIDDEN_SYMBOL("File") 33 #define SIGNATURE DUK_HIDDEN_SYMBOL("File")
16 34
17 struct theme { 35 static struct {
18 char base[PATH_MAX];
19 duk_context *ctx; 36 duk_context *ctx;
20 }; 37 } theme;
21 38
22 /* {{{ mustache support */ 39 /* {{{ mustache support */
23 40
24 static void 41 static void
25 mch_parse_error(int code, const char *msg, unsigned int line, unsigned int col, void *data) 42 mch_parse_error(int code, const char *msg, unsigned int line, unsigned int col, void *data)
196 .get_child_by_index = mch_get_child_by_index, 213 .get_child_by_index = mch_get_child_by_index,
197 .get_partial = mch_get_partial 214 .get_partial = mch_get_partial
198 }; 215 };
199 MUSTACHE_TEMPLATE *tmpl; 216 MUSTACHE_TEMPLATE *tmpl;
200 int status; 217 int status;
201 218
202 if (!(tmpl = mustache_compile(input, strlen(input), &parser, (void *)path, 0))) 219 if (!(tmpl = mustache_compile(input, strlen(input), &parser, (void *)path, 0)))
203 return -1; 220 return -1;
204 221
205 status = mustache_process(tmpl, &rdr, fp, &pv, doc); 222 status = mustache_process(tmpl, &rdr, fp, &pv, doc);
206 mustache_release(tmpl); 223 mustache_release(tmpl);
239 json_error_t err; 256 json_error_t err;
240 257
241 if (json && !(doc = json_loads(json, 0, &err))) 258 if (json && !(doc = json_loads(json, 0, &err)))
242 return duk_error(ctx, DUK_ERR_ERROR, "%d:%d:%s", err.line, err.column, err.text); 259 return duk_error(ctx, DUK_ERR_ERROR, "%d:%d:%s", err.line, err.column, err.text);
243 260
244 mch_templatize(fp, theme_path(scid.theme, path), doc); 261 mch_templatize(fp, theme_path(path), doc);
245 262
246 if (doc) 263 if (doc)
247 json_decref(doc); 264 json_decref(doc);
248 265
249 return 0; 266 return 0;
264 }; 281 };
265 282
266 /* }}} */ 283 /* }}} */
267 284
268 static char * 285 static char *
269 call(struct theme *t, json_t *json, const char *function) 286 call(const json_t *json, const char *function)
270 { 287 {
271 char *out = NULL, *dump = NULL; 288 char *out = NULL, *dump;
272 size_t outsz = 0; 289 size_t outsz = 0;
273 FILE *fp = NULL; 290 FILE *fp;
274 int nargs = 1; 291
275 292 duk_get_global_string(theme.ctx, function);
276 duk_get_global_string(t->ctx, function); 293
277 294 if (duk_is_callable(theme.ctx, -1)) {
278 if (!duk_is_callable(t->ctx, -1)) 295 fp = util_open_memstream(&out, &outsz);
279 goto over; 296 dump = util_json_dump(json);
280 if (!(fp = open_memstream(&out, &outsz))) 297
281 goto over; 298 duk_push_pointer(theme.ctx, fp);
282 299 duk_push_string(theme.ctx, dump);
283 duk_push_pointer(t->ctx, fp); 300 duk_json_decode(theme.ctx, -1);
284 301
285 if (json && (dump = json_dumps(json, JSON_COMPACT))) { 302 if (duk_pcall(theme.ctx, 2) != 0)
286 duk_push_string(t->ctx, dump); 303 log_warn("theme: %s", duk_safe_to_string(theme.ctx, -1));
287 duk_json_decode(t->ctx, -1); 304
288 nargs++; 305 duk_pop(theme.ctx);
289 }
290
291 if (duk_pcall(t->ctx, nargs) != 0)
292 log_warn("theme: %s", duk_safe_to_string(t->ctx, -1));
293
294 over:
295 duk_pop(t->ctx);
296
297 /*
298 * For convenience, otherwise all callers have to check for non-NULL
299 * after calling the function.
300 */
301 free(dump);
302
303 if (fp)
304 fclose(fp); 306 fclose(fp);
307 free(dump);
308 } else
309 duk_pop(theme.ctx);
310
305 if (!out) 311 if (!out)
306 out = util_strdup(""); 312 out = util_strdup("");
307 313
308 return out; 314 return out;
309 } 315 }
310 316
317 void
318 theme_open(const char *directory)
319 {
320 assert(directory);
321
322 const char *path;
323 char *data;
324
325 theme.ctx = duk_create_heap_default();
326 path = theme_path("theme.js");
327
328 if (!(data = util_read(path)))
329 log_warn("theme: %s: %s", path, strerror(errno));
330 else {
331 if (duk_peval_string(theme.ctx, data) != 0)
332 log_warn("theme: %s", duk_safe_to_string(theme.ctx, -1));
333
334 duk_pop(theme.ctx);
335 duk_push_object(theme.ctx);
336 duk_put_function_list(theme.ctx, -1, functions);
337 duk_put_global_string(theme.ctx, "Scid");
338 free(data);
339 }
340 }
341
311 const char * 342 const char *
312 theme_path(struct theme *t, const char *filename) 343 theme_path(const char *filename)
313 { 344 {
314 assert(filename); 345 assert(filename);
315 346
316 /* Build path to the template file. */ 347 /* Build path to the template file. */
317 static _Thread_local char path[PATH_MAX]; 348 static _Thread_local char path[PATH_MAX];
318 349
319 snprintf(path, sizeof (path), "%s/%s", t->base, filename); 350 snprintf(path, sizeof (path), "%s/%s", scid.themedir, filename);
320 351
321 return path; 352 return path;
322 } 353 }
323 354
324 struct theme *
325 theme_open(const char *directory)
326 {
327 assert(directory);
328
329 struct theme *t;
330 char themefile[PATH_MAX], *data;
331
332 t = util_calloc(1, sizeof (*t));
333 t->ctx = duk_create_heap_default();
334 util_strlcpy(t->base, directory, sizeof (t->base));
335
336 /* Open theme.js in the directory. */
337 snprintf(themefile, sizeof (themefile), "%s/theme.js", t->base);
338
339 if (!(data = util_read(themefile)))
340 log_warn("theme: %s: %s", themefile, strerror(errno));
341 else {
342 if (duk_peval_string(t->ctx, data) != 0)
343 log_warn("theme: %s", duk_safe_to_string(t->ctx, -1));
344
345 duk_pop(t->ctx);
346 duk_push_object(t->ctx);
347 duk_put_function_list(t->ctx, -1, functions);
348 duk_put_global_string(t->ctx, "Scid");
349 free(data);
350 }
351
352 return t;
353 }
354
355 char * 355 char *
356 theme_page_index(struct theme *t, json_t *json) 356 theme_page_index(const json_t *json)
357 { 357 {
358 assert(t); 358 assert(json);
359 359
360 return call(t, json, "onPageIndex"); 360 return call(json, "onPageIndex");
361 } 361 }
362 362
363 char * 363 char *
364 theme_page_status(struct theme *t, enum khttp status) 364 theme_page_status(enum khttp status)
365 { 365 {
366 assert(t); 366 json_t *doc;
367 367 char *ret;
368 (void)t; 368
369 (void)status; 369 doc = util_json_pack("{si}", "status", status);
370 370 ret = call(doc, "onPageStatus");
371 #if 0 371
372 return call(t, json, "onPageStatus"); 372 json_decref(doc);
373 #endif 373
374 return "ERROR"; 374 return ret;
375 } 375 }
376 376
377 void 377 void
378 theme_free(struct theme *t) 378 theme_free(void)
379 { 379 {
380 assert(t); 380 duk_destroy_heap(theme.ctx);
381 381 }
382 duk_destroy_heap(t->ctx);
383 }