diff --git a/inc/ini/ini.h b/inc/ini/ini.h deleted file mode 100644 index 449d2dce0d01f9d0dc8c60f89ee2c6fece17d9ce..0000000000000000000000000000000000000000 --- a/inc/ini/ini.h +++ /dev/null @@ -1,139 +0,0 @@ -/* inih -- simple .INI file parser - SPDX-License-Identifier: BSD-3-Clause - Copyright (C) 2009-2020, Ben Hoyt */ - -#ifndef __INI_H__ -#define __INI_H__ - -/* Make this header file easier to include in C++ code */ -#ifdef __cplusplus -extern "C" { -#endif - -#include <stdio.h> - -/* Nonzero if ini_handler callback should accept lineno parameter. */ -#ifndef INI_HANDLER_LINENO -#define INI_HANDLER_LINENO 0 -#endif - -/* Typedef for prototype of handler function. */ -#if INI_HANDLER_LINENO -typedef int (*ini_handler)(void *user, const char *section, - const char *name, const char *value, - int lineno); -#else -typedef int (*ini_handler)(void *user, const char *section, - const char *name, const char *value); -#endif - -/* Typedef for prototype of fgets-style reader function. */ -typedef char *(*ini_reader)(char *str, int num, void *stream); - -/* Parse given INI-style file. May have [section]s, name=value pairs - (whitespace stripped), and comments starting with ';' (semicolon). Section - is "" if name=value pair parsed before any section heading. name:value - pairs are also supported as a concession to Python's configparser. - - For each name=value pair parsed, call handler function with given user - pointer as well as section, name, and value (data only valid for duration - of handler call). Handler should return nonzero on success, zero on error. - - Returns 0 on success, line number of first error on parse error (doesn't - stop on first error), -1 on file open error, or -2 on memory allocation - error (only when INI_USE_STACK is zero). -*/ -int ini_parse(const char *filename, ini_handler handler, void *user); - -/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't - close the file when it's finished -- the caller must do that. */ -int ini_parse_file(FILE *file, ini_handler handler, void *user); - -/* Same as ini_parse(), but takes an ini_reader function pointer instead of - filename. Used for implementing custom or string-based I/O (see also - ini_parse_string). */ -int ini_parse_stream(ini_reader reader, void *stream, ini_handler handler, - void *user); - -/* Same as ini_parse(), but takes a zero-terminated string with the INI data -instead of a file. Useful for parsing INI data from a network socket or -already in memory. */ -int ini_parse_string(const char *string, ini_handler handler, void *user); - -/* Nonzero to allow multi-line value parsing, in the style of Python's - configparser. If allowed, ini_parse() will call the handler with the same - name for each subsequent line parsed. */ -#ifndef INI_ALLOW_MULTILINE -#define INI_ALLOW_MULTILINE 1 -#endif - -/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of - the file. See https://github.com/benhoyt/inih/issues/21 */ -#ifndef INI_ALLOW_BOM -#define INI_ALLOW_BOM 1 -#endif - -/* Chars that begin a start-of-line comment. Per Python configparser, allow - both ; and # comments at the start of a line by default. */ -#ifndef INI_START_COMMENT_PREFIXES -#define INI_START_COMMENT_PREFIXES ";#" -#endif - -/* Nonzero to allow inline comments (with valid inline comment characters - specified by INI_INLINE_COMMENT_PREFIXES). Set to 0 to turn off and match - Python 3.2+ configparser behaviour. */ -#ifndef INI_ALLOW_INLINE_COMMENTS -#define INI_ALLOW_INLINE_COMMENTS 1 -#endif -#ifndef INI_INLINE_COMMENT_PREFIXES -#define INI_INLINE_COMMENT_PREFIXES ";" -#endif - -/* Nonzero to use stack for line buffer, zero to use heap (malloc/free). */ -#ifndef INI_USE_STACK -#define INI_USE_STACK 1 -#endif - -/* Maximum line length for any line in INI file (stack or heap). Note that - this must be 3 more than the longest line (due to '\r', '\n', and '\0'). */ -#ifndef INI_MAX_LINE -#define INI_MAX_LINE 200 -#endif - -/* Nonzero to allow heap line buffer to grow via realloc(), zero for a - fixed-size buffer of INI_MAX_LINE bytes. Only applies if INI_USE_STACK is - zero. */ -#ifndef INI_ALLOW_REALLOC -#define INI_ALLOW_REALLOC 0 -#endif - -/* Initial size in bytes for heap line buffer. Only applies if INI_USE_STACK - is zero. */ -#ifndef INI_INITIAL_ALLOC -#define INI_INITIAL_ALLOC 200 -#endif - -/* Stop parsing on first error (default is to keep parsing). */ -#ifndef INI_STOP_ON_FIRST_ERROR -#define INI_STOP_ON_FIRST_ERROR 0 -#endif - -/* Nonzero to call the handler at the start of each new section (with - name and value NULL). Default is to only call the handler on - each name=value pair. */ -#ifndef INI_CALL_HANDLER_ON_NEW_SECTION -#define INI_CALL_HANDLER_ON_NEW_SECTION 0 -#endif - -/* Nonzero to allow a name without a value (no '=' or ':' on the line) and - call the handler with value NULL in this case. Default is to treat - no-value lines as an error. */ -#ifndef INI_ALLOW_NO_VALUE -#define INI_ALLOW_NO_VALUE 0 -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* __INI_H__ */ diff --git a/inc/lektor/common.h b/inc/lektor/common.h index ebb7faabb2356896afd2c17fd0c5f8a8b32745e5..75f81aba4aac524c50a0ab89b42106c6e5b723d6 100644 --- a/inc/lektor/common.h +++ b/inc/lektor/common.h @@ -7,10 +7,13 @@ /* Defines */ -#define URL_MAX_LEN 1024 -#define DEFAULT_URL "https://kurisu.iiens.net" -#define GET_ID_JSON DEFAULT_URL "/api_karas.php?id=%ld" -#define GET_ID_FILE DEFAULT_URL "/download.php?id=%ld" +#define INI_MAX_LINE_LEN 512 +#define INI_MAX_SECTION_LEN 80 + +#define URL_MAX_LEN 1024 +#define DEFAULT_URL "https://kurisu.iiens.net" +#define GET_ID_JSON DEFAULT_URL "/api_karas.php?id=%ld" +#define GET_ID_FILE DEFAULT_URL "/download.php?id=%ld" #define SELF_EXECUTABLE_LINUX "/proc/self/exe" #define SELF_EXECUTABLE_FREEBSD "/proc/curproc/file" diff --git a/meson.build b/meson.build index 3a06d3244e75a7e7d510f9cf1145b1ffa5bae427..5d3d4429352a4851cf0c34246472a178eca591f0 100644 --- a/meson.build +++ b/meson.build @@ -58,7 +58,6 @@ core_sources = [ 'src/mkv/bufferfd.c' , 'src/net/downloader.c' , 'src/config.c' , 'src/uri.c' - , 'src/ini/ini.c' , 'src/thread.c' ] diff --git a/src/config.c b/src/config.c index cfc6e2b3eaef579628ad42f7a251ba7be3880aeb..e36fcf6bb336b9d205936c17e9795f4f516d2348 100644 --- a/src/config.c +++ b/src/config.c @@ -1,9 +1,9 @@ #define _POSIX_C_SOURCE 200809L #include <common/common.h> +#include <lektor/common.h> #include <lektor/config.h> #include <lektor/database.h> -#include <ini/ini.h> #include <stdlib.h> #include <errno.h> #include <string.h> @@ -14,6 +14,103 @@ #include <sys/types.h> #include <sys/stat.h> #include <limits.h> +#include <ctype.h> + +typedef int (*ini_handler)(volatile sqlite3 *db, const char *section, const char *name, const char *value); + +static inline char * +strip(char *s) +{ + char *p = s + strlen(s); + while (p > s && isspace(*(--p))) + *p = 0; + return s; +} + +static inline char * +skip(char *s) +{ + while (*s && isspace(*s)) + s++; + return s; +} + +static inline int +ini_parse(const char *path, ini_handler handle, volatile sqlite3 *db) +{ + char *start, *end, *name, *value; + char section[INI_MAX_SECTION_LEN], line[INI_MAX_LINE_LEN]; + int error = 0, linenum = 0, len; + FILE *file = fopen(path, "r"); + if (!file) { + LOG_ERROR_SCT("PARSER", "Failed to open config file '%s'", path); + return 1; + } + + /* Parse the file */ + while (NULL != fgets(line, INI_MAX_LINE_LEN, file)) { + ++linenum; + start = skip(strip(line)); + + /* Skip comments */ + if (strspn(start, ";#")) + continue; + + /* Handle sections */ + else if (start[0] == '[') { + end = &start[1 + strcspn(start + 1, "]")]; + if (end[0] == ']') { + end[0] = '\0'; + len = strlen(&start[1]); + len = MIN(len + 1, INI_MAX_SECTION_LEN); + memcpy(section, &start[1], len); + section[INI_MAX_SECTION_LEN - 1] = '\0'; + } + + else { + error = 1; + LOG_ERROR_SCT("PARSER", "Invalid section name at line '%d'", linenum); + } + } + + /* Handle name[:=]name pair */ + else if (start[0]) { + end = &start[1 + strcspn(start + 1, ":=")]; + if (end[0] == '=' || end[0] == ':') { + end[0] = '\0'; + name = strip(start); + value = &end[1]; + + /* Find a comment */ + end = &value[strcspn(value, ":=")]; + if (end[0]) + end[0] = '\0'; + + /* Skip all spaces */ + value = skip(value); + strip(value); + + /* Handle the SECTION, NAME[:=]VALUE */ + if (handle(db, section, name, value)) { + error = 1; + LOG_ERROR_SCT("PARSER", "Failed to '[handle] %s, %s{:,=}%s' at line '%d'", + section, name, value, linenum); + } + } + + else { + error = 1; + LOG_ERROR_SCT("PARSER", "Invalid name[:=]value pair at line '%d'", linenum); + } + } + } + + /* End of the function */ + fclose(file); + if (error) + LOG_ERROR_SCT("PARSER", "An error occured while parsing the file '%s'", path); + return error; +} int load_so(const char *const mod_path, const char *const mod_init, void *mod) @@ -46,10 +143,10 @@ load_so(const char *const mod_path, const char *const mod_init, void *mod) inline int load_module_by_name(volatile sqlite3 *db, const char *name, void *mod) { - char mod_path[PATH_MAX], mod_load[INI_MAX_LINE]; + char mod_path[PATH_MAX], mod_load[INI_MAX_LINE_LEN]; if (!database_config_get_text(db, name, "path", mod_path, PATH_MAX) || - !database_config_get_text(db, name, "load_function", mod_load, INI_MAX_LINE)) { + !database_config_get_text(db, name, "load_function", mod_load, INI_MAX_LINE_LEN)) { LOG_ERROR("Module named %s is incomplete or is not defined in config file", name); return 1; } @@ -67,7 +164,6 @@ validate_conf(volatile sqlite3 *db) } CHK_OPTION("externals", "mkvpropedit"); - CHK_OPTION("externals", "sqlite3"); CHK_OPTION("server", "host"); CHK_OPTION("server", "port"); @@ -87,17 +183,11 @@ validate_conf(volatile sqlite3 *db) } static int -#if INI_HANDLER_LINENO -handler(void *user, const char *section, const char *name, const char *value, int lineno) +handler(volatile sqlite3 *user, const char *section, const char *name, const char *value) { - UNUSED(lineno); -#else -handler(void *user, const char *section, const char *name, const char *value) -{ -#endif RETURN_UNLESS(section && name && value, "I can't complete the database with incomplete lines", 1); - RETURN_UNLESS(database_config_set(user, section, name, value), "Failed to update the database", 0); - return 1; + RETURN_UNLESS(database_config_set(user, section, name, value), "Failed to update the database", 1); + return 0; } int @@ -166,7 +256,7 @@ found: int config_new(volatile sqlite3 *db, const char *conf) { - if (ini_parse(conf, handler, (void *) db)) { + if (ini_parse(conf, handler, db)) { LOG_ERROR("Failed to parse file %s", conf); return 1; } diff --git a/src/ini/ini.c b/src/ini/ini.c deleted file mode 100644 index 25e3870318e7efb1201ff8e3831067e1777f7e1e..0000000000000000000000000000000000000000 --- a/src/ini/ini.c +++ /dev/null @@ -1,280 +0,0 @@ -/* inih -- simple .INI file parser - SPDX-License-Identifier: BSD-3-Clause - Copyright (C) 2009-2020, Ben Hoyt */ - -#include <stdio.h> -#include <ctype.h> -#include <string.h> - -#include <ini/ini.h> - -#if !INI_USE_STACK -#include <stdlib.h> -#endif - -#define MAX_SECTION 50 -#define MAX_NAME 50 - -/* Used by ini_parse_string() to keep track of string parsing state. */ -typedef struct { - const char *ptr; - size_t num_left; -} ini_parse_string_ctx; - -/* Strip whitespace chars off end of given string, in place. Return s. */ -static char * -rstrip(char *s) -{ - char *p = s + strlen(s); - while (p > s && isspace((unsigned char)(*--p))) - *p = '\0'; - return s; -} - -/* Return pointer to first non-whitespace char in given string. */ -static char * -lskip(const char *s) -{ - while (*s && isspace((unsigned char)(*s))) - s++; - return (char *)s; -} - -/* Return pointer to first char (of chars) or inline comment in given string, - or pointer to null at end of string if neither found. Inline comment must - be prefixed by a whitespace character to register as a comment. */ -static char * -find_chars_or_comment(const char *s, const char *chars) -{ -#if INI_ALLOW_INLINE_COMMENTS - int was_space = 0; - while (*s && (!chars || !strchr(chars, *s)) && - !(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) { - was_space = isspace((unsigned char)(*s)); - s++; - } -#else - while (*s && (!chars || !strchr(chars, *s))) - s++; -#endif - return (char *)s; -} - -/* Version of strncpy that ensures dest (size bytes) is null-terminated. */ -static char * -strncpy0(char *dest, const char *src, size_t size) -{ - strncpy(dest, src, size - 1); - dest[size - 1] = '\0'; - return dest; -} - -/* See documentation in header file. */ -int -ini_parse_stream(ini_reader reader, void *stream, ini_handler handler, - void *user) -{ - /* Uses a fair bit of stack (use heap instead if you need to) */ -#if INI_USE_STACK - char line[INI_MAX_LINE]; - int max_line = INI_MAX_LINE; -#else - char *line; - size_t max_line = INI_INITIAL_ALLOC; -#endif -#if INI_ALLOW_REALLOC && !INI_USE_STACK - char *new_line; - size_t offset; -#endif - char section[MAX_SECTION] = ""; - char prev_name[MAX_NAME] = ""; - - char *start; - char *end; - char *name; - char *value; - int lineno = 0; - int error = 0; - -#if !INI_USE_STACK - line = (char *)malloc(INI_INITIAL_ALLOC); - if (!line) - return -2; -#endif - -#if INI_HANDLER_LINENO -#define HANDLER(u, s, n, v) handler(u, s, n, v, lineno) -#else -#define HANDLER(u, s, n, v) handler(u, s, n, v) -#endif - - /* Scan through stream line by line */ - while (reader(line, (int)max_line, stream) != NULL) { -#if INI_ALLOW_REALLOC && !INI_USE_STACK - offset = strlen(line); - while (offset == max_line - 1 && line[offset - 1] != '\n') { - max_line *= 2; - if (max_line > INI_MAX_LINE) - max_line = INI_MAX_LINE; - new_line = realloc(line, max_line); - if (!new_line) { - free(line); - return -2; - } - line = new_line; - if (reader(line + offset, (int)(max_line - offset), stream) == NULL) - break; - if (max_line >= INI_MAX_LINE) - break; - offset += strlen(line + offset); - } -#endif - - lineno++; - - start = line; -#if INI_ALLOW_BOM - if (lineno == 1 && (unsigned char)start[0] == 0xEF && - (unsigned char)start[1] == 0xBB && - (unsigned char)start[2] == 0xBF) - start += 3; -#endif - start = lskip(rstrip(start)); - - if (strchr(INI_START_COMMENT_PREFIXES, *start)) { - /* Start-of-line comment */ - } -#if INI_ALLOW_MULTILINE - else if (*prev_name && *start && start > line) { - /* Non-blank line with leading whitespace, treat as continuation - of previous name's value (as per Python configparser). */ - if (!HANDLER(user, section, prev_name, start) && !error) - error = lineno; - } -#endif - else if (*start == '[') { - /* A "[section]" line */ - end = find_chars_or_comment(start + 1, "]"); - if (*end == ']') { - *end = '\0'; - strncpy0(section, start + 1, sizeof(section)); - *prev_name = '\0'; -#if INI_CALL_HANDLER_ON_NEW_SECTION - if (!HANDLER(user, section, NULL, NULL) && !error) - error = lineno; -#endif - } else if (!error) { - /* No ']' found on section line */ - error = lineno; - } - } else if (*start) { - /* Not a comment, must be a name[=:]value pair */ - end = find_chars_or_comment(start, "=:"); - if (*end == '=' || *end == ':') { - *end = '\0'; - name = rstrip(start); - value = end + 1; -#if INI_ALLOW_INLINE_COMMENTS - end = find_chars_or_comment(value, NULL); - if (*end) - *end = '\0'; -#endif - value = lskip(value); - rstrip(value); - - /* Valid name[=:]value pair found, call handler */ - strncpy0(prev_name, name, sizeof(prev_name)); - if (!HANDLER(user, section, name, value) && !error) - error = lineno; - } else if (!error) { - /* No '=' or ':' found on name[=:]value line */ -#if INI_ALLOW_NO_VALUE - *end = '\0'; - name = rstrip(start); - if (!HANDLER(user, section, name, NULL) && !error) - error = lineno; -#else - error = lineno; -#endif - } - } - -#if INI_STOP_ON_FIRST_ERROR - if (error) - break; -#endif - } - -#if !INI_USE_STACK - free(line); -#endif - - return error; -} - -/* See documentation in header file. */ -int -ini_parse_file(FILE *file, ini_handler handler, void *user) -{ - return ini_parse_stream((ini_reader)fgets, file, handler, user); -} - -/* See documentation in header file. */ -int -ini_parse(const char *filename, ini_handler handler, void *user) -{ - FILE *file; - int error; - - file = fopen(filename, "r"); - if (!file) { - fprintf(stderr, " ! ini_parse: Failed to open file %s\n", filename); - return -1; - } - error = ini_parse_file(file, handler, user); - fclose(file); - if (error) - fprintf(stderr, " ! ini_parse: Got an error, code is %d\n", error); - return error; -} - -/* An ini_reader function to read the next line from a string buffer. This - is the fgets() equivalent used by ini_parse_string(). */ -static char * -ini_reader_string(char *str, int num, void *stream) -{ - ini_parse_string_ctx *ctx = (ini_parse_string_ctx *)stream; - const char *ctx_ptr = ctx->ptr; - size_t ctx_num_left = ctx->num_left; - char *strp = str; - char c; - - if (ctx_num_left == 0 || num < 2) - return NULL; - - while (num > 1 && ctx_num_left != 0) { - c = *ctx_ptr++; - ctx_num_left--; - *strp++ = c; - if (c == '\n') - break; - num--; - } - - *strp = '\0'; - ctx->ptr = ctx_ptr; - ctx->num_left = ctx_num_left; - return str; -} - -/* See documentation in header file. */ -int -ini_parse_string(const char *string, ini_handler handler, void *user) -{ - ini_parse_string_ctx ctx; - - ctx.ptr = string; - ctx.num_left = strlen(string); - return ini_parse_stream((ini_reader)ini_reader_string, &ctx, handler, - user); -} diff --git a/src/net/listen.c b/src/net/listen.c index 30f5e5789f7a32e17ff3dbde969b269ae9560e6f..e72110309974648bd43f5bd519264172ee5d5bfa 100644 --- a/src/net/listen.c +++ b/src/net/listen.c @@ -4,7 +4,6 @@ #include <lektor/common.h> #include <lektor/database.h> #include <lektor/net.h> -#include <ini/ini.h> #include <sqlite3.h> @@ -697,7 +696,7 @@ lkt_listen(void) char *const kara_dir = memory + PATH_MAX + 1; /* Size is PATH_MAX. */ char *const host = kara_dir + PATH_MAX + 1; /* Size is HOST_NAME_MAX. */ char port[7]; /* Maximal port number is 65535, +2 for '\n' and '\0' */ - char player_mod[INI_MAX_LINE]; + char player_mod[INI_MAX_LINE_LEN]; char conf_file[PATH_MAX]; memset(&srv, 0, sizeof(struct lkt_state)); @@ -711,11 +710,11 @@ lkt_listen(void) RETURN_UNLESS(database_open(srv.db, db_path), "Can't open database", 1); /* Read the configuration. */ - RETURN_UNLESS(database_config_get_int (srv.db, "player", "autoclear", &autoclear), "Cfg error", 2); - RETURN_UNLESS(database_config_get_text(srv.db, "database", "kara_dir", kara_dir, PATH_MAX), "Cfg error", 2); - RETURN_UNLESS(database_config_get_text(srv.db, "server", "host", host, HOST_NAME_MAX), "Cfg error", 2); - RETURN_UNLESS(database_config_get_text(srv.db, "server", "port", port, 5), "Cfg error", 2); - RETURN_UNLESS(database_config_get_text(srv.db, "player", "module", player_mod, INI_MAX_LINE), "Cfg error", 2); + RETURN_UNLESS(database_config_get_int (srv.db, "player", "autoclear", &autoclear), "Cfg error", 2); + RETURN_UNLESS(database_config_get_text(srv.db, "database", "kara_dir", kara_dir, PATH_MAX), "Cfg error", 2); + RETURN_UNLESS(database_config_get_text(srv.db, "server", "host", host, HOST_NAME_MAX), "Cfg error", 2); + RETURN_UNLESS(database_config_get_text(srv.db, "server", "port", port, 5), "Cfg error", 2); + RETURN_UNLESS(database_config_get_text(srv.db, "player", "module", player_mod, INI_MAX_LINE_LEN), "Cfg error", 2); if (kara_dir[strlen(kara_dir) - 1] != '/') strncat(kara_dir, "/", PATH_MAX - 1);