diff --git a/inc/lektor/common.h b/inc/lektor/common.h index 6699edeffb2658f0948d96c562b063981efaec15..c65f732a5fc441a5d90858350852c337ef4af2ad 100644 --- a/inc/lektor/common.h +++ b/inc/lektor/common.h @@ -180,5 +180,10 @@ long long_length(long integer); void *safe_malloc(size_t size); void *safe_zero_malloc(size_t size); int safe_snprintf(char *dest, const size_t max_len, const char *format, ...); +char *safe_strncpy(char *dest, const char *src, size_t n); + +/* Iterate throught a string, copy each element in the dest string. + The save ptr must contains a null integer. */ +int iter_string(const char *str, const char *sep, char *dest, const size_t dest_len, size_t *save); #endif /* __LKT_COMMON_H__ */ diff --git a/inc/lektor/config.def b/inc/lektor/config.def index 8c442b0174fc5749145561b10e4186218a738fca..e32c0f78000a0ce91c3712dfad0448c69758b937 100644 --- a/inc/lektor/config.def +++ b/inc/lektor/config.def @@ -13,6 +13,8 @@ value("kara_dir", "/home/kara") /* All the folder and sub folder must be on the same partition */ value("db_path", "/home/kara/kara.db") +/* The repo module, here to be able to sync the bakabase with kurisu or + any other server, if configured correctly */ section("repo") value("obfuscate", "1") value("module", "repo") @@ -23,6 +25,9 @@ value("json", "https://kurisu.iiens.net/api") value("id_json", "https://kurisu.iiens.net/api?id=%ld") value("id_kara", "https://kurisu.iiens.net/download.php?id=%ld") +/* The player module, so that people can 'sing' when using lektor. By + default it's sdl, but one can create any module, for audio support + only for example. */ section("player") value("module", "sdl2") value("autoclear", "true") @@ -33,3 +38,16 @@ value("def_repeat", "false") value("font_size", "20") value("font_name", "Hack Nerd Font") value("msg_duration", "4") + +/* To place hooks, when some things are done in lektor. The default value 'none' is here so that + nothing happens. Like any module, the value can point to a module or a function in the internal + register. To specify multiple modules, use a comma separated list, line this: + `kara_load = print_stdout, print_stderr` + For the moment, only functions in the server register are supported. + NOTE: All the functions will recieve a va_list as a unique argument. */ +section("hook") +value("kara_load", "none") /* Before a kara is loaded to be played, + the 'player' module needs to support it */ +value("queue_begin", "none") /* On play, when the player is not already playing or paused */ + +// vi:syntax=c diff --git a/inc/lektor/config.h b/inc/lektor/config.h index 4515f0e352df48e9bc35978cedd42993206534ce..5db459f178c1983f23810a844a5423535f1f81a3 100644 --- a/inc/lektor/config.h +++ b/inc/lektor/config.h @@ -9,6 +9,7 @@ /* Forward definition of the lkt_state structure */ struct lkt_state; +/* The default configuration, stored as a string */ #define section(sct) "\n[" sct "]\n" #define value(key, val) key " = " val "\n" #define value_opt(key, val) value(key, val) @@ -44,4 +45,8 @@ void config_default_file(char *dest, size_t len); #define env_set(var, val) setenv(var, val, 1) #define env_get getenv +/* Handle everything for a hook */ +void config_handle_hook(volatile sqlite3 *db, const char *hook_name, int arg_count, ...); +#define HANDLE_HOOK(db, n, ...) config_handle_hook(db, n, GET_VA_COUNT(__VA_ARGS__), __VA_ARGS__) + #endif /* __LKT_CONFIG_H__ */ diff --git a/inc/lektor/database.h b/inc/lektor/database.h index 1c709d90f14bad6ccd2c65add613ebd80a1b0a06..dc7f91c396eab8d9d23d7342999731c26f162540 100644 --- a/inc/lektor/database.h +++ b/inc/lektor/database.h @@ -144,8 +144,9 @@ bool database_validate_conf (volatile sqlite3 *db); bool database_config_set (volatile sqlite3 *db, const char *section, const char *key, const char *value); bool database_config_get_text(volatile sqlite3 *db, const char *section, const char *key, - char *value, - size_t len); + char *value, size_t len); +bool database_config_get_text_nospace(volatile sqlite3 *db, const char *section, + const char *key, char *value, size_t len); bool database_config_get_int (volatile sqlite3 *db, const char *section, const char *key, int *value); bool database_config_exists (volatile sqlite3 *db, const char *section, const char *key); diff --git a/inc/lektor/reg.h b/inc/lektor/reg.h index 9439439d1f63e3ad939160a70a5e6f60c8a0ee16..f1b4ec8ea92842ba4f3673a6235720c6974a59a1 100644 --- a/inc/lektor/reg.h +++ b/inc/lektor/reg.h @@ -46,6 +46,9 @@ struct lkt_module { REG_DECLARE(reg) \ static struct module_reg *as = reg; +/* The server register */ +#define REG_SERVER __reg__ + /* Call a function from a reg. * NOTE: * - Use the MOD_CALL macro to call a function that takes arguments @@ -66,5 +69,6 @@ int reg_import(const char *mod, struct module_reg **ret, void **handle); /* Set the __reg__ pointer. */ void reg_export(struct module_reg *reg); +void reg_global(struct module_reg **reg_ptr); #endif /* __LKT_REG_H__ */ diff --git a/src/base/common.c b/src/base/common.c index 7d76ad345b8bcaff011d6388eb564475c1bf98ef..093e5ff3fe816a7b1bba9e9a04a02031d2fec86a 100644 --- a/src/base/common.c +++ b/src/base/common.c @@ -274,3 +274,27 @@ long_length(long integer) } return count; } + +char * +safe_strncpy(char *dest, const char *src, size_t n) +{ + char *ret = strncpy(dest, src, n); + dest[n - 1] = '\0'; + return ret; +} + +int +iter_string(const char *str_list, const char *sep, char *dest, const size_t dest_len, size_t *save) +{ + size_t len = strcspn(&str_list[*save], sep); + + if (len == 0) + return 1; + if (len >= dest_len) + return -1; + + strncpy(dest, &str_list[*save], len); + dest[len] = '\0'; + *save += len + 1; + return 0; +} diff --git a/src/base/config.c b/src/base/config.c index 4d5d7d50564dfdbe22a04befaa19cef117c30d8f..5326bf9c479d827619a7ef7c12975049dc136af5 100644 --- a/src/base/config.c +++ b/src/base/config.c @@ -296,3 +296,33 @@ config_open(volatile sqlite3 *db) error: return ret; } + +void +config_handle_hook(volatile sqlite3 *db, const char *hook_name, int arg_count, ...) +{ + char hook_handlers[LKT_LINE_MAX]; + if (!database_config_get_text_nospace(db, "hook", hook_name, hook_handlers, LKT_LINE_MAX)) { + LOG_ERROR("HOOK", "Failed to get the hook handlers list for hook '%s'", hook_name); + return; + } + + va_list va; + va_start(va, arg_count); + + size_t save = 0; + char name[LKT_LINE_MAX]; + int code; + struct module_reg *server_reg; + reg_global(&server_reg); + + while (0 == (code = iter_string(hook_handlers, ",", name, LKT_LINE_MAX, &save))) { + if (STR_MATCH("none", name)) + continue; + reg_call(server_reg, name, 1, va); + } + + if (code == -1) + LOG_ERROR("HOOK", "Failed to parse the handle list for hook '%s'", hook_name); + + va_end(va); +} diff --git a/src/base/reg.c b/src/base/reg.c index 5a92130142a629d67b315b9cb96468e633cc9ea7..ec42e88851878a5971851aabf93d4c279c353742 100644 --- a/src/base/reg.c +++ b/src/base/reg.c @@ -20,6 +20,12 @@ reg_export(struct module_reg *reg) __reg__ = reg; } +void +reg_global(struct module_reg **reg_ptr) +{ + *reg_ptr = __reg__; +} + void * __reg_get(struct module_reg *reg, const char *name) { diff --git a/src/database/config.c b/src/database/config.c index ec8c5b139abcb0279ef7a3a4c3022f6b8e2d8af1..86fd2d605dc58eaec6adfd56db04057c101b9c0c 100644 --- a/src/database/config.c +++ b/src/database/config.c @@ -67,6 +67,32 @@ error: return ret; } +bool +database_config_get_text_nospace(volatile sqlite3 *db, const char *section, const char *key, + char *value, size_t len) +{ + static const char *SQL_STMT = + "SELECT REPLACE(value, ' ', '')" + " FROM config" + " WHERE section = ? AND key = ?;\n"; + sqlite3_stmt *stmt = 0; + bool ret = false; + char *row; + + SQLITE_PREPARE(db, stmt, SQL_STMT, error); + SQLITE_BIND_TEXT(db, stmt, 1, section, error); + SQLITE_BIND_TEXT(db, stmt, 2, key, error); + SQLITE_STEP_ROW(db, stmt, error); + + row = (char *) sqlite3_column_text(stmt, 0); + strncpy(value, row, len); + value[len - 1] = 0; + ret = true; +error: + sqlite3_finalize(stmt); + return ret; +} + bool database_config_exists(volatile sqlite3 *db, const char *section, const char *key)