#include "Utility.h" #include "../Scraping/Scraping.h" #include #include #include #include #include static char global_default_locale[32] = "en_gb"; static char **themes_list = NULL; static int themes_count = 0; static int themes_initialized = 0; void init_themes(const char *static_path) { if (themes_initialized) return; char themes_dir[512]; snprintf(themes_dir, sizeof(themes_dir), "%s/themes", static_path); DIR *dir = opendir(themes_dir); if (!dir) return; struct dirent *entry; int capacity = 4; themes_list = malloc(sizeof(char *) * capacity); if (!themes_list) { closedir(dir); return; } themes_count = 0; while ((entry = readdir(dir)) != NULL) { size_t len = strlen(entry->d_name); if (len > 4 && strcmp(entry->d_name + len - 4, ".css") == 0) { if (themes_count >= capacity) { int new_capacity = capacity * 2; char **new_list = realloc(themes_list, sizeof(char *) * new_capacity); if (!new_list) break; themes_list = new_list; capacity = new_capacity; } char *theme = strndup(entry->d_name, len - 4); if (!theme) break; themes_list[themes_count] = theme; themes_count++; } } closedir(dir); themes_initialized = 1; for (int i = 0; i < themes_count; i++) { for (int j = i + 1; j < themes_count; j++) { int priority_i = 0, priority_j = 0; if (strcmp(themes_list[i], "system") == 0) priority_i = 0; else if (strcmp(themes_list[i], "light") == 0) priority_i = 1; else if (strcmp(themes_list[i], "dark") == 0) priority_i = 2; else priority_i = 3; if (strcmp(themes_list[j], "system") == 0) priority_j = 0; else if (strcmp(themes_list[j], "light") == 0) priority_j = 1; else if (strcmp(themes_list[j], "dark") == 0) priority_j = 2; else priority_j = 3; if (priority_i > priority_j || (priority_i == priority_j && strcmp(themes_list[i], themes_list[j]) > 0)) { char *tmp = themes_list[i]; themes_list[i] = themes_list[j]; themes_list[j] = tmp; } } } } void get_available_themes(char ***out_themes, int *out_count) { *out_themes = themes_list; *out_count = themes_count; } void set_default_locale(const char *locale) { if (locale && strlen(locale) > 0) { strncpy(global_default_locale, locale, sizeof(global_default_locale) - 1); global_default_locale[sizeof(global_default_locale) - 1] = '\0'; } } int hex_to_int(char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; if (c >= 'A' && c <= 'F') return c - 'A' + 10; return -1; } char *get_theme(const char *default_theme) { char *cookie = get_cookie("theme"); if (cookie && strlen(cookie) > 0) { for (int i = 0; i < themes_count; i++) { if (strcmp(cookie, themes_list[i]) == 0) { return cookie; } } } free(cookie); return strdup(default_theme && strlen(default_theme) > 0 ? default_theme : "system"); } char *get_locale(const char *default_locale) { char *cookie = get_cookie("locale"); if (cookie && beaker_get_locale_meta(cookie) != NULL) { return cookie; } free(cookie); const char *fallback = default_locale ? default_locale : global_default_locale; return strdup(fallback); } static int engine_id_casecmp(const char *a, const char *b) { while (*a && *b) { char la = *a; char lb = *b; if (la >= 'A' && la <= 'Z') la = la - 'A' + 'a'; if (lb >= 'A' && lb <= 'Z') lb = lb - 'A' + 'a'; if (la != lb) return 0; a++; b++; } return *a == *b; } int is_engine_id_enabled(const char *engine_id) { if (!engine_id) return 0; for (int i = 0; i < ENGINE_COUNT; i++) { if (ENGINE_REGISTRY[i].enabled && engine_id_casecmp(ENGINE_REGISTRY[i].id, engine_id)) { return 1; } } return 0; } int get_user_engines(char ***out_ids, int *out_count) { *out_ids = NULL; *out_count = 0; char *cookie = get_cookie("engines"); if (!cookie || cookie[0] == '\0') { free(cookie); return -1; } char **ids = NULL; int count = 0; char *copy = strdup(cookie); if (!copy) { free(cookie); return -1; } char *saveptr; char *token = strtok_r(copy, ",", &saveptr); while (token) { while (*token == ' ' || *token == '\t') token++; if (token[0] != '\0' && is_engine_id_enabled(token)) { char **new_ids = realloc(ids, sizeof(char *) * (count + 1)); if (new_ids) { ids = new_ids; ids[count] = strdup(token); count++; } } token = strtok_r(NULL, ",", &saveptr); } free(copy); free(cookie); if (count == 0) { free(ids); return -1; } *out_ids = ids; *out_count = count; return 0; } int user_engines_contains(const char *engine_id, char **ids, int count) { if (!engine_id || !ids) return 0; for (int i = 0; i < count; i++) { if (engine_id_casecmp(ids[i], engine_id)) return 1; } return 0; } char *get_default_search_engine(void) { char *cookie = get_cookie("default_engine"); if (cookie && (strcmp(cookie, "all") == 0 || is_engine_id_enabled(cookie))) return cookie; free(cookie); return strdup("all"); } void free_string_matrix(char ***matrix, int *inner_counts, int row_count) { if (matrix) { for (int i = 0; i < row_count; i++) { int field_count = inner_counts ? inner_counts[i] : 0; for (int j = 0; j < field_count; j++) free(matrix[i][j]); free(matrix[i]); } } free(matrix); free(inner_counts); } void string_matrix_init(StringMatrix *matrix) { if (matrix) *matrix = (StringMatrix){0}; } int string_matrix_append(StringMatrix *matrix, const char *const *values, int field_count) { if (!matrix || !values || field_count <= 0) return -1; char **row = calloc((size_t)field_count, sizeof(*row)); if (!row) return -1; for (int i = 0; i < field_count; i++) { row[i] = strdup(values[i] ? values[i] : ""); if (!row[i]) { for (int j = 0; j < i; j++) free(row[j]); free(row); return -1; } } if (matrix->count == matrix->capacity) { int new_capacity = matrix->capacity ? matrix->capacity * 2 : 8; char ***new_rows = malloc(sizeof(*new_rows) * (size_t)new_capacity); int *new_counts = malloc(sizeof(*new_counts) * (size_t)new_capacity); if (!new_rows || !new_counts) { free(new_rows); free(new_counts); for (int i = 0; i < field_count; i++) free(row[i]); free(row); return -1; } if (matrix->count > 0) { memcpy(new_rows, matrix->rows, sizeof(*new_rows) * matrix->count); memcpy(new_counts, matrix->field_counts, sizeof(*new_counts) * matrix->count); } free(matrix->rows); free(matrix->field_counts); matrix->rows = new_rows; matrix->field_counts = new_counts; matrix->capacity = new_capacity; } matrix->rows[matrix->count] = row; matrix->field_counts[matrix->count] = field_count; matrix->count++; return 0; } void string_matrix_free(StringMatrix *matrix) { if (!matrix) return; free_string_matrix(matrix->rows, matrix->field_counts, matrix->count); *matrix = (StringMatrix){0}; } int string_matrix_build_pagination(int page, char *(*href_builder)(int page, void *data), void *data, StringMatrix *out_matrix) { enum { PAGER_WINDOW_SIZE = 5 }; if (!out_matrix || !href_builder) return -1; string_matrix_init(out_matrix); int pager_start = page <= 3 ? 1 : page - 2; int pager_end = pager_start + PAGER_WINDOW_SIZE - 1; for (int i = page > 1 ? pager_start - 1 : pager_start; i <= pager_end + 1; i++) { const char *label = NULL; const char *class_name = "pagination-btn"; char page_label[16]; int target_page = i; if (page > 1 && i == pager_start - 1) { label = "←"; class_name = "pagination-btn prev"; target_page = page - 1; } else if (i == pager_end + 1) { label = "→"; class_name = "pagination-btn next"; target_page = page + 1; } else { snprintf(page_label, sizeof(page_label), "%d", i); label = page_label; if (i == page) class_name = "pagination-btn pagination-current"; } char *href = href_builder(target_page, data); const char *values[LINK_FIELD_COUNT] = {href, label, class_name}; int result = string_matrix_append(out_matrix, values, LINK_FIELD_COUNT); free(href); if (result != 0) { string_matrix_free(out_matrix); return -1; } } return 0; }