diff options
| author | dam <dam@gudinoff> | 2023-02-26 18:24:30 +0000 |
|---|---|---|
| committer | dam <dam@gudinoff> | 2023-02-26 18:24:30 +0000 |
| commit | ffbcc2d1556dcd55f53abb320c5be72951506f9f (patch) | |
| tree | 4355678b8062c2376da8828b92f49c306e378a90 | |
| parent | b75c965d3d2bb4bd9059d0df0366cd54f76825ff (diff) | |
| download | task-time-tracker-ffbcc2d1556dcd55f53abb320c5be72951506f9f.tar.zst task-time-tracker-ffbcc2d1556dcd55f53abb320c5be72951506f9f.zip | |
Prototype implementation of import_csv, sys_open, sys_close, and usage of map_entire_file_start.
| -rw-r--r-- | syscall.jai | 107 | ||||
| -rw-r--r-- | ttt.jai | 274 |
2 files changed, 216 insertions, 165 deletions
diff --git a/syscall.jai b/syscall.jai index 46a9d84..e30dc2f 100644 --- a/syscall.jai +++ b/syscall.jai @@ -8,43 +8,106 @@ // Syscall info: https://filippo.io/linux-syscall-table/ main :: () { - print("starting syscall\n"); - - sys_exit(-1); - fd := sys_open("./dummy"); - print("fd is %\nerrno is %\n", fd, errno()); - print("done syscall\n"); + //sys_exit(-1); + print("> open dummy\n"); + fd, error_open := sys_open("./dummy"); + print("> opened dummy with fd % and errno %\n", fd, error_open); + if fd < 0 return; + LOOPER :: "\\|/-"; idx := 0; loop: string; loop.count = 1; - for 0..3 { + for 0..1 { sleep_milliseconds(1000); loop.data = *LOOPER.data[idx]; idx = (idx + 1) % LOOPER.count; print("\rlooping %", loop); } + + error_close := sys_close(fd); + print("\r> close(%) with errno %\n", fd, error_close); - sys_close(fd); - print("\rclosed\n"); - - for 0..3 { - sleep_milliseconds(1000); - loop.data = *LOOPER.data[idx]; - idx = (idx + 1) % LOOPER.count; - print("\rlooping %", loop); - } + print("---\n"); + error :s64; + fd, error = sys_open("./fail"); + print("$ open(fail) returned fd % and error %\n", fd, error); + error = sys_close(456); + print("$ close(456) returned error %\n", error); } -sys_open :: (path: string) -> fd: s64 { - SYS_OPEN :: 2; - return syscall(SYS_OPEN, cast(*s8)path.data, O_RDONLY); + + + + + + + +sys_open :: (path: string) -> file_descriptor: s64, error: s64 { + + #if OS == .WINDOWS { + print("TODO Implement this\n"); // TODO Implement this. + } + else #if OS == .LINUX { + SYS_OPEN :: 2; + data: *s8 = xx path.data; + result: s64 = ---; + #if CPU == .X64 { + print("\r# LINUX:ASM\n"); + #asm SYSCALL_SYSRET { + mov rax: gpr === a, SYS_OPEN; + mov rdi: gpr === di, data; + mov rsi: gpr === si, O_RDONLY; + mov rdx: gpr === d, O_RDONLY; + //syscall rcx, r11, rax, rdi, rsi, rdx; // TODO Cleanup? + syscall + rcx: gpr === c, // Implicitly used by syscall to store RIP + r11: gpr === 11, // Implicitly used by syscall to store RFLAGS + rax, rdi, rsi, rdx; + mov result, rax; + } + if result < 0 + return -1, -result; // Error. + else + return result, 0; // OK. + } else { + print("\r# LINUX:LIBC\n"); + result = syscall(SYS_OPEN, data, O_RDONLY); + if result < 0 + return -1, errno(); // Error. + else + return result, 0; // OK. + } + } } -sys_close :: (fd: s64) { - SYS_CLOSE :: 3; - syscall(SYS_CLOSE, fd); +sys_close :: (file_descriptor: s64) -> error: s64 { + + #if OS == .WINDOWS { + print("TODO Implement this\n"); // TODO Implement this. + } + else #if OS == .LINUX { + SYS_CLOSE :: 3; + result: s64 = ---; + #if CPU == .X64 { + print("\r# LINUX:ASM\n"); + #asm SYSCALL_SYSRET { + mov rax: gpr === a, SYS_CLOSE; + mov rdi: gpr === di, file_descriptor; + syscall + rcx: gpr === c, // Implicitly used by syscall to store RIP + r11: gpr === 11, // Implicitly used by syscall to store RFLAGS + rax, rdi; + mov result, rax; + } + return ifx result < 0 then -result else 0; + } else { + print("\r# LINUX:LIBC\n"); + result = syscall(SYS_CLOSE, file_descriptor); + return ifx result < 0 then errno() else 0; + } + } } sys_exit :: (status: s32) { @@ -43,27 +43,18 @@ SECONDS_IN_DAY :: cast(s64)24*SECONDS_IN_HOUR; SECONDS_IN_YEAR :: cast(s64)365*SECONDS_IN_DAY; MAX_DATABASE_TASKS :: S64_MAX; -OldTask :: struct { - times : [NUM_WEEK_DAYS] s64; - name : [TASK_NAME_BYTES] u8; // TODO Start using strings. -} - Task :: struct { times : [NUM_WEEK_DAYS] s64; - name : string~s8; - name_data : [62]u8; - name.data = cast(*~s8 u8) (0x80 ^ 0x01); // *name_data[0]; + name : [72] u8; + //name_data : [70] u8; + //name.data = cast(*~s8 u8) (0x80 ^ 0x01); // *name_data[0]; } -DatabaseCore :: struct { +Database :: struct { + modified_on : Apollo_Time; active_idx : s64; - selected_task : s64; - modified_on : s64; + selected_idx : s64; total_times : [NUM_WEEK_DAYS] s64; -} - -Database :: struct { - #as using base : DatabaseCore; tasks : [..] Task; } @@ -325,7 +316,18 @@ task_st *get_selected_task(database_st *db) { } return task; } - +*/ +// Creates new task stored at location given by task pointer. +// If necessary, expands database capacity. +// Returns success. +add_task :: (db: *Database, task: *Task) -> success: bool { + idx := db.tasks.count; + maybe_grow(*db.tasks); // TODO Check for errors? + db.tasks.count += 1; + db.tasks[idx] = task; + return true; +} +/* // Creates new task stored at location given by task pointer. // If necessary, expands database capacity. // Returns success. @@ -693,70 +695,83 @@ bool export_to_csv(const database_st *db, const char *path) { fclose(file); return true; } - +*/ // Imports CSV file into database. // Returns success. -bool import_from_csv(database_st *db, const char *path) { - assert(db != NULL); - assert(path != NULL); +import_from_csv :: (db: *Database, path: string) -> bool { - FILE *file = fopen(path, "r"); - if (file == NULL) { - print_error("Failed to open file '%s' while importing from CSV: %s.", path, strerror(errno)); + assert(db != null, "Parameter 'db' is null."); + assert(xx path, "Parameter 'path' is empty."); + + // Read file. + file_data, success := read_entire_file(path); // TODO Read entire file... may fail it file is too big. + if success == false { + print_error("Failed to read file '%' while loading database: ERROR_FROM_LOG", path); // TODO Get error from logger ?! return false; } + defer free(file_data.data); + csv := file_data; - // Skip header line. - fscanf(file, "%*[^\n]\n"); + // TODO Helper function. + consume_next_line :: (sp: *string) -> string, bool { + // To find the end of the line, we look for a linefeed character. + // We will trim a carriage return off the end if there is one there also. + // Thus this works on both 'dos' and 'unix'-style files. - // Parse CSV file. - char *csv_buffer = NULL; - size_t csv_buffer_size = 0; - while(getline(&csv_buffer, &csv_buffer_size, file) != -1) { // Check if reached EOF. - - // Find task name string limits. - char *name_delimiter = strchr(csv_buffer, ','); - if (name_delimiter == NULL) { - continue; - } - size_t name_length = (name_delimiter - csv_buffer); - if (name_length > TASK_NAME_LENGTH) { - name_length = TASK_NAME_LENGTH; + s := << sp; + found, result, right := split_from_left(s, 10); + + if !found { + // This is the last line; there may not have been a linefeed after that, + // but we still want to handle that data, so we return true if there was + // a nonzero amount of stuff there. + + << sp = ""; + + return s, (s.count > 0); } - - // Prepare new task. - task_st *task; - if (create_task(db, &task) == false) { - return false; + + // Chop the characters we are going to return from 'sp', + // which holds the remaining file data. + advance(sp, result.count + 1); + + if result { + if result[result.count-1] == 13 result.count -= 1; // If there's a carriage return at the end, remove it by decrementing the string's length. } - // Import task name. - memcpy(task->name, csv_buffer, name_length); - truncate_string_utf8(task->name, name_length); + return result, true; + } + + //Skip header line. + consume_next_line(*csv); + + // TODO Helper function. + advance :: inline (array: *[] $T, amount: int = 1) { + assert(amount >= 0); + assert(array.count >= amount); + array.count -= amount; + array.data += amount; + } + + // Parse CSV lines. + while (true) { + line, success := consume_next_line(*csv); + if success == false break; - // Parse task times. - if (sscanf(name_delimiter + 1, - "%" SCNd64 ",%" SCNd64 ",%" SCNd64 ",%" SCNd64 ",%" SCNd64 ",%" SCNd64 ",%" SCNd64, - &task->times[0], &task->times[1], &task->times[2], &task->times[3], &task->times[4], &task->times[5], &task->times[6] - ) != NUM_WEEK_DAYS - ) { - replace_char(csv_buffer, '\n', ' '); - print_error("Discarding invalid line '%s' and continuing.", csv_buffer); - delete_task(db, task); - continue; + task: Task; + values := split(line, ","); // TODO Temporary memory... if file is too big this may break. + memcpy(task.name.data, values[0].data, xx min(task.name.count, values[0].count)); + advance(*values); + for values { + task.times[it_index] = string_to_int(it); } - // Add task timer values to total timers. - for (int idx = 0; idx < NUM_WEEK_DAYS; idx++) { - db->total_times[idx] = add_int64(db->total_times[idx], task->times[idx]); - } + add_task(db, *task); } - fclose(file); - free(csv_buffer); - return true; + return false; } - +/* // Appends task to the end of the CSV file. // Returns success. bool append_to_csv(task_st *task, const char *path) { @@ -1237,82 +1252,53 @@ main :: () { } - { // Load database prototype - -/* -typedef struct { - task_st *tasks; - size_t count; // Will always be equal or less than capacity. - size_t capacity; // Will always be equal or less than PTRDIFF_MAX (see MAX_DATABASE_TASKS). - ptrdiff_t active_task; // Will always be less than capacity/count. - ptrdiff_t selected_task; // Will always be less than capacity/count. - int64_t modified_on; - int64_t total_times[NUM_WEEK_DAYS]; -} database_st; -*/ - -DatabaseX :: struct { - active_idx : s64; - selected_task : s64; - modified_on : s64; - total_times : [NUM_WEEK_DAYS] s64; - tasks : [] Task; -} - - - dd: DatabaseX; - - - - db : Database; - - // I'm having some troubles with the relative pointers: - // - array_add uses = to copy the pointers and I lose their values. - // - when printing the database after loading from file I'm getting a segmentation fault. - // also... the array_add - // TODO WIP - - load_database(*db, db_file_path); + + { // Try out the mapping file in linux. + //a, b := file_open(db_file_path); + //c, d := file_open(ar_file_path); + mfi, success := map_entire_file_start(ar_file_path); + print("Success is %\n", success); + print("MFI is %\n", mfi); + print("MFI.data.count is %\n", mfi.data.count); + print("MFI.data.data[1] is %\n", mfi.data.data[123]); + print("%\n", ifx success then "success" else "fail"); + print("--------------------------------------\n"); -// task : Task; -// memcpy(task.name.data, "bazinga".data, 7); -// task.name.count = 7; -// { -// path := join(app_directory, "/", "test"); -// file := file_open(path, for_writing = true); -// file_write(*file, *task, size_of(Task)); -// file_close(*file); -// -// data: Task; -// file = file_open(path); -// file_read(file, *data, size_of(Task)); -// print("### > %\n", data); -// } -// array_add(*db.tasks, task); -// store_database(db, db_file_path); + print(">>>%\n", mfi.map_info.file.handle.unknown_pre[111]); + print("###%\n", mfi.map_info.file.handle._file); + //file_h := c.handle; + //for file_h.cena + //if it == 4 { + //data := file_h.cena.data; + //print("HERE[%] = %\n", it_index-4, data[it-4]); + //print("HERE[%] = %\n", it_index-3, data[it-3]); + //print("HERE[%] = %\n", it_index-2, data[it-2]); + //print("HERE[%] = %\n", it_index-1, data[it-1]); + //print("HERE[%] = %\n", it_index, it); + //print("HERE[%] = %\n", it_index+1, data[it+1]); + //print("HERE[%] = %\n", it_index+2, data[it+2]); + //print("HERE[%] = %\n", it_index+3, data[it+3]); + //print("HERE[%] = %\n", it_index+4, data[it+4]); + //} + //print("%\n", <<mfi.map_info.file.handle); + return; + } + + + + db : Database; + { -// print("size_of([..]) = %\n", size_of([..] Task)); - //print("www\n"); - print("loaded: %\n", db); -// print(">>>'%'\n", task.name); -// print("###%\n\n", task); -// print(":%\n", size_of(type_of(db.tasks))); + import_from_csv(*db, ar_file_path); + + for db.tasks print_task(it); - array_add :: (array: *[..] $T/Task, item: T) #no_abc { - print("my_array\n"); - maybe_grow(array); -// array.data[array.count] = item; - memcpy(*array.data[array.count], *item, size_of(T)); - array.count += 1; + print_task :: (task: Task) { + for task.times print("% |", it); + print(" %\n", cast(string)task.name); } - add_task :: (db: *Database, task: *Task) { - idx := db.tasks.count; - maybe_grow(*db.tasks); - db.tasks.count += 1; - memcpy(*db.tasks[idx], task, size_of(Task)); - } // Stores data from database into binary file. // Returns success. @@ -1326,16 +1312,14 @@ DatabaseX :: struct { 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(DatabaseCore)); - file_write(*file, *db.tasks.count, size_of(type_of(Database.tasks.count))); - file_write(*file, db.tasks.data, size_of(Task) * db.tasks.count); + 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); - file_close(*file); return true; } @@ -1351,6 +1335,7 @@ DatabaseX :: struct { 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; @@ -1363,15 +1348,18 @@ DatabaseX :: struct { } // Read database structure. - read_success = file_read(file, db, size_of(DatabaseCore)); - tasks_count: s64; - file_read(file, *tasks_count, size_of(type_of(Database.tasks.count))); - array_resize(*db.tasks, tasks_count, initialize = false); - file_read(file, db.tasks.data, size_of(Task) * tasks_count); + + 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. /* |
