#include "database.h" #include #include #include "sql.h" #include #include "config.h" sqlite3* db = nullptr; pthread_mutex_t db_mutex = PTHREAD_MUTEX_INITIALIZER; void init_db() { if (sqlite3_open(cm_get_parameter_as_string(config, "database"), &db) != SQLITE_OK) { fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); exit(1); } } void migrate_db() { char *err_msg = 0; pthread_mutex_lock(&db_mutex); if (sqlite3_exec(db, CREATE_TABLE_USERS, nullptr, nullptr, &err_msg) != SQLITE_OK) { fprintf(stderr, "SQL error: %s\n", err_msg); sqlite3_free(err_msg); sqlite3_close(db); exit(1); } pthread_mutex_unlock(&db_mutex); } // Вспомогательная функция для экранирования специальных символов в JSON char* json_escape(const char* str) { if (!str) return NULL; size_t len = strlen(str); // Выделяем память с запасом (каждый символ может быть экранирован) char* escaped = malloc(len * 6 + 1); if (!escaped) return NULL; char* p = escaped; for (size_t i = 0; i < len; i++) { switch (str[i]) { case '\"': strcpy(p, "\\\""); p += 2; break; case '\\': strcpy(p, "\\\\"); p += 2; break; case '\b': strcpy(p, "\\b"); p += 2; break; case '\f': strcpy(p, "\\f"); p += 2; break; case '\n': strcpy(p, "\\n"); p += 2; break; case '\r': strcpy(p, "\\r"); p += 2; break; case '\t': strcpy(p, "\\t"); p += 2; break; default: if (str[i] < 0x20) { sprintf(p, "\\u%04x", (unsigned char)str[i]); p += 6; } else { *p++ = str[i]; } } } *p = '\0'; return escaped; }