fix: improvements allocation safety and string processing
This commit is contained in:
parent
f20d8f7115
commit
10d44e7ff5
5 changed files with 87 additions and 166 deletions
66
src/Config.c
66
src/Config.c
|
|
@ -3,6 +3,17 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
static char *trim(char *value) {
|
||||||
|
while (*value == ' ' || *value == '\t')
|
||||||
|
value++;
|
||||||
|
|
||||||
|
char *end = value + strlen(value);
|
||||||
|
while (end > value && (end[-1] == ' ' || end[-1] == '\t'))
|
||||||
|
end--;
|
||||||
|
*end = '\0';
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
int load_config(const char *filename, Config *config) {
|
int load_config(const char *filename, Config *config) {
|
||||||
FILE *file = fopen(filename, "r");
|
FILE *file = fopen(filename, "r");
|
||||||
if (!file) {
|
if (!file) {
|
||||||
|
|
@ -33,51 +44,31 @@ int load_config(const char *filename, Config *config) {
|
||||||
char *delimiter = strchr(line, '=');
|
char *delimiter = strchr(line, '=');
|
||||||
if (delimiter) {
|
if (delimiter) {
|
||||||
*delimiter = '\0';
|
*delimiter = '\0';
|
||||||
char *key = line;
|
char *key = trim(line);
|
||||||
char *value = delimiter + 1;
|
char *value = trim(delimiter + 1);
|
||||||
|
|
||||||
while (*key == ' ' || *key == '\t')
|
char *value_end = value + strlen(value);
|
||||||
key++;
|
while (value_end > value &&
|
||||||
while (*value == ' ' || *value == '\t')
|
(value_end[-1] == '"' || value_end[-1] == '\''))
|
||||||
value++;
|
*--value_end = '\0';
|
||||||
|
|
||||||
char *key_end = key + strlen(key) - 1;
|
|
||||||
while (key_end > key && (*key_end == ' ' || *key_end == '\t')) {
|
|
||||||
*key_end = '\0';
|
|
||||||
key_end--;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *value_end = value + strlen(value) - 1;
|
|
||||||
while (value_end > value && (*value_end == ' ' || *value_end == '\t' ||
|
|
||||||
*value_end == '"' || *value_end == '\'')) {
|
|
||||||
*value_end = '\0';
|
|
||||||
value_end--;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (*value == ' ' || *value == '\t')
|
|
||||||
value++;
|
|
||||||
while (*value == '"' || *value == '\'')
|
while (*value == '"' || *value == '\'')
|
||||||
value++;
|
value++;
|
||||||
|
|
||||||
if (strcmp(section, "server") == 0) {
|
if (strcmp(section, "server") == 0) {
|
||||||
if (strcmp(key, "host") == 0) {
|
if (strcmp(key, "host") == 0) {
|
||||||
strncpy(config->host, value, sizeof(config->host) - 1);
|
snprintf(config->host, sizeof(config->host), "%s", value);
|
||||||
config->host[sizeof(config->host) - 1] = '\0';
|
|
||||||
} else if (strcmp(key, "port") == 0) {
|
} else if (strcmp(key, "port") == 0) {
|
||||||
config->port = atoi(value);
|
config->port = atoi(value);
|
||||||
} else if (strcmp(key, "locale") == 0) {
|
} else if (strcmp(key, "locale") == 0) {
|
||||||
strncpy(config->default_locale, value,
|
snprintf(config->default_locale, sizeof(config->default_locale), "%s",
|
||||||
sizeof(config->default_locale) - 1);
|
value);
|
||||||
config->default_locale[sizeof(config->default_locale) - 1] = '\0';
|
|
||||||
}
|
}
|
||||||
} else if (strcmp(section, "proxy") == 0) {
|
} else if (strcmp(section, "proxy") == 0) {
|
||||||
if (strcmp(key, "proxy") == 0) {
|
if (strcmp(key, "proxy") == 0) {
|
||||||
strncpy(config->proxy, value, sizeof(config->proxy) - 1);
|
snprintf(config->proxy, sizeof(config->proxy), "%s", value);
|
||||||
config->proxy[sizeof(config->proxy) - 1] = '\0';
|
|
||||||
} else if (strcmp(key, "list_file") == 0) {
|
} else if (strcmp(key, "list_file") == 0) {
|
||||||
strncpy(config->proxy_list_file, value,
|
snprintf(config->proxy_list_file, sizeof(config->proxy_list_file),
|
||||||
sizeof(config->proxy_list_file) - 1);
|
"%s", value);
|
||||||
config->proxy_list_file[sizeof(config->proxy_list_file) - 1] = '\0';
|
|
||||||
} else if (strcmp(key, "max_retries") == 0) {
|
} else if (strcmp(key, "max_retries") == 0) {
|
||||||
config->max_proxy_retries = atoi(value);
|
config->max_proxy_retries = atoi(value);
|
||||||
} else if (strcmp(key, "randomize_username") == 0) {
|
} else if (strcmp(key, "randomize_username") == 0) {
|
||||||
|
|
@ -87,8 +78,7 @@ int load_config(const char *filename, Config *config) {
|
||||||
}
|
}
|
||||||
} else if (strcmp(section, "cache") == 0) {
|
} else if (strcmp(section, "cache") == 0) {
|
||||||
if (strcmp(key, "dir") == 0) {
|
if (strcmp(key, "dir") == 0) {
|
||||||
strncpy(config->cache_dir, value, sizeof(config->cache_dir) - 1);
|
snprintf(config->cache_dir, sizeof(config->cache_dir), "%s", value);
|
||||||
config->cache_dir[sizeof(config->cache_dir) - 1] = '\0';
|
|
||||||
} else if (strcmp(key, "ttl_search") == 0) {
|
} else if (strcmp(key, "ttl_search") == 0) {
|
||||||
config->cache_ttl_search = atoi(value);
|
config->cache_ttl_search = atoi(value);
|
||||||
} else if (strcmp(key, "ttl_infobox") == 0) {
|
} else if (strcmp(key, "ttl_infobox") == 0) {
|
||||||
|
|
@ -98,12 +88,10 @@ int load_config(const char *filename, Config *config) {
|
||||||
}
|
}
|
||||||
} else if (strcmp(section, "engines") == 0) {
|
} else if (strcmp(section, "engines") == 0) {
|
||||||
if (strcmp(key, "engines") == 0) {
|
if (strcmp(key, "engines") == 0) {
|
||||||
strncpy(config->engines, value, sizeof(config->engines) - 1);
|
snprintf(config->engines, sizeof(config->engines), "%s", value);
|
||||||
config->engines[sizeof(config->engines) - 1] = '\0';
|
|
||||||
} else if (strcmp(key, "yacy_instance") == 0) {
|
} else if (strcmp(key, "yacy_instance") == 0) {
|
||||||
strncpy(config->yacy_instance, value,
|
snprintf(config->yacy_instance, sizeof(config->yacy_instance), "%s",
|
||||||
sizeof(config->yacy_instance) - 1);
|
value);
|
||||||
config->yacy_instance[sizeof(config->yacy_instance) - 1] = '\0';
|
|
||||||
}
|
}
|
||||||
} else if (strcmp(section, "rate_limit") == 0) {
|
} else if (strcmp(section, "rate_limit") == 0) {
|
||||||
if (strcmp(key, "search_requests") == 0) {
|
if (strcmp(key, "search_requests") == 0) {
|
||||||
|
|
|
||||||
|
|
@ -251,22 +251,20 @@ static void *infobox_thread_func(void *arg) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_infobox_to_collection(InfoBox *infobox, char ****collection,
|
static int add_infobox_to_collection(InfoBox *infobox,
|
||||||
int **inner_counts, int current_count) {
|
StringMatrix *collection) {
|
||||||
const char *values[INFOBOX_FIELD_COUNT] = {
|
const char *values[INFOBOX_FIELD_COUNT] = {
|
||||||
infobox->title, infobox->thumbnail_url, infobox->extract,
|
infobox->title, infobox->thumbnail_url, infobox->extract,
|
||||||
infobox->url, infobox->url,
|
infobox->url, infobox->url,
|
||||||
};
|
};
|
||||||
return append_string_row(collection, inner_counts, current_count, values,
|
return string_matrix_append(collection, values, INFOBOX_FIELD_COUNT);
|
||||||
INFOBOX_FIELD_COUNT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_warning_to_collection(const char *engine_name,
|
static int add_warning_to_collection(const char *engine_name,
|
||||||
const char *warning_message,
|
const char *warning_message,
|
||||||
char ****collection, int **inner_counts,
|
StringMatrix *collection) {
|
||||||
int current_count) {
|
|
||||||
const char *values[] = {engine_name, warning_message};
|
const char *values[] = {engine_name, warning_message};
|
||||||
return append_string_row(collection, inner_counts, current_count, values, 2);
|
return string_matrix_append(collection, values, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_user_engine_list(char **user_engines, int user_engine_count) {
|
static void free_user_engine_list(char **user_engines, int user_engine_count) {
|
||||||
|
|
@ -587,15 +585,14 @@ int results_handler(UrlParams *params) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filter_engine_count > 1) {
|
if (filter_engine_count > 1) {
|
||||||
char ***filter_matrix = NULL;
|
StringMatrix filter_matrix;
|
||||||
int *filter_inner_counts = NULL;
|
string_matrix_init(&filter_matrix);
|
||||||
int filter_count = 0;
|
|
||||||
char *all_href = build_search_href(raw_query, "all", 1);
|
char *all_href = build_search_href(raw_query, "all", 1);
|
||||||
|
const char *all_values[LINK_FIELD_COUNT] = {
|
||||||
filter_count = add_link_to_collection(
|
|
||||||
all_href, "All",
|
all_href, "All",
|
||||||
selected_engine ? "engine-filter" : "engine-filter active",
|
selected_engine ? "engine-filter" : "engine-filter active"};
|
||||||
&filter_matrix, &filter_inner_counts, filter_count);
|
|
||||||
|
string_matrix_append(&filter_matrix, all_values, LINK_FIELD_COUNT);
|
||||||
free(all_href);
|
free(all_href);
|
||||||
|
|
||||||
for (int i = 0; i < ENGINE_COUNT; i++) {
|
for (int i = 0; i < ENGINE_COUNT; i++) {
|
||||||
|
|
@ -611,17 +608,18 @@ int results_handler(UrlParams *params) {
|
||||||
? "engine-filter active"
|
? "engine-filter active"
|
||||||
: "engine-filter";
|
: "engine-filter";
|
||||||
|
|
||||||
filter_count = add_link_to_collection(
|
const char *filter_values[LINK_FIELD_COUNT] = {
|
||||||
filter_href, ENGINE_REGISTRY[i].name, filter_class, &filter_matrix,
|
filter_href, ENGINE_REGISTRY[i].name, filter_class};
|
||||||
&filter_inner_counts, filter_count);
|
string_matrix_append(&filter_matrix, filter_values, LINK_FIELD_COUNT);
|
||||||
free(filter_href);
|
free(filter_href);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filter_count > 0) {
|
if (filter_matrix.count > 0) {
|
||||||
context_set_array_of_arrays(&ctx, "engine_filters", filter_matrix,
|
context_set_array_of_arrays(&ctx, "engine_filters", filter_matrix.rows,
|
||||||
filter_count, filter_inner_counts);
|
filter_matrix.count,
|
||||||
free_string_matrix(filter_matrix, filter_inner_counts, filter_count);
|
filter_matrix.field_counts);
|
||||||
}
|
}
|
||||||
|
string_matrix_free(&filter_matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (page == 1) {
|
if (page == 1) {
|
||||||
|
|
@ -673,25 +671,23 @@ int results_handler(UrlParams *params) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char ***infobox_matrix = NULL;
|
StringMatrix infobox_matrix;
|
||||||
int *infobox_inner_counts = NULL;
|
string_matrix_init(&infobox_matrix);
|
||||||
int infobox_count = 0;
|
|
||||||
|
|
||||||
if (page == 1) {
|
if (page == 1) {
|
||||||
for (int i = 0; i < HANDLER_COUNT; i++) {
|
for (int i = 0; i < HANDLER_COUNT; i++) {
|
||||||
if (infobox_data[i].success) {
|
if (infobox_data[i].success) {
|
||||||
infobox_count =
|
add_infobox_to_collection(&infobox_data[i].result, &infobox_matrix);
|
||||||
add_infobox_to_collection(&infobox_data[i].result, &infobox_matrix,
|
|
||||||
&infobox_inner_counts, infobox_count);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (infobox_count > 0) {
|
if (infobox_matrix.count > 0) {
|
||||||
context_set_array_of_arrays(&ctx, "infoboxes", infobox_matrix,
|
context_set_array_of_arrays(&ctx, "infoboxes", infobox_matrix.rows,
|
||||||
infobox_count, infobox_inner_counts);
|
infobox_matrix.count,
|
||||||
free_string_matrix(infobox_matrix, infobox_inner_counts, infobox_count);
|
infobox_matrix.field_counts);
|
||||||
}
|
}
|
||||||
|
string_matrix_free(&infobox_matrix);
|
||||||
|
|
||||||
int warning_count = 0;
|
int warning_count = 0;
|
||||||
for (int i = 0; i < enabled_engine_count; i++) {
|
for (int i = 0; i < enabled_engine_count; i++) {
|
||||||
|
|
@ -700,26 +696,25 @@ int results_handler(UrlParams *params) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (warning_count > 0) {
|
if (warning_count > 0) {
|
||||||
char ***warning_matrix = NULL;
|
StringMatrix warning_matrix;
|
||||||
int *warning_inner_counts = NULL;
|
string_matrix_init(&warning_matrix);
|
||||||
int warning_index = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < enabled_engine_count; i++) {
|
for (int i = 0; i < enabled_engine_count; i++) {
|
||||||
const char *warning_message = warning_message_for_job(&jobs[i], locale);
|
const char *warning_message = warning_message_for_job(&jobs[i], locale);
|
||||||
if (!warning_message)
|
if (!warning_message)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
warning_index = add_warning_to_collection(
|
add_warning_to_collection(jobs[i].engine->name, warning_message,
|
||||||
jobs[i].engine->name, warning_message, &warning_matrix,
|
&warning_matrix);
|
||||||
&warning_inner_counts, warning_index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (warning_index > 0) {
|
if (warning_matrix.count > 0) {
|
||||||
context_set_array_of_arrays(&ctx, "engine_warnings", warning_matrix,
|
context_set_array_of_arrays(&ctx, "engine_warnings", warning_matrix.rows,
|
||||||
warning_index, warning_inner_counts);
|
warning_matrix.count,
|
||||||
|
warning_matrix.field_counts);
|
||||||
}
|
}
|
||||||
|
|
||||||
free_string_matrix(warning_matrix, warning_inner_counts, warning_index);
|
string_matrix_free(&warning_matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
int total_results = 0;
|
int total_results = 0;
|
||||||
|
|
|
||||||
|
|
@ -214,13 +214,17 @@ int setup_job(ScrapeJob *job, CURLM *multi_handle) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (char *p = encoded_query + strlen(encoded_query) - 3; p >= encoded_query;
|
char *read = encoded_query;
|
||||||
p--) {
|
char *write = encoded_query;
|
||||||
if (p[0] == '%' && p[1] == '2' && p[2] == '0') {
|
while (*read) {
|
||||||
*p = '+';
|
if (read[0] == '%' && read[1] == '2' && read[2] == '0') {
|
||||||
memmove(p + 1, p + 3, strlen(p + 3) + 1);
|
*write++ = '+';
|
||||||
|
read += 3;
|
||||||
|
} else {
|
||||||
|
*write++ = *read++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*write = '\0';
|
||||||
|
|
||||||
char *full_url =
|
char *full_url =
|
||||||
build_search_url(job->engine->base_url, job->engine->page_param,
|
build_search_url(job->engine->base_url, job->engine->page_param,
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@ static int themes_initialized = 0;
|
||||||
void init_themes(const char *static_path) {
|
void init_themes(const char *static_path) {
|
||||||
if (themes_initialized)
|
if (themes_initialized)
|
||||||
return;
|
return;
|
||||||
themes_initialized = 1;
|
|
||||||
|
|
||||||
char themes_dir[512];
|
char themes_dir[512];
|
||||||
snprintf(themes_dir, sizeof(themes_dir), "%s/themes", static_path);
|
snprintf(themes_dir, sizeof(themes_dir), "%s/themes", static_path);
|
||||||
|
|
@ -26,20 +25,32 @@ void init_themes(const char *static_path) {
|
||||||
struct dirent *entry;
|
struct dirent *entry;
|
||||||
int capacity = 4;
|
int capacity = 4;
|
||||||
themes_list = malloc(sizeof(char *) * capacity);
|
themes_list = malloc(sizeof(char *) * capacity);
|
||||||
|
if (!themes_list) {
|
||||||
|
closedir(dir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
themes_count = 0;
|
themes_count = 0;
|
||||||
|
|
||||||
while ((entry = readdir(dir)) != NULL) {
|
while ((entry = readdir(dir)) != NULL) {
|
||||||
size_t len = strlen(entry->d_name);
|
size_t len = strlen(entry->d_name);
|
||||||
if (len > 4 && strcmp(entry->d_name + len - 4, ".css") == 0) {
|
if (len > 4 && strcmp(entry->d_name + len - 4, ".css") == 0) {
|
||||||
if (themes_count >= capacity) {
|
if (themes_count >= capacity) {
|
||||||
capacity *= 2;
|
int new_capacity = capacity * 2;
|
||||||
themes_list = realloc(themes_list, sizeof(char *) * capacity);
|
char **new_list = realloc(themes_list, sizeof(char *) * new_capacity);
|
||||||
|
if (!new_list)
|
||||||
|
break;
|
||||||
|
themes_list = new_list;
|
||||||
|
capacity = new_capacity;
|
||||||
}
|
}
|
||||||
themes_list[themes_count] = strndup(entry->d_name, len - 4);
|
char *theme = strndup(entry->d_name, len - 4);
|
||||||
|
if (!theme)
|
||||||
|
break;
|
||||||
|
themes_list[themes_count] = theme;
|
||||||
themes_count++;
|
themes_count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
|
themes_initialized = 1;
|
||||||
|
|
||||||
for (int i = 0; i < themes_count; i++) {
|
for (int i = 0; i < themes_count; i++) {
|
||||||
for (int j = i + 1; j < themes_count; j++) {
|
for (int j = i + 1; j < themes_count; j++) {
|
||||||
|
|
@ -206,50 +217,6 @@ int user_engines_contains(const char *engine_id, char **ids, int count) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int append_string_row(char ****matrix, int **inner_counts, int row_count,
|
|
||||||
const char *const *values, int field_count) {
|
|
||||||
if (!matrix || !inner_counts || !values || field_count <= 0)
|
|
||||||
return row_count;
|
|
||||||
|
|
||||||
char **row = calloc((size_t)field_count, sizeof(*row));
|
|
||||||
if (!row)
|
|
||||||
return row_count;
|
|
||||||
|
|
||||||
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 row_count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char ***new_matrix = malloc(sizeof(*new_matrix) * (row_count + 1));
|
|
||||||
int *new_counts = malloc(sizeof(*new_counts) * (row_count + 1));
|
|
||||||
if (!new_matrix || !new_counts) {
|
|
||||||
free(new_matrix);
|
|
||||||
free(new_counts);
|
|
||||||
for (int i = 0; i < field_count; i++)
|
|
||||||
free(row[i]);
|
|
||||||
free(row);
|
|
||||||
return row_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (row_count > 0) {
|
|
||||||
memcpy(new_matrix, *matrix, sizeof(*new_matrix) * row_count);
|
|
||||||
memcpy(new_counts, *inner_counts, sizeof(*new_counts) * row_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
new_matrix[row_count] = row;
|
|
||||||
new_counts[row_count] = field_count;
|
|
||||||
free(*matrix);
|
|
||||||
free(*inner_counts);
|
|
||||||
*matrix = new_matrix;
|
|
||||||
*inner_counts = new_counts;
|
|
||||||
return row_count + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_string_matrix(char ***matrix, int *inner_counts, int row_count) {
|
void free_string_matrix(char ***matrix, int *inner_counts, int row_count) {
|
||||||
if (matrix) {
|
if (matrix) {
|
||||||
for (int i = 0; i < row_count; i++) {
|
for (int i = 0; i < row_count; i++) {
|
||||||
|
|
@ -324,31 +291,6 @@ void string_matrix_free(StringMatrix *matrix) {
|
||||||
*matrix = (StringMatrix){0};
|
*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) {
|
|
||||||
const char *values[LINK_FIELD_COUNT] = {href, label, class_name};
|
|
||||||
return append_string_row(collection, inner_counts, current_count, values,
|
|
||||||
LINK_FIELD_COUNT);
|
|
||||||
}
|
|
||||||
|
|
||||||
int build_pagination(int page, char *(*href_builder)(int page, void *data),
|
|
||||||
void *data, char ****out_matrix, int **out_inner_counts) {
|
|
||||||
if (!out_matrix || !out_inner_counts)
|
|
||||||
return 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,
|
int string_matrix_build_pagination(int page,
|
||||||
char *(*href_builder)(int page, void *data),
|
char *(*href_builder)(int page, void *data),
|
||||||
void *data, StringMatrix *out_matrix) {
|
void *data, StringMatrix *out_matrix) {
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,6 @@ int is_engine_id_enabled(const char *engine_id);
|
||||||
int get_user_engines(char ***out_ids, int *out_count);
|
int get_user_engines(char ***out_ids, int *out_count);
|
||||||
int user_engines_contains(const char *engine_id, char **ids, int count);
|
int user_engines_contains(const char *engine_id, char **ids, int count);
|
||||||
|
|
||||||
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 free_string_matrix(char ***matrix, int *inner_counts, int row_count);
|
||||||
|
|
||||||
void string_matrix_init(StringMatrix *matrix);
|
void string_matrix_init(StringMatrix *matrix);
|
||||||
|
|
@ -40,12 +38,6 @@ int string_matrix_append(StringMatrix *matrix, const char *const *values,
|
||||||
int field_count);
|
int field_count);
|
||||||
void string_matrix_free(StringMatrix *matrix);
|
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,
|
int string_matrix_build_pagination(int page,
|
||||||
char *(*href_builder)(int page, void *data),
|
char *(*href_builder)(int page, void *data),
|
||||||
void *data, StringMatrix *out_matrix);
|
void *data, StringMatrix *out_matrix);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue