summaryrefslogtreecommitdiff
path: root/src/save.c
diff options
context:
space:
mode:
authorAldrik Ramaekers <aldrik.ramaekers@protonmail.com>2020-01-30 21:11:12 +0100
committerAldrik Ramaekers <aldrik.ramaekers@protonmail.com>2020-01-30 21:11:12 +0100
commit260f05025631031b7cc4904805d5017feaf53eda (patch)
treed5a723bb7bbbc9f8b598712723fe3d8290c0a54c /src/save.c
initial commit
Diffstat (limited to 'src/save.c')
-rw-r--r--src/save.c380
1 files changed, 380 insertions, 0 deletions
diff --git a/src/save.c b/src/save.c
new file mode 100644
index 0000000..82ca623
--- /dev/null
+++ b/src/save.c
@@ -0,0 +1,380 @@
+/*
+* BSD 2-Clause “Simplified” License
+* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com
+* All rights reserved.
+*/
+
+search_result *create_empty_search_result();
+void* destroy_search_result_thread(void *arg);
+
+static void write_json_file(char *buffer, s32 length, search_result *search_result)
+{
+ array matches = search_result->matches;
+
+ cJSON *result = cJSON_CreateObject();
+ if (cJSON_AddStringToObject(result, "search_directory",
+ search_result->directory_to_search) == NULL)
+ return;
+
+ if (cJSON_AddStringToObject(result, "filter",
+ search_result->file_filter) == NULL)
+ return;
+
+ if (cJSON_AddStringToObject(result, "search_query",
+ search_result->text_to_find) == NULL)
+ return;
+
+ if (cJSON_AddNumberToObject(result, "duration_us",
+ search_result->find_duration_us) == NULL)
+ return;
+
+ if (cJSON_AddNumberToObject(result, "show_error",
+ search_result->show_error_message) == NULL)
+ return;
+
+ if (cJSON_AddNumberToObject(result, "file_match_found",
+ search_result->found_file_matches) == NULL)
+ return;
+
+ if (cJSON_AddNumberToObject(result, "files_searched",
+ search_result->files_searched) == NULL)
+ return;
+
+ if (cJSON_AddNumberToObject(result, "files_matched",
+ search_result->files_matched) == NULL)
+ return;
+
+ if (cJSON_AddNumberToObject(result, "query_match_found",
+ search_result->match_found) == NULL)
+ return;
+
+ if (cJSON_AddNumberToObject(result, "recursive_search",
+ search_result->is_recursive) == NULL)
+ return;
+
+ cJSON *match_list = cJSON_AddArrayToObject(result, "match_list");
+
+ if (!match_list) return;
+
+ for (s32 i = 0; i < matches.length; i++)
+ {
+ file_match* m = array_at(&matches, i);
+
+ cJSON *item = cJSON_CreateObject();
+
+ if (cJSON_AddStringToObject(item, "path",
+ m->file.path) == NULL)
+ return;
+
+ if (cJSON_AddStringToObject(item, "matched_filter",
+ m->file.matched_filter) == NULL)
+ return;
+
+ if (cJSON_AddNumberToObject(item, "word_offset",
+ m->word_match_offset) == NULL)
+ return;
+
+ if (cJSON_AddNumberToObject(item, "word_length",
+ m->word_match_length) == NULL)
+ return;
+
+ if (cJSON_AddNumberToObject(item, "file_error",
+ m->file_error) == NULL)
+ return;
+
+ if (cJSON_AddNumberToObject(item, "line_nr",
+ m->line_nr) == NULL)
+ return;
+
+ if (cJSON_AddNumberToObject(item, "file_size",
+ m->file_size) == NULL)
+ return;
+
+ if (m->line_info)
+ {
+ if (cJSON_AddStringToObject(item, "line_info",
+ m->line_info) == NULL)
+ return;
+ }
+ else
+ {
+ if (cJSON_AddNumberToObject(item, "line_info", 0) == NULL)
+ return;
+ }
+
+ cJSON_AddItemToArray(match_list, item);
+ }
+
+ cJSON_PrintPreallocated(result, buffer, length, true);
+ cJSON_Delete(result);
+}
+
+static void *export_result_d(void *arg)
+{
+ search_result *search_result = arg;
+
+ array matches = search_result->files;
+
+ char path_buf[MAX_INPUT_LENGTH];
+ path_buf[0] = 0;
+
+ char start_path[MAX_INPUT_LENGTH];
+ snprintf(start_path, MAX_INPUT_LENGTH, "%s%s", binary_path, "");
+
+ char default_save_file_extension[50];
+ string_copyn(default_save_file_extension, "json", 50);
+
+ if (!search_result->is_command_line_search)
+ {
+ struct open_dialog_args *args = mem_alloc(sizeof(struct open_dialog_args));
+ args->buffer = path_buf;
+ args->type = SAVE_FILE;
+ args->file_filter = SEARCH_RESULT_FILE_EXTENSION;
+ args->start_path = start_path;
+ args->default_save_file_extension = default_save_file_extension;
+
+ platform_open_file_dialog_block(args);
+ }
+ else
+ {
+ string_copyn(path_buf, search_result->export_path, MAX_INPUT_LENGTH);
+ }
+
+ char tmp_dir_buffer[MAX_INPUT_LENGTH];
+ get_directory_from_path(tmp_dir_buffer, path_buf);
+
+ char tmp_name_buffer[MAX_INPUT_LENGTH];
+ get_name_from_path(tmp_name_buffer, path_buf);
+
+ if (string_equals(path_buf, "")) return 0;
+ if (string_equals(tmp_name_buffer, "")) return 0;
+ if (!platform_directory_exists(tmp_dir_buffer)) return 0;
+
+ s32 size = matches.length * (MAX_INPUT_LENGTH*10);
+ char *buffer = mem_alloc(size);
+ memset(buffer, 0, size);
+
+ char *file_extension = get_file_extension(path_buf);
+ if (string_equals(file_extension, ".json") || string_equals(file_extension, ""))
+ {
+ write_json_file(buffer, size, search_result);
+ }
+
+ if (string_equals(file_extension, ""))
+ {
+ string_appendn(path_buf, ".json", MAX_INPUT_LENGTH);
+ }
+
+ platform_write_file_content(path_buf, "w", buffer, size);
+
+ return 0;
+}
+
+bool export_results(search_result *search_result)
+{
+ thread thr;
+ thr.valid = false;
+
+ while (!thr.valid)
+ thr = thread_start(export_result_d, search_result);
+
+ if (!search_result->is_command_line_search)
+ thread_detach(&thr);
+ else
+ thread_join(&thr);
+
+ return true;
+}
+
+static bool read_json_file(char *buffer, s32 size, search_result *search_result)
+{
+ cJSON *result = cJSON_Parse(buffer);
+ if (!result) return false;
+
+ cJSON *search_directory = cJSON_GetObjectItemCaseSensitive(result, "search_directory");
+ string_copyn(textbox_path.buffer, search_directory->valuestring, MAX_INPUT_LENGTH);
+ string_copyn(search_result->directory_to_search, search_directory->valuestring, MAX_INPUT_LENGTH);
+
+ cJSON *filter = cJSON_GetObjectItemCaseSensitive(result, "filter");
+ string_copyn(textbox_file_filter.buffer, filter->valuestring, MAX_INPUT_LENGTH);
+ string_copyn(search_result->file_filter, filter->valuestring, MAX_INPUT_LENGTH);
+
+ cJSON *search_query = cJSON_GetObjectItemCaseSensitive(result, "search_query");
+ string_copyn(textbox_search_text.buffer, search_query->valuestring, MAX_INPUT_LENGTH);
+ string_copyn(search_result->text_to_find, search_query->valuestring, MAX_INPUT_LENGTH);
+
+ cJSON *duration_us = cJSON_GetObjectItemCaseSensitive(result, "duration_us");
+ search_result->find_duration_us = duration_us->valueint;
+
+ cJSON *show_error = cJSON_GetObjectItemCaseSensitive(result, "show_error");
+ search_result->show_error_message = show_error->valueint;
+
+ cJSON *file_match_found = cJSON_GetObjectItemCaseSensitive(result, "file_match_found");
+ search_result->found_file_matches = file_match_found->valueint;
+
+ cJSON *files_searched = cJSON_GetObjectItemCaseSensitive(result, "files_searched");
+ search_result->files_searched = files_searched->valueint;
+
+ cJSON *files_matched = cJSON_GetObjectItemCaseSensitive(result, "files_matched");
+ search_result->files_matched = files_matched->valueint;
+
+ cJSON *query_match_found = cJSON_GetObjectItemCaseSensitive(result, "query_match_found");
+ search_result->match_found = query_match_found->valueint;
+
+ cJSON *recursive = cJSON_GetObjectItemCaseSensitive(result, "recursive_search");
+ search_result->is_recursive = recursive->valueint;
+ checkbox_recursive.state = search_result->is_recursive;
+
+ search_result->search_result_source_dir_len = strlen(search_result->directory_to_search);
+
+ cJSON *file_list = cJSON_GetObjectItem(result, "match_list");
+ cJSON *file;
+ cJSON_ArrayForEach(file, file_list)
+ {
+ file_match new_match;
+
+ ////
+ cJSON *path = cJSON_GetObjectItem(file, "path");
+ new_match.file.path = memory_bucket_reserve(&search_result->mem_bucket, strlen(path->valuestring)+1);
+ string_copyn(new_match.file.path, path->valuestring, strlen(path->valuestring)+1);
+
+ ////
+ cJSON *matched_filter = cJSON_GetObjectItem(file, "matched_filter");
+ new_match.file.matched_filter = memory_bucket_reserve(&search_result->mem_bucket, strlen(matched_filter->valuestring)+1);
+ string_copyn(new_match.file.matched_filter, matched_filter->valuestring, strlen(matched_filter->valuestring)+1);
+
+ ////
+ cJSON *word_offset = cJSON_GetObjectItem(file, "word_offset");
+ new_match.word_match_offset = word_offset->valueint;
+
+ ////
+ cJSON *word_length = cJSON_GetObjectItem(file, "word_length");
+ new_match.word_match_length = word_length->valueint;
+
+ ////
+ cJSON *file_error = cJSON_GetObjectItem(file, "file_error");
+ new_match.file_error = file_error->valueint;
+
+ ////
+ cJSON *line_nr = cJSON_GetObjectItem(file, "line_nr");
+ new_match.line_nr = line_nr->valueint;
+
+ ////
+ cJSON *file_size = cJSON_GetObjectItem(file, "file_size");
+ new_match.file_size = file_size->valueint;
+
+ ////
+ cJSON *line_info = cJSON_GetObjectItem(file, "line_info");
+ if (cJSON_IsString(line_info))
+ {
+ new_match.line_info = memory_bucket_reserve(&search_result->mem_bucket, strlen(line_info->valuestring)+1);
+ string_copyn(new_match.line_info, line_info->valuestring, strlen(line_info->valuestring)+1);
+ search_result->match_found = true;
+ }
+ else
+ {
+ new_match.line_info = 0;
+ }
+
+ // calculate highlight offsets
+ if (new_match.line_info)
+ {
+ new_match.word_match_offset_x =
+ calculate_text_width_upto(font_mini, new_match.line_info, new_match.word_match_offset);
+
+ new_match.word_match_width =
+ calculate_text_width_from_upto(font_mini, new_match.line_info, new_match.word_match_offset, new_match.word_match_offset + new_match.word_match_length);
+ }
+
+ array_push(&search_result->matches, &new_match);
+ }
+
+ return true;
+}
+
+void import_results_from_file(char *path_buf)
+{
+ char *file_extension = get_file_extension(path_buf);
+ if (!string_equals(file_extension, ".json") && !string_equals(file_extension, ".xml") && !string_equals(file_extension, ".yaml"))
+ {
+ platform_show_message(main_window, localize("invalid_search_result_file"), localize("error_importing_results"));
+ return;
+ }
+
+ scroll_y = 0;
+ file_content content = platform_read_file_content(path_buf, "r");
+
+ if (!content.content || content.file_error)
+ {
+ platform_destroy_file_content(&content);
+ return;
+ }
+
+ search_result *new_result = create_empty_search_result();
+ search_result *old_result = current_search_result;
+ current_search_result = new_result;
+
+ thread cleanup_thread = thread_start(destroy_search_result_thread, old_result);
+ thread_detach(&cleanup_thread);
+
+ if (string_equals(file_extension, ".json"))
+ {
+ bool result = read_json_file(content.content, content.content_length, new_result);
+ if (!result) goto failed_to_load_file;
+ }
+ else
+ {
+ goto failed_to_load_file;
+ }
+
+ new_result->walking_file_system = false;
+ new_result->done_finding_matches = true;
+ new_result->done_finding_files = true;
+
+ snprintf(global_status_bar.result_status_text, MAX_INPUT_LENGTH, localize("files_matches_comparison"), current_search_result->matches.length, current_search_result->files_searched, current_search_result->find_duration_us/1000.0);
+
+ array_destroy(&new_result->files);
+ platform_destroy_file_content(&content);
+ return;
+
+ failed_to_load_file:
+ platform_show_message(main_window, localize("invalid_search_result_file"), localize("error_importing_results"));
+ platform_destroy_file_content(&content);
+}
+
+static void* import_results_d(void *arg)
+{
+ char path_buf[MAX_INPUT_LENGTH];
+ path_buf[0] = 0;
+
+ char start_path[MAX_INPUT_LENGTH];
+ snprintf(start_path, MAX_INPUT_LENGTH, "%s%s", binary_path, "");
+
+ char default_save_file_extension[50];
+ string_copyn(default_save_file_extension, "json", 50);
+
+ struct open_dialog_args *args = mem_alloc(sizeof(struct open_dialog_args));
+ args->buffer = path_buf;
+ args->type = OPEN_FILE;
+ args->file_filter = SEARCH_RESULT_FILE_EXTENSION;
+ args->start_path = start_path;
+ args->default_save_file_extension = default_save_file_extension;
+
+ platform_open_file_dialog_block(args);
+
+ if (string_equals(path_buf, "")) return 0;
+ if (!platform_file_exists(path_buf)) return 0;
+
+ import_results_from_file(path_buf);
+ return 0;
+}
+
+void import_results()
+{
+ thread thr;
+ thr.valid = false;
+
+ while (!thr.valid)
+ thr = thread_start(import_results_d, 0);
+ thread_detach(&thr);
+} \ No newline at end of file