From d93fead0aeaed1b7860fe132476c81c1845ce756 Mon Sep 17 00:00:00 2001 From: frosty Date: Sat, 8 Aug 2026 12:56:26 -0400 Subject: refactor: centralise matrix ownership and request cleanup --- src/Routes/Images.c | 77 ++++++++++++++++++++++++++--------------------------- 1 file changed, 38 insertions(+), 39 deletions(-) (limited to 'src/Routes/Images.c') diff --git a/src/Routes/Images.c b/src/Routes/Images.c index 40ab88f..d89b732 100644 --- a/src/Routes/Images.c +++ b/src/Routes/Images.c @@ -41,6 +41,10 @@ static char *images_href_builder(int page, void *data) { return build_images_href((const char *)data, page); } +static void free_pagination(char ***matrix, int *inner_counts, int count) { + free_string_matrix(matrix, inner_counts, count); +} + int images_handler(UrlParams *params) { extern Config global_config; TemplateContext ctx = new_context(); @@ -91,8 +95,9 @@ int images_handler(UrlParams *params) { if (!raw_query || strlen(raw_query) == 0) { send_redirect("/"); - if (display_query) - free(display_query); + free_pagination(pager_matrix, pager_inner_counts, pager_count); + free(display_query); + free(locale); free_context(&ctx); return -1; } @@ -128,7 +133,9 @@ int images_handler(UrlParams *params) { snprintf(response, sizeof(response), "

%s

", rate_limit_msg); send_response(response); free(request_cache_key); + free_pagination(pager_matrix, pager_inner_counts, pager_count); free(display_query); + free(locale); free_context(&ctx); return -1; } @@ -147,36 +154,41 @@ int images_handler(UrlParams *params) { snprintf(error_html, sizeof(error_html), "

%s

", error_images_msg); send_response(error_html); free(request_cache_key); + free_pagination(pager_matrix, pager_inner_counts, pager_count); free(display_query); + free(locale); free_context(&ctx); return -1; } - char ***image_matrix = malloc(sizeof(char **) * result_count); - int *inner_counts = malloc(sizeof(int) * result_count); - - if (!image_matrix || !inner_counts) { - if (image_matrix) - free(image_matrix); - if (inner_counts) - free(inner_counts); - free_image_results(results, result_count); - free(request_cache_key); - free(display_query); - free_context(&ctx); - return -1; - } + char ***image_matrix = NULL; + int *inner_counts = NULL; + int image_count = 0; for (int i = 0; i < result_count; i++) { - image_matrix[i] = malloc(sizeof(char *) * IMAGE_RESULT_FIELDS); - image_matrix[i][0] = strdup(results[i].thumbnail_url); - image_matrix[i][1] = strdup(results[i].title); - image_matrix[i][2] = strdup(results[i].page_url); - image_matrix[i][3] = strdup(results[i].full_url); - inner_counts[i] = IMAGE_RESULT_FIELDS; + const char *values[IMAGE_RESULT_FIELDS] = { + results[i].thumbnail_url, + results[i].title, + results[i].page_url, + results[i].full_url, + }; + int new_count = append_string_row(&image_matrix, &inner_counts, + image_count, values, + IMAGE_RESULT_FIELDS); + if (new_count == image_count) { + free_string_matrix(image_matrix, inner_counts, image_count); + free_pagination(pager_matrix, pager_inner_counts, pager_count); + free_image_results(results, result_count); + free(request_cache_key); + free(display_query); + free(locale); + free_context(&ctx); + return -1; + } + image_count = new_count; } - context_set_array_of_arrays(&ctx, "images", image_matrix, result_count, + context_set_array_of_arrays(&ctx, "images", image_matrix, image_count, inner_counts); char *rendered = render_template("images.html", &ctx); @@ -187,27 +199,14 @@ int images_handler(UrlParams *params) { send_response("

Error rendering image results

"); } - for (int i = 0; i < result_count; i++) { - for (int j = 0; j < IMAGE_RESULT_FIELDS; j++) - free(image_matrix[i][j]); - free(image_matrix[i]); - } - free(image_matrix); - free(inner_counts); + free_string_matrix(image_matrix, inner_counts, image_count); - if (pager_count > 0) { - for (int i = 0; i < pager_count; i++) { - for (int j = 0; j < LINK_FIELD_COUNT; j++) - free(pager_matrix[i][j]); - free(pager_matrix[i]); - } - free(pager_matrix); - free(pager_inner_counts); - } + free_pagination(pager_matrix, pager_inner_counts, pager_count); free_image_results(results, result_count); free(request_cache_key); free(display_query); + free(locale); free_context(&ctx); return 0; -- cgit v1.3 From f20d8f711588a1918a6d75b99b0e11d745ca8395 Mon Sep 17 00:00:00 2001 From: frosty Date: Sat, 8 Aug 2026 13:25:16 -0400 Subject: refactor: add capacity-aware template string matrices --- src/Routes/Images.c | 48 +++++++----------- src/Routes/Search.c | 123 ++++++++++++++++++++++++--------------------- src/Utility/Utility.c | 136 ++++++++++++++++++++++++++++++++++++++++---------- src/Utility/Utility.h | 15 ++++++ 4 files changed, 210 insertions(+), 112 deletions(-) (limited to 'src/Routes/Images.c') diff --git a/src/Routes/Images.c b/src/Routes/Images.c index d89b732..1ab875e 100644 --- a/src/Routes/Images.c +++ b/src/Routes/Images.c @@ -41,10 +41,6 @@ static char *images_href_builder(int page, void *data) { return build_images_href((const char *)data, page); } -static void free_pagination(char ***matrix, int *inner_counts, int count) { - free_string_matrix(matrix, inner_counts, count); -} - int images_handler(UrlParams *params) { extern Config global_config; TemplateContext ctx = new_context(); @@ -80,14 +76,12 @@ int images_handler(UrlParams *params) { if (!error_images_msg) error_images_msg = "Error fetching images"; - char ***pager_matrix = NULL; - int *pager_inner_counts = NULL; - int pager_count = - build_pagination(page, images_href_builder, (void *)raw_query, - &pager_matrix, &pager_inner_counts); - if (pager_count > 0) { - context_set_array_of_arrays(&ctx, "pagination_links", pager_matrix, - pager_count, pager_inner_counts); + StringMatrix pagination; + string_matrix_build_pagination(page, images_href_builder, (void *)raw_query, + &pagination); + if (pagination.count > 0) { + context_set_array_of_arrays(&ctx, "pagination_links", pagination.rows, + pagination.count, pagination.field_counts); } char *display_query = url_decode_query(raw_query); @@ -95,7 +89,7 @@ int images_handler(UrlParams *params) { if (!raw_query || strlen(raw_query) == 0) { send_redirect("/"); - free_pagination(pager_matrix, pager_inner_counts, pager_count); + string_matrix_free(&pagination); free(display_query); free(locale); free_context(&ctx); @@ -133,7 +127,7 @@ int images_handler(UrlParams *params) { snprintf(response, sizeof(response), "

%s

", rate_limit_msg); send_response(response); free(request_cache_key); - free_pagination(pager_matrix, pager_inner_counts, pager_count); + string_matrix_free(&pagination); free(display_query); free(locale); free_context(&ctx); @@ -154,16 +148,15 @@ int images_handler(UrlParams *params) { snprintf(error_html, sizeof(error_html), "

%s

", error_images_msg); send_response(error_html); free(request_cache_key); - free_pagination(pager_matrix, pager_inner_counts, pager_count); + string_matrix_free(&pagination); free(display_query); free(locale); free_context(&ctx); return -1; } - char ***image_matrix = NULL; - int *inner_counts = NULL; - int image_count = 0; + StringMatrix images; + string_matrix_init(&images); for (int i = 0; i < result_count; i++) { const char *values[IMAGE_RESULT_FIELDS] = { @@ -172,12 +165,9 @@ int images_handler(UrlParams *params) { results[i].page_url, results[i].full_url, }; - int new_count = append_string_row(&image_matrix, &inner_counts, - image_count, values, - IMAGE_RESULT_FIELDS); - if (new_count == image_count) { - free_string_matrix(image_matrix, inner_counts, image_count); - free_pagination(pager_matrix, pager_inner_counts, pager_count); + if (string_matrix_append(&images, values, IMAGE_RESULT_FIELDS) != 0) { + string_matrix_free(&images); + string_matrix_free(&pagination); free_image_results(results, result_count); free(request_cache_key); free(display_query); @@ -185,11 +175,10 @@ int images_handler(UrlParams *params) { free_context(&ctx); return -1; } - image_count = new_count; } - context_set_array_of_arrays(&ctx, "images", image_matrix, image_count, - inner_counts); + context_set_array_of_arrays(&ctx, "images", images.rows, images.count, + images.field_counts); char *rendered = render_template("images.html", &ctx); if (rendered) { @@ -199,9 +188,8 @@ int images_handler(UrlParams *params) { send_response("

Error rendering image results

"); } - free_string_matrix(image_matrix, inner_counts, image_count); - - free_pagination(pager_matrix, pager_inner_counts, pager_count); + string_matrix_free(&images); + string_matrix_free(&pagination); free_image_results(results, result_count); free(request_cache_key); diff --git a/src/Routes/Search.c b/src/Routes/Search.c index 53718b3..abc2e73 100644 --- a/src/Routes/Search.c +++ b/src/Routes/Search.c @@ -140,29 +140,31 @@ static InfoBox fetch_currency_wrapper(char *query) { return fetch_currency_data(query); } char *get_base_url(const char *input) { - if (!input) return NULL; + if (!input) + return NULL; - const char *start = input; + const char *start = input; - const char *protocol_pos = strstr(input, "://"); - if (protocol_pos) { - start = protocol_pos + 3; - } + const char *protocol_pos = strstr(input, "://"); + if (protocol_pos) { + start = protocol_pos + 3; + } - const char *end = start; - while (*end && *end != '/' && *end != '?' && *end != '#') { - end++; - } + const char *end = start; + while (*end && *end != '/' && *end != '?' && *end != '#') { + end++; + } - size_t len = end - start; + size_t len = end - start; - char *domain = (char *)malloc(len + 1); - if (!domain) return NULL; + char *domain = (char *)malloc(len + 1); + if (!domain) + return NULL; - strncpy(domain, start, len); - domain[len] = '\0'; + strncpy(domain, start, len); + domain[len] = '\0'; - return domain; + return domain; } static int is_calculator_query(const char *query) { if (!query) @@ -252,11 +254,8 @@ static void *infobox_thread_func(void *arg) { static int add_infobox_to_collection(InfoBox *infobox, char ****collection, int **inner_counts, int current_count) { const char *values[INFOBOX_FIELD_COUNT] = { - infobox->title, - infobox->thumbnail_url, - infobox->extract, - infobox->url, - infobox->url, + infobox->title, infobox->thumbnail_url, infobox->extract, + infobox->url, infobox->url, }; return append_string_row(collection, inner_counts, current_count, values, INFOBOX_FIELD_COUNT); @@ -267,8 +266,7 @@ static int add_warning_to_collection(const char *engine_name, char ****collection, int **inner_counts, int current_count) { const char *values[] = {engine_name, warning_message}; - return append_string_row(collection, inner_counts, current_count, values, - 2); + return append_string_row(collection, inner_counts, current_count, values, 2); } static void free_user_engine_list(char **user_engines, int user_engine_count) { @@ -296,19 +294,25 @@ static void free_infobox_results(InfoBoxThreadData *data) { } } -static const char *warning_message_for_job(const ScrapeJob *job, const char *locale) { +static const char *warning_message_for_job(const ScrapeJob *job, + const char *locale) { switch (job->status) { case SCRAPE_STATUS_FETCH_ERROR: { const char *msg = beaker_get_locale_value(locale, "warning_fetch_error"); - return msg ? msg : "request failed before OmniSearch could read search results."; + return msg ? msg + : "request failed before OmniSearch could read search results."; } case SCRAPE_STATUS_PARSE_MISMATCH: { const char *msg = beaker_get_locale_value(locale, "warning_parse_mismatch"); - return msg ? msg : "returned search results in a format OmniSearch could not parse."; + return msg ? msg + : "returned search results in a format OmniSearch could not " + "parse."; } case SCRAPE_STATUS_BLOCKED: { const char *msg = beaker_get_locale_value(locale, "warning_blocked"); - return msg ? msg : "returned a captcha or another blocking page instead of search results."; + return msg ? msg + : "returned a captcha or another blocking page instead of " + "search results."; } default: return NULL; @@ -362,8 +366,8 @@ static int engine_allowed_for_user(const SearchEngine *eng, char **user_ids, static char *build_search_href(const char *query, const char *engine_id, int page) { const char *safe_query = query ? query : ""; - int use_engine = engine_id && engine_id[0] != '\0' && - !engine_id_matches(engine_id, "all"); + int use_engine = + engine_id && engine_id[0] != '\0' && !engine_id_matches(engine_id, "all"); size_t needed = strlen("/search?q=") + strlen(safe_query) + 1; if (use_engine) @@ -421,7 +425,8 @@ int results_handler(UrlParams *params) { char **user_engines = NULL; int user_engine_count = 0; - int has_user_pref = (get_user_engines(&user_engines, &user_engine_count) == 0); + int has_user_pref = + (get_user_engines(&user_engines, &user_engine_count) == 0); if (params) { for (int i = 0; i < params->count; i++) { @@ -449,9 +454,11 @@ int results_handler(UrlParams *params) { beaker_set_locale(&ctx, locale); const char *rate_limit_msg = beaker_get_locale_value(locale, "rate_limit"); - if (!rate_limit_msg) rate_limit_msg = "Slow down! Too many searches from you!"; + if (!rate_limit_msg) + rate_limit_msg = "Slow down! Too many searches from you!"; const char *no_results_msg = beaker_get_locale_value(locale, "no_results"); - if (!no_results_msg) no_results_msg = "No results found"; + if (!no_results_msg) + no_results_msg = "No results found"; char page_str[16]; snprintf(page_str, sizeof(page_str), "%d", page); @@ -604,9 +611,9 @@ int results_handler(UrlParams *params) { ? "engine-filter active" : "engine-filter"; - filter_count = add_link_to_collection(filter_href, ENGINE_REGISTRY[i].name, - filter_class, &filter_matrix, - &filter_inner_counts, filter_count); + filter_count = add_link_to_collection( + filter_href, ENGINE_REGISTRY[i].name, filter_class, &filter_matrix, + &filter_inner_counts, filter_count); free(filter_href); } @@ -660,11 +667,12 @@ int results_handler(UrlParams *params) { free_user_engine_list(user_engines, user_engine_count); free_context(&ctx); char no_results_html[128]; - snprintf(no_results_html, sizeof(no_results_html), "

%s

", no_results_msg); + snprintf(no_results_html, sizeof(no_results_html), "

%s

", + no_results_msg); send_response(no_results_html); return 0; } - + char ***infobox_matrix = NULL; int *infobox_inner_counts = NULL; int infobox_count = 0; @@ -720,9 +728,8 @@ int results_handler(UrlParams *params) { } if (total_results > 0) { - char ***results_matrix = NULL; - int *results_inner_counts = NULL; - int unique_count = 0; + StringMatrix results_matrix; + string_matrix_init(&results_matrix); UrlHashTable url_table; url_hash_init(&url_table); @@ -749,34 +756,35 @@ int results_handler(UrlParams *params) { base_url, "", }; - int new_count = append_string_row(&results_matrix, &results_inner_counts, - unique_count, values, - RESULT_FIELD_COUNT); + int append_result = + string_matrix_append(&results_matrix, values, RESULT_FIELD_COUNT); free(pretty_url); free(base_url); free(all_results[i][j].url); free(all_results[i][j].title); free(all_results[i][j].snippet); - unique_count = new_count; + if (append_result != 0) { + continue; + } } free(all_results[i]); } - context_set_array_of_arrays(&ctx, "results", results_matrix, unique_count, - results_inner_counts); + context_set_array_of_arrays(&ctx, "results", results_matrix.rows, + results_matrix.count, + results_matrix.field_counts); - char ***pager_matrix = NULL; - int *pager_inner_counts = NULL; - SearchHrefData href_data = { .query = raw_query, .engine_id = selected_engine_id }; - int pager_count = build_pagination(page, search_href_builder, - &href_data, &pager_matrix, - &pager_inner_counts); + StringMatrix pager_matrix; + SearchHrefData href_data = {.query = raw_query, + .engine_id = selected_engine_id}; + int pagination_result = string_matrix_build_pagination( + page, search_href_builder, &href_data, &pager_matrix); - if (pager_count > 0) { - context_set_array_of_arrays(&ctx, "pagination_links", pager_matrix, - pager_count, pager_inner_counts); - free_string_matrix(pager_matrix, pager_inner_counts, pager_count); + if (pagination_result == 0 && pager_matrix.count > 0) { + context_set_array_of_arrays(&ctx, "pagination_links", pager_matrix.rows, + pager_matrix.count, + pager_matrix.field_counts); } char *html = render_template("results.html", &ctx); @@ -785,7 +793,8 @@ int results_handler(UrlParams *params) { free(html); } - free_string_matrix(results_matrix, results_inner_counts, unique_count); + string_matrix_free(&pager_matrix); + string_matrix_free(&results_matrix); url_hash_free(&url_table); } else { char *html = render_template("results.html", &ctx); diff --git a/src/Utility/Utility.c b/src/Utility/Utility.c index 9c05434..97a8d15 100644 --- a/src/Utility/Utility.c +++ b/src/Utility/Utility.c @@ -263,6 +263,67 @@ void free_string_matrix(char ***matrix, int *inner_counts, int row_count) { 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 add_link_to_collection(const char *href, const char *label, const char *class_name, char ****collection, int **inner_counts, int current_count) { @@ -273,37 +334,62 @@ int add_link_to_collection(const char *href, const char *label, int build_pagination(int page, char *(*href_builder)(int page, void *data), void *data, char ****out_matrix, int **out_inner_counts) { - enum { PAGER_WINDOW_SIZE = 5 }; + if (!out_matrix || !out_inner_counts) + return 0; - *out_matrix = NULL; - *out_inner_counts = NULL; - int count = 0; + StringMatrix matrix; + if (string_matrix_build_pagination(page, href_builder, data, &matrix) != 0) { + *out_matrix = NULL; + *out_inner_counts = NULL; + return 0; + } + + *out_matrix = matrix.rows; + *out_inner_counts = matrix.field_counts; + return matrix.count; +} + +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; - if (page > 1) { - char *href = href_builder(page - 1, data); - count = add_link_to_collection(href, "←", "pagination-btn prev", out_matrix, - out_inner_counts, count); - free(href); - } + 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"; + } - for (int i = pager_start; i <= pager_end; i++) { - char label[16]; - snprintf(label, sizeof(label), "%d", i); - char *href = href_builder(i, data); - count = add_link_to_collection( - href, label, - i == page ? "pagination-btn pagination-current" : "pagination-btn", - out_matrix, out_inner_counts, count); + 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; + } } - - char *href = href_builder(page + 1, data); - count = add_link_to_collection(href, "→", "pagination-btn next", out_matrix, - out_inner_counts, count); - free(href); - - return count; + return 0; } diff --git a/src/Utility/Utility.h b/src/Utility/Utility.h index 9fca8b6..663f2c4 100644 --- a/src/Utility/Utility.h +++ b/src/Utility/Utility.h @@ -13,6 +13,13 @@ #define LINK_FIELD_COUNT 3 +typedef struct { + char ***rows; + int *field_counts; + int count; + int capacity; +} StringMatrix; + int hex_to_int(char c); char *get_theme(const char *default_theme); void init_themes(const char *static_path); @@ -28,11 +35,19 @@ int append_string_row(char ****matrix, int **inner_counts, int row_count, const char *const *values, int field_count); void free_string_matrix(char ***matrix, int *inner_counts, int row_count); +void string_matrix_init(StringMatrix *matrix); +int string_matrix_append(StringMatrix *matrix, const char *const *values, + int field_count); +void string_matrix_free(StringMatrix *matrix); + int add_link_to_collection(const char *href, const char *label, const char *class_name, char ****collection, int **inner_counts, int current_count); int build_pagination(int page, char *(*href_builder)(int page, void *data), void *data, char ****out_matrix, int **out_inner_counts); +int string_matrix_build_pagination(int page, + char *(*href_builder)(int page, void *data), + void *data, StringMatrix *out_matrix); #endif -- cgit v1.3