aboutsummaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c200
1 files changed, 98 insertions, 102 deletions
diff --git a/main.c b/main.c
index 05719c1..19b9d23 100644
--- a/main.c
+++ b/main.c
@@ -1,6 +1,6 @@
// Compilation command:
// - release: gcc main.c -Wall -O2 -m64 -lncurses -o ttt
-// - debug : gcc main.c -Wall -g3 -m64 -lncurses -o ttt
+// - debug : gcc main.c -Wall -g3 -m64 -lncurses -o ttt -D DEBUG
#include <assert.h>
@@ -16,7 +16,7 @@
#define STR_(X) #X // Convert to string.
#define STR(X) STR_(X) // Force argument expansions before converting to string.
-#define MAX_TASK_NAME 127
+#define MAX_TASK_NAME 64
#define FIRST_DAY_OF_WEEK 1 // (0-6, Sunday = 0)
#define LOG_FILE_NAME "log.txt"
@@ -24,16 +24,13 @@
#define DB_CSV_PATH_NAME "./database.csv"
-
-
-typedef struct {
- char name[MAX_TASK_NAME+1]; // Allow space for null termination char.
- uint32_t time[7];
+typedef /*struct __attribute__((__packed__))*/ struct {
+ char name[MAX_TASK_NAME];
uint64_t modified_on;
+ uint32_t time[7];
uint8_t state;
} task_t;
-
const char* DB_BIN_FILE_SIGNATURE = "TTBF:1.0";
const uint8_t DB_BIN_FILE_SIGNATURE_SIZE = sizeof(DB_BIN_FILE_SIGNATURE);
const size_t SIZEOF_TASK_T = sizeof(task_t);
@@ -47,14 +44,13 @@ uint32_t selected_task = -1;
// Given an UTF8 encoded string, truncate it to length without breaking any UTF8 character.
-// The string should have, at least length number of items.
+// The string should have capacity for at least length number of items.
// The terminating null byte ('\0') is included in length.
// The function returns the amount of items that got discarded counting from length.
size_t truncate_string_utf8(char* string, size_t length) {
// Check for special cases where no truncation is required.
- if (length == 0 || string[length] == '\0') {
- string[length] = '\0';
+ if (length == 0 || string[length-1] == '\0') {
return 0;
}
@@ -64,16 +60,6 @@ size_t truncate_string_utf8(char* string, size_t length) {
idx--;
}
string[idx] = '\0';
-
-#if DEBUG
- // Check if there is a null byte before the place where we terminated the string.
- size_t idx_dbg = idx;
- while (idx_dbg > 0) {
- assert(string[idx_dbg-1] != '\0');
- idx_dbg--;
- }
-#endif
-
return length - idx;
}
@@ -205,21 +191,49 @@ uint32_t import_database(task_t** database, const char* path_name) {
FILE* file = fopen(path_name, "r");
if (file == NULL) {
- fprintf(stderr, "Failed to open database file '%s': %s.\n", path_name, strerror(errno)); // TODO Fix message.
+ fprintf(stderr, "Failed to open file '%s' while importing database: %s.\n", path_name, strerror(errno));
return 0;
}
uint32_t number_of_entries = 0;
uint32_t capacity = 0;
task_t task;
- int error;
+ task_t* database_reallocation = NULL;
+ char *line_buffer = NULL;
+ size_t line_buffer_size = 0;
+ ssize_t read_characters = 0;
+ char* name_delimiter;
+
+ // Skip header line.
+ fscanf(file, "%*[^\n]\n");
- fscanf(file, "%*[^\n]\n"); // Skip header line.
- scan_csv: {
+ // Parse CSV file.
+ while(true) {
+
+ read_characters = getline(&line_buffer, &line_buffer_size, file);
+
+ // Check if reached EOF.
+ if (read_characters == -1) {
+ break;
+ }
+
+ // Clear task struct.
+ memset(&task, '\0', SIZEOF_TASK_T);
+
+ // Find task name string limits.
+ name_delimiter = strchr(line_buffer, ',');
+ size_t name_length = (name_delimiter - line_buffer) + 1;
+ if (name_length > MAX_TASK_NAME) {
+ name_length = MAX_TASK_NAME;
+ }
- error = fscanf(file,
- "%" STR(MAX_TASK_NAME) "[^,],%" SCNu32 ",%" SCNu32 ",%" SCNu32 ",%" SCNu32 ",%" SCNu32 ",%" SCNu32 ",%" SCNu32 "\n",
- task.name,
+ // Import task name.
+ memcpy(task.name, line_buffer, name_length);
+ truncate_string_utf8(task.name, name_length);
+
+ // Parse task times.
+ if(sscanf(name_delimiter+1,
+ "%" SCNu32 ",%" SCNu32 ",%" SCNu32 ",%" SCNu32 ",%" SCNu32 ",%" SCNu32 ",%" SCNu32,
&task.time[0],
&task.time[1],
&task.time[2],
@@ -227,51 +241,47 @@ uint32_t import_database(task_t** database, const char* path_name) {
&task.time[4],
&task.time[5],
&task.time[6]
- );
+ ) != 7) {
+ replace_char(line_buffer, '\n', ' ');
+// fprintf(stderr, "Discarding invalid line '%s' and continuing.\n", line_buffer);
+ continue;
+ }
- if (error != EOF)
- {
- number_of_entries++;
-
- // Expand tasks capacity if required.
- if (number_of_entries > capacity) {
- capacity = capacity == 0 ? 16 : capacity << 1;
- *database = realloc(*database, capacity * SIZEOF_TASK_T);
- if (errno != 0 || errno == ENOMEM) {
- ; // TODO realloc failed
- }
+ // Expand database capacity when required.
+ number_of_entries++;
+ if (number_of_entries > capacity) {
+ capacity = capacity == 0 ? 16 : capacity << 1;
+ database_reallocation = realloc(*database, capacity * SIZEOF_TASK_T);
+ if (database_reallocation == NULL) {
+ fprintf(stderr, "Failed to allocate memory while importing database.\n");
+ number_of_entries--;
+ break;
}
- memcpy(&((*database)[number_of_entries-1]), &task, SIZEOF_TASK_T);
-
- goto scan_csv;
+ *database = database_reallocation;
}
+
+ memcpy(&((*database)[number_of_entries-1]), &task, SIZEOF_TASK_T);
}
- assert(number_of_entries == 3);
- *database = realloc(*database, number_of_entries * SIZEOF_TASK_T);
- // TODO check for allocation errors.
-// if (error != EOF) {
-// fprintf(stderr, "Failed to parse database file: %s.\n", strerror(errno));
-// }
-
-
fclose(file);
+ free(line_buffer);
- return number_of_entries;
-}
-
-
-void prt(char* str, uint8_t size) { // TODO Debug function... to be removed.
- fprintf(stderr, ">");
- for (uint8_t idx = 0; idx < size; idx++) {
- if (idx % 2 == 0) {
- fprintf(stderr, " ");
+ // Trim any excess memory allocated for database.
+ if (capacity > number_of_entries) {
+// *database = realloc(*database, number_of_entries * SIZEOF_TASK_T); // TODO dangerous stuff going on here.
+ database_reallocation = realloc(*database, number_of_entries * SIZEOF_TASK_T);
+ if (database_reallocation == NULL) {
+ fprintf(stderr, "Failed to allocate memory while importing database.\n");
+ }
+ else {
+ *database = database_reallocation;
}
- fprintf(stderr, "%02x", str[idx]);
}
- fprintf(stderr, "\n");
+
+ return number_of_entries;
}
+
enum TEST {
T_NONE = 0x00,
T_UTC = 0x01,
@@ -280,51 +290,12 @@ enum TEST {
T_LBIN = 0x08,
T_ECSV = 0x10,
T_ICSV = 0x20,
+ T_TTS = 0x40,
T_ALL = 0xFF,
};
void prototype(int level) {
- /*
- uint8_t size = 20;
- char* test_string;
- // C3 A7 - C3 A9 - C2 BA - 2C - F0 92 90 AB
- const char* DUMMY = "çéº,,,𒐫";
- test_string = calloc(size, sizeof(char));
- sprintf(test_string, "%s", DUMMY);
-
- fprintf(stderr, "%s\n", test_string);
- prt(test_string, size);
-
- // C3 A7 - C3 A9 - C2 BA - 2E - F0 92 90 AB
- replace_char(test_string, ',', ',');
- fprintf(stderr, "%s\n", test_string);
- prt(test_string, size);
-
-// test_string[10] = '\0';
-// prt(test_string, size);
-// test_string[1] = '\0';
-
-// uint8_t trunc = truncate_string_utf8(test_string, 3);
-// fprintf(stderr, "%d:%s\n", trunc, test_string);
-// prt(test_string, size);
-
- return;
-
- FILE* file = fopen("./test.txt", "w");
-
- uint8_t length = strlen(test_string);
- fwrite(test_string, sizeof(uint8_t), length, file);
-
-// fwrite(test_string, sizeof(uint8_t), size, file);
-
- fclose(file);
-// truncate_string(test_string, 8);
-// fprintf(stderr, "%s", (char*)test_string);
- return;
- */
-
-
const char* done = "# -- done -- -- -- /\n";
///////////////////////////////////////////////////////////////////////////
@@ -416,6 +387,15 @@ void prototype(int level) {
}
///////////////////////////////////////////////////////////////////////////
+ // Check task_t size
+ if (level & T_TTS) {
+ fprintf(stderr, "# check task_t size --------------------------- \\\n");
+ size_t tts = sizeof(task_t);
+ fprintf(stderr, "sizeof(super_t) = %zu bytes (%zu bits : %6.3f W64b)\n", tts, tts*8, ((double)tts)*8.0/64.0);
+ fprintf(stderr, done);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
// Release memory and exit.
// free(tasks);
@@ -605,6 +585,8 @@ void destroy_win(WINDOW *local_win);
int main(int argc, char *argv[]) {
initialization();
+
+
// TODO Parse commands using: https://stackoverflow.com/questions/9642732/parsing-command-line-arguments-in-c
if (argc > 1) {
// const char* command_version = { "--version", "-v" };
@@ -629,6 +611,20 @@ int main(int argc, char *argv[]) {
return EXIT_SUCCESS;
}
+ action = "--t_tts";
+ do_action = strncmp(argv[idx], action, strlen(action)) == 0;
+ if (do_action) {
+ prototype(T_TTS);
+ return EXIT_SUCCESS;
+ }
+
+ action = "--t_icsv";
+ do_action = strncmp(argv[idx], action, strlen(action)) == 0;
+ if (do_action) {
+ prototype(T_ICSV);
+ return EXIT_SUCCESS;
+ }
+
action = "--test";
do_action = strncmp(argv[idx], action, strlen(action)) == 0;
if (do_action) {