From 5108f6062c1045b85ba0e624eab0833326604b86 Mon Sep 17 00:00:00 2001 From: dam Date: Tue, 28 Mar 2023 03:12:21 +0100 Subject: Prototyping database load and store. --- ttt.jai | 417 +++++++++++++++++++++++++++++----------------------------------- 1 file changed, 187 insertions(+), 230 deletions(-) diff --git a/ttt.jai b/ttt.jai index 2dac60b..42c68d7 100644 --- a/ttt.jai +++ b/ttt.jai @@ -14,14 +14,15 @@ // this program. If not, see . // Compilation commands: -// - release : jai ttt.jai -import_dir . -x64 -release -// - debug : jai ttt.jai -import_dir . -x64 +// - release : jai ttt.jai -import_dir . -quiet -x64 -release +// - debug : jai ttt.jai -import_dir . -quiet -x64 #import "Basic"()(MEMORY_DEBUGGER=true); #import "System"; #import "Math"; #import "POSIX"; #import "File"; +#import "File_Utilities"; #import "String"; #import "curses"; @@ -155,17 +156,6 @@ void show_processing() { refresh(); } -// Checks if file is exists and is accessible. -// Returns true when the file exists and is accessible. -bool is_file_accessible(const char *path) { - assert(path != NULL); - FILE *file = fopen(path, "r+"); - bool is_file_accessible = file != NULL; - if (is_file_accessible) { - fclose(file); - } - return is_file_accessible; -} */ // Returns true if string to_compare is equal to any of the other passed strings, false otherwise. @@ -237,19 +227,13 @@ is_empty_string :: (str: string) -> bool { } return true; } -/* -// Uses strchr to replace all instances of find by replace. -// Returns string. -replace_char :: (str: string, char find, char replace) -> string { // TODO Use modules/String/module.jai:replace_chars - // TODO replace_chars :: (s: string, chars: string, replacement: u8) { - char *idx = string; - while((idx = strchr(idx, find)) != NULL) { - *idx = replace; - idx++; - } - return string; -} +replace_char :: (str: string, find: u8, replace: u8) -> string { + assert(false, "Use modules/String/module.jai:replace_chars"); + // TODO Use modules/String/module.jai:replace_chars + return ""; +} +/* // Prints, on row y and column x, the time using 5 characters centered on space. // Returns the result of a call to mvprintw. int mvprintw_time(int y, int x, intmax_t time, int space) { @@ -606,52 +590,73 @@ void add_task_time(database_st *db, task_st *task, int day, int64_t time) { task->times[day] = add_int64(task->times[day], time); db->total_times[day] = add_int64(db->total_times[day], time); } +*/ // Resets database to the initial state and deallocates all memory taken by tasks. -void reset_database(database_st *db) { - assert(db != NULL); +reset_database :: (db: *Database) { + assert(db != null); - free(db->tasks); - memset(db, 0, SIZEOF_DATABASE_ST); - db->active_task = -1; - db->selected_task = -1; + free(db.tasks.data); + <tasks, SIZEOF_TASK_ST, db->count, file); +// +// fclose(file); +// return true; +// } + +// Stores data from database into binary file. +// Returns success. +store_database :: (db: *Database, path: string) -> success: bool { + assert(db != null, "Parameter 'db' is null."); + assert(xx path, "Parameter 'path' is empty."); // Open file. - FILE *file = fopen(path, "wb"); - if (file == NULL) { - print_error("Failed to open file '%s' while storing database: %s.", path, strerror(errno)); + file, open_success := file_open(path, for_writing = true); // log_errors: bool = true + if open_success == false { + print_error("Failed to open file '%' while storing database: ERROR_FROM_LOG", path); // TODO Get error from logger ?! return false; } + defer file_close(*file); - fwrite(DB_FILE_SIGN, SIZEOF_CHAR, DB_FILE_SIGN_LENGTH, file); - fwrite(db, SIZEOF_DATABASE_ST, 1, file); - fwrite(db->tasks, SIZEOF_TASK_ST, db->count, file); - - fclose(file); + file_write(*file, DB_FILE_SIGN_STR); + file_write(*file, db, size_of(Database)); + file_write(*file, db.tasks.data, size_of(Task)*db.tasks.count); + return true; } // Loads data from binary file into database. // Returns success. +/* bool load_database(database_st *db, const char *path) { assert(db != NULL); assert(path != NULL); - // Open file. + Open file. FILE *file = fopen(path, "rb"); if (file == NULL) { print_error("Failed to open file '%s' while loading database: %s.", path, strerror(errno)); return false; } - // Validate file signature. + Validate file signature. char file_signature[DB_FILE_SIGN_LENGTH]; fread(&file_signature, SIZEOF_CHAR, DB_FILE_SIGN_LENGTH, file); if (strncmp(file_signature, DB_FILE_SIGN, DB_FILE_SIGN_LENGTH) != 0) { @@ -660,10 +665,10 @@ bool load_database(database_st *db, const char *path) { return false; } - // Read database structure. + Read database structure. fread(db, SIZEOF_DATABASE_ST, 1, file); - // Reserve database capacity for tasks. + Reserve database capacity for tasks. size_t capacity_bytes = db->capacity * SIZEOF_TASK_ST; db->tasks = malloc(capacity_bytes); if (db->tasks == NULL && capacity_bytes > 0) { @@ -671,46 +676,110 @@ bool load_database(database_st *db, const char *path) { return false; } - // Read database tasks. + Read database tasks. fread(db->tasks, SIZEOF_TASK_ST, db->count, file); - // Make sure we are reading all the file. + Make sure we are reading all the file. assert(fgetc(file) == EOF); fclose(file); return true; -} +}*/ -// Exports data into CSV file. +// Loads data from binary file into database. // Returns success. -bool export_to_csv(const database_st *db, const char *path) { - assert(db != NULL); - assert(path != NULL); +load_database :: (db: *Database, path: string) -> success: bool { + assert(db != null, "Parameter 'db' is null."); + assert(xx path, "Parameter 'path' is empty."); - FILE *file = fopen(path, "w"); - if (file == NULL) { - print_error("Failed to open file '%s' while exporting to CSV: %s.", path, strerror(errno)); + // Open file. + file, open_success := file_open(path); // log_errors: bool = true + if open_success == false { + print_error("Failed to open file '%' while loading database: ERROR_FROM_LOG", path); // TODO Get error from logger ?! return false; } + defer file_close(*file); - fprintf(file, "%s,%s,%s,%s,%s,%s,%s,%s\n", - "task", "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday" - ); + // Validate file signature. + file_signature: [DB_FILE_SIGN_STR.count] u8; + read_success := file_read(file, *file_signature, DB_FILE_SIGN_STR.count); + if read_success == false print_error("Failed to read file signature from '%'.", path); + if cast(string)file_signature != DB_FILE_SIGN_STR { + print_error("Invalid file signature."); + file_close(*file); + return false; + } - char name[TASK_NAME_BYTES]; - for (size_t idx = 0; idx < db->count; idx++) { - task_st *task = &db->tasks[idx]; - memcpy(name, task->name, TASK_NAME_BYTES); - replace_char(name, ',', ' '); - fprintf(file, "%s,%" PRId64 ",%" PRId64 ",%" PRId64 ",%" PRId64 ",%" PRId64 ",%" PRId64 ",%" PRId64 "\n", - name, task->times[0], task->times[1], task->times[2], task->times[3], task->times[4], task->times[5], task->times[6] - ); + // Read database structure. + read_success = file_read(file, db, size_of(Database)); + db.tasks.data = null; // Discard invalid pointer read into 'data'. + //if read_success == false print_error("Failed to read database info from '%'.", path); TODO + + //file_open :: (name: string, for_writing := false, keep_existing_content := false, log_errors := true) -> File, bool + //file_read :: (f: File, vdata: *void, bytes_to_read: s64) -> (success: bool, total_read: s64) + + + // Reserve database capacity for tasks. HACK + value := db.tasks.count; + d: [..] Task; + db.tasks = d; +// array_reserve(*db.tasks, value); +// db.tasks.count = value; + +// size_t capacity_bytes = db->capacity * SIZEOF_TASK_ST; +// db->tasks = malloc(capacity_bytes); +// if (db->tasks == NULL && capacity_bytes > 0) { +// print_error("Failed to allocate memory while loading database: %s.", strerror(errno)); +// return false; +// } +// + // Read database tasks. HACK + for 0..value-1 { + task: Task; + file_read(file, *task, size_of(Task)); + array_add(*db.tasks, task); } +// file_read(file, db.tasks.data, size_of(Task)*db.tasks.count); + + // Make sure we are reading all the file. + buffer: [1] u8; + success, bytes := file_read(file, *buffer, 1); + assert(bytes == 0); + + print("done importing CSV with a bunch of hacks\n"); - fclose(file); return true; } -*/ + +// Exports data into CSV file. +// Returns success. +export_to_csv :: (db: *Database, path: string) -> success: bool { + assert(db != null, "Parameter 'db' is null."); + assert(xx path, "Parameter 'path' is empty."); + // TODO Make sure (IN ALL PROCEDURES) we're not receiving an empty path. + + + builder: String_Builder; + defer reset(*builder); + + CSV_HEADER :: string.[ "task", "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday" ]; + print_to_builder(*builder, "%\n", join(..CSV_HEADER, separator = ",")); + + buffer: [Task.name.count] u8; + name: string = xx buffer; + for db.tasks { + memcpy(name.data, it.name.data, name.count); + replace_chars(name, ",", #char " "); + print_to_builder(*builder, "%,%,%,%,%,%,%,%\n", + name, it.times[0], it.times[1], it.times[2], + it.times[3], it.times[4], it.times[5], it.times[6]); + } + + write_entire_file(path, *builder); + + return true; +} + // Imports CSV file into database. // Returns success. import_from_csv :: (db: *Database, path: string) -> bool { @@ -831,7 +900,7 @@ import_from_csv :: (db: *Database, path: string) -> bool { print("temp: %\n", context.temporary_storage.total_bytes_occupied >> 20); reset_temporary_storage(); - return false; + return true; } /* // Appends task to the end of the CSV file. @@ -1295,6 +1364,9 @@ bool read_enter_confirmation(int row, int style, const char *message) { main :: () { + database: Database; + archive: Database; + defer report_memory_leaks(); // TODO DEBUG defer free_memory(); @@ -1308,158 +1380,43 @@ main :: () { home_path, success_path := get_absolute_path(home_dir); // Returns temporary memory. TODO LEAK if success_path == false { print_error("Failed to find home directory '%'.", home_dir); - return; + exit(1); } app_directory = join(home_path, "/", APP_FOLDER_NAME); db_file_path = join(app_directory, "/", DB_FILE_NAME); ar_file_path = join(app_directory, "/", AR_FILE_NAME); - } - - - db: Database; - { - import_from_csv(*db, ar_file_path); - - for db.tasks print_task(it); - - print_task :: (task: Task) { - for task.times print("% |", it); - print(" %\n", cast(string)task.name); - } - return; - - // Stores data from database into binary file. - // Returns success. - store_database :: (db: Database, path: string) -> success: bool { - //assert(db != null, "Parameter 'db' is null."); - assert(xx path, "Parameter 'path' is empty."); - - // Open file. - file, open_success := file_open(path, for_writing = true); // log_errors: bool = true - if open_success == false { - print_error("Failed to open file '%' while storing database: ERROR_FROM_LOG", path); // TODO Get error from logger ?! - return false; - } - defer file_close(*file); - - file_write(*file, DB_FILE_SIGN_STR); - file_write(*file, *db, size_of(Database)); - //fwrite(DB_FILE_SIGN, SIZEOF_CHAR, DB_FILE_SIGN_LENGTH, file); - //fwrite(db, SIZEOF_DATABASE_ST, 1, file); - //fwrite(db->tasks, SIZEOF_TASK_ST, db->count, file); + make_directory_if_it_does_not_exist(app_directory, recursive = true); + } - return true; - } - - // Loads data from binary file into database. - // Returns success. - load_database :: (db: *Database, path: string) -> success: bool { - assert(db != null, "Parameter 'db' is null."); - assert(xx path, "Parameter 'path' is empty."); - - // Open file. - file, open_success := file_open(path); // log_errors: bool = true - if open_success == false { - print_error("Failed to open file '%' while loading database: ERROR_FROM_LOG", path); // TODO Get error from logger ?! - return false; - } - defer file_close(*file); - - // Validate file signature. - file_signature: [DB_FILE_SIGN_STR.count] u8; - read_success := file_read(file, *file_signature, DB_FILE_SIGN_STR.count); - if read_success == false print_error("Failed to read file signature from '%'.", path); - if cast(string)file_signature != DB_FILE_SIGN_STR { - print_error("Invalid file signature."); - file_close(*file); - return false; - } - - // Read database structure. - - read_success = file_read(file, db, size_of(Database)); - //if read_success == false print_error("Failed to read database info from '%'.", path); - - - //file_open :: (name: string, for_writing := false, keep_existing_content := false, log_errors := true) -> File, bool - //file_read :: (f: File, vdata: *void, bytes_to_read: s64) -> (success: bool, total_read: s64) - - return true; - } - - - // Loads data from binary file into database. - // Returns success. - /* - load_database :: ( + { // Initialize database and archive files if needed. - - bool load_database(database_st *db, const char *path) { - assert(db != NULL); - assert(path != NULL); - - // Open file. - FILE *file = fopen(path, "rb"); - if (file == NULL) { - print_error("Failed to open file '%s' while loading database: %s.", path, strerror(errno)); - return false; - } - - // Validate file signature. - char file_signature[DB_FILE_SIGN_LENGTH]; - fread(&file_signature, SIZEOF_CHAR, DB_FILE_SIGN_LENGTH, file); - if (strncmp(file_signature, DB_FILE_SIGN, DB_FILE_SIGN_LENGTH) != 0) { - print_error("Invalid file signature."); - fclose(file); - return false; + if (file_exists(db_file_path) == false) { + if (store_database(*database, db_file_path) == false) { + print_error("Failed to initialize database."); + exit(1); } - - // Read database structure. - fread(db, SIZEOF_DATABASE_ST, 1, file); - - // Reserve database capacity for tasks. - size_t capacity_bytes = db->capacity * SIZEOF_TASK_ST; - db->tasks = malloc(capacity_bytes); - if (db->tasks == NULL && capacity_bytes > 0) { - print_error("Failed to allocate memory while loading database: %s.", strerror(errno)); - return false; - } - - // Read database tasks. - fread(db->tasks, SIZEOF_TASK_ST, db->count, file); - - // Make sure we are reading all the file. - assert(fgetc(file) == EOF); - - fclose(file); - return true; } - */ - } - - return; // TODO DEBUG - - /* - db = &database; - reset_database(&database); - reset_database(&archive); - if (is_file_accessible(db_file_path) == false) { - if (store_database(&database, db_file_path) == false) { - print_error("Failed to initialize database."); - return; + if (file_exists(ar_file_path) == false) { + if (export_to_csv(*archive, ar_file_path) == false) { + print_error("Failed to initialize archive."); + exit(1); + } } - } - if (is_file_accessible(ar_file_path) == false) { - if (export_to_csv(&archive, ar_file_path) == false) { - print_error("Failed to initialize archive."); - return; - } + +// import_from_csv(*db, ar_file_path); +// +// for db.tasks print_task(it); +// +// print_task :: (task: Task) { +// for task.times print("% |", it); +// print(" %\n", cast(string)task.name); +// } +// return; } - */ args := get_command_line_arguments(); defer array_reset(*args); @@ -1531,19 +1488,19 @@ main :: () { return; } // TODO Implement -// if (load_database(&database, db_file_path) == false) { -// print_error("Failed to load database."); -// return; -// } -// if (import_from_csv(&database, args[it]) == false) { -// print_error("Failed to import CSV file."); -// return; -// } -// if (store_database(&database, db_file_path) == false) { -// print_error("Failed to store database."); -// return; -// } -// reset_database(&database); + if (load_database(*database, db_file_path) == false) { + print_error("Failed to load database."); + return; + } + if (import_from_csv(*database, args[it]) == false) { + print_error("Failed to import CSV file."); + return; + } + if (store_database(*database, db_file_path) == false) { + print_error("Failed to store database."); + return; + } + reset_database(*database); is_exit_requested = true; continue; } @@ -1555,15 +1512,15 @@ main :: () { return; } // TODO Implement -// if (load_database(&database, db_file_path) == false) { -// print_error("Failed to load database."); -// return; -// } -// if (export_to_csv(&database, args[it]) == false) { -// print_error("Failed to export CSV file."); -// return; -// } -// reset_database(&database); + if (load_database(*database, db_file_path) == false) { + print_error("Failed to load database."); + return; + } + if (export_to_csv(*database, args[it]) == false) { + print_error("Failed to export CSV file."); + return; + } + reset_database(*database); is_exit_requested = true; continue; } -- cgit v1.2.3