aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordam <dam@gudinoff>2023-02-26 18:24:30 +0000
committerdam <dam@gudinoff>2023-02-26 18:24:30 +0000
commitffbcc2d1556dcd55f53abb320c5be72951506f9f (patch)
tree4355678b8062c2376da8828b92f49c306e378a90
parentb75c965d3d2bb4bd9059d0df0366cd54f76825ff (diff)
downloadtask-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.jai107
-rw-r--r--ttt.jai274
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) {
diff --git a/ttt.jai b/ttt.jai
index e69132e..9592d5b 100644
--- a/ttt.jai
+++ b/ttt.jai
@@ -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.
/*