Add all core functions for minion module
This commit is contained in:
+182
-41
@@ -18,6 +18,7 @@
|
||||
#include <uuid.h>
|
||||
#include <errno.h>
|
||||
#include <cStuff/string.h>
|
||||
#include <cStuff/file.h>
|
||||
#include <components/log.h>
|
||||
#include "todo.h"
|
||||
|
||||
@@ -25,19 +26,12 @@
|
||||
AislStatus
|
||||
ax_todo_init(AxTodo self, const char *file)
|
||||
{
|
||||
FILE *f;
|
||||
uuid_generate(self->id);
|
||||
uuid_generate(self->list_id);
|
||||
|
||||
if (!(f = fopen(file, "a+"))) {
|
||||
return AISL_SYSCALL_ERROR;
|
||||
}
|
||||
self->file = file;
|
||||
|
||||
if (cstuff_list_init(&self->list, 16) != CSTUFF_SUCCESS) {
|
||||
fclose(f);
|
||||
if (cstuff_sprintf(&self->swap, "%s.swap", file) == -1)
|
||||
return AISL_MALLOC_ERROR;
|
||||
}
|
||||
|
||||
self->fd = f;
|
||||
|
||||
return AISL_SUCCESS;
|
||||
}
|
||||
@@ -46,32 +40,126 @@ ax_todo_init(AxTodo self, const char *file)
|
||||
void
|
||||
ax_todo_release(AxTodo self)
|
||||
{
|
||||
if (self->fd)
|
||||
fclose(self->fd);
|
||||
if (self->swap)
|
||||
free(self->swap);
|
||||
}
|
||||
|
||||
cstuff_list_release(&self->list, (CStuffListFree)ax_todo_task_free);
|
||||
|
||||
static AislStatus
|
||||
ax_todo_add_project(CStuffList list, time_t completed, char *key, size_t k_len)
|
||||
{
|
||||
int i;
|
||||
AxTodoProject proj;
|
||||
|
||||
for (i = 0; i < list->length; i++) {
|
||||
proj = list->items[i];
|
||||
|
||||
if (strncmp(proj->name, key, k_len) == 0 && !proj->name[k_len]) {
|
||||
proj->ref_count++;
|
||||
|
||||
if (proj->last_completed < completed) {
|
||||
proj->last_completed = completed;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(proj = calloc(1, sizeof (*proj))))
|
||||
return false;
|
||||
|
||||
if (cstuff_strncpy(&proj->name, key, k_len) != -1) {
|
||||
proj->ref_count = 1;
|
||||
proj->last_completed = completed;
|
||||
uuid_generate(proj->project_id);
|
||||
if (cstuff_list_append(list, proj) != -1)
|
||||
return true;
|
||||
}
|
||||
|
||||
ax_todo_project_free(proj);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static AislStatus
|
||||
ax_todo_add_tag(CStuffList list, char *key, size_t k_len)
|
||||
{
|
||||
int i;
|
||||
AxTodoTag tag;
|
||||
|
||||
for (i = 0; i < list->length; i++) {
|
||||
tag = list->items[i];
|
||||
|
||||
if (strncmp(tag->name, key, k_len) == 0 && !tag->name[k_len]) {
|
||||
tag->ref_count++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(tag = calloc(1, sizeof (*tag))))
|
||||
return false;
|
||||
|
||||
if (cstuff_strncpy(&tag->name, key, k_len) != -1) {
|
||||
tag->ref_count = 1;
|
||||
uuid_generate(tag->tag_id);
|
||||
if (cstuff_list_append(list, tag) != -1)
|
||||
return true;
|
||||
}
|
||||
|
||||
ax_todo_tag_free(tag);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static AislStatus
|
||||
ax_todo_read_keys(AxTodoTask task, CStuffList projs, CStuffList tags)
|
||||
{
|
||||
const char tokens[] = "+@";
|
||||
char *s = task->description;
|
||||
size_t offset = 0;
|
||||
|
||||
for (;;) {
|
||||
char t;
|
||||
offset = strcspn(s, tokens);
|
||||
|
||||
s += offset;
|
||||
|
||||
if ((t = *(s++)) == 0)
|
||||
break;
|
||||
|
||||
offset = strcspn(s, " ");
|
||||
|
||||
if (offset) {
|
||||
if ((t == '+' && !ax_todo_add_project(projs, task->completed, s, offset))
|
||||
|| (t == '@' && !ax_todo_add_tag(tags, s, offset))) {
|
||||
return AISL_MALLOC_ERROR;
|
||||
}
|
||||
s += offset;
|
||||
}
|
||||
}
|
||||
|
||||
return AISL_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
AislStatus
|
||||
ax_todo_read(AxTodo self)
|
||||
ax_todo_read(AxTodo self, CStuffList tasks, CStuffList projs, CStuffList tags)
|
||||
{
|
||||
FILE *f = self->fd;
|
||||
FILE *f = NULL;
|
||||
size_t sz = 256;
|
||||
char *buf;
|
||||
ssize_t rs;
|
||||
AislStatus result = AISL_SUCCESS;
|
||||
|
||||
if ((fseek(f, 0L, SEEK_SET) != 0))
|
||||
return AISL_SYSCALL_ERROR;
|
||||
|
||||
if (!(buf = malloc(sz)))
|
||||
return AISL_MALLOC_ERROR;
|
||||
|
||||
if (!(f = fopen(self->file, "r")))
|
||||
goto e_syscall;
|
||||
|
||||
while ((rs = getdelim(&buf, &sz, '\n', f)) != -1) {
|
||||
AxTodoTask task;
|
||||
|
||||
if (!(task = ax_todo_task_new()))
|
||||
if (!(task = ax_todo_task_new(self->list_id)))
|
||||
goto e_malloc;
|
||||
|
||||
if (ax_todo_task_set(task, buf, rs) != 0) {
|
||||
@@ -79,10 +167,14 @@ ax_todo_read(AxTodo self)
|
||||
goto e_input;
|
||||
}
|
||||
|
||||
if (cstuff_list_append(&self->list, task) == -1) {
|
||||
if (cstuff_list_append(tasks, task) == -1) {
|
||||
ax_todo_task_free(task);
|
||||
goto e_malloc;
|
||||
}
|
||||
|
||||
if ((result = ax_todo_read_keys(task, projs, tags)) != AISL_SUCCESS) {
|
||||
goto e_malloc;
|
||||
}
|
||||
}
|
||||
|
||||
switch(errno) {
|
||||
@@ -109,6 +201,8 @@ e_syscall:
|
||||
|
||||
finally:
|
||||
free(buf);
|
||||
if (f)
|
||||
fclose(f);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -124,52 +218,60 @@ ax_todo__write_dt(FILE *f, time_t dt)
|
||||
|
||||
|
||||
AislStatus
|
||||
ax_todo_write(AxTodo self)
|
||||
ax_todo_write(AxTodo self, CStuffList list)
|
||||
{
|
||||
FILE *f = self->fd;
|
||||
FILE *f;
|
||||
int i;
|
||||
|
||||
if ((fseek(f, 0L, SEEK_SET) != 0))
|
||||
if (!(f = fopen(self->swap, "w")))
|
||||
return AISL_SYSCALL_ERROR;
|
||||
|
||||
f = self->fd;
|
||||
for (i = 0; i < list->length; i++) {
|
||||
AxTodoTask task = (AxTodoTask) list->items[i];
|
||||
|
||||
for (i = 0; i < self->list.length; i++) {
|
||||
AxTodoTask task = (AxTodoTask) self->list.items[i];
|
||||
if (uuid_compare(task->list_id, self->list_id) != 0)
|
||||
continue;
|
||||
|
||||
if (task->is_done) {
|
||||
fwrite("x ", 1, 2, f);
|
||||
}
|
||||
|
||||
if (task->priority) {
|
||||
if (task->priority && task->priority != AX_TODO_ZERO_PRIORITY) {
|
||||
fprintf(f, "(%c) ", task->priority);
|
||||
}
|
||||
|
||||
if (task->is_done) {
|
||||
if (task->completion) {
|
||||
ax_todo__write_dt(f, task->completion);
|
||||
if (task->creation) {
|
||||
ax_todo__write_dt(f, task->creation);
|
||||
if (task->completed) {
|
||||
ax_todo__write_dt(f, task->completed);
|
||||
if (task->created) {
|
||||
ax_todo__write_dt(f, task->created);
|
||||
}
|
||||
}
|
||||
} else if (task->creation) {
|
||||
ax_todo__write_dt(f, task->creation);
|
||||
} else if (task->created) {
|
||||
ax_todo__write_dt(f, task->created);
|
||||
}
|
||||
|
||||
fprintf(f, "%s\n", task->description);
|
||||
}
|
||||
|
||||
return (fflush(f) == 0) ? AISL_SUCCESS : AISL_SYSCALL_ERROR;
|
||||
fclose(f);
|
||||
|
||||
if (cstuff_file_move(self->swap, self->file) != 0)
|
||||
return AISL_SYSCALL_ERROR;
|
||||
|
||||
return AISL_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
AxTodoTask
|
||||
ax_todo_task_new(void)
|
||||
ax_todo_task_new(uuid_t list_id)
|
||||
{
|
||||
AxTodoTask result;
|
||||
|
||||
if ((result = calloc(1, sizeof (struct ax_todo_task))) != NULL) {
|
||||
if ((result = calloc(1, sizeof (*result))) != NULL) {
|
||||
uuid_copy(result->list_id, list_id);
|
||||
uuid_generate(result->task_id);
|
||||
result->priority = AX_TODO_ZERO_PRIORITY;
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -220,7 +322,7 @@ ax_todo__get_priority(char *buf, char *p_priority)
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
int
|
||||
ax_todo__get_dt(char *buf, time_t *p_dt)
|
||||
{
|
||||
struct tm stm = {0};
|
||||
@@ -228,6 +330,8 @@ ax_todo__get_dt(char *buf, time_t *p_dt)
|
||||
const char fmt[] = "Y-M-DTH:m:s.uZB:b ", *f = fmt;
|
||||
char *ptr = NULL;
|
||||
|
||||
setenv("TZ", "UTC", 1);
|
||||
|
||||
for (result = 0; *f != 0; result++, f++) {
|
||||
switch(*f) {
|
||||
case 'Y':
|
||||
@@ -329,7 +433,6 @@ ax_todo__get_dt(char *buf, time_t *p_dt)
|
||||
stm.tm_min += (b_min * z_bias);
|
||||
}
|
||||
|
||||
setenv("TZ", "UTC", 1);
|
||||
*p_dt = mktime(&stm);
|
||||
unsetenv("TZ");
|
||||
|
||||
@@ -337,12 +440,33 @@ ax_todo__get_dt(char *buf, time_t *p_dt)
|
||||
}
|
||||
|
||||
e_input:
|
||||
AX_LOG_DEBUG("Parse error: %c(%d) at %d", *f, (int) (f - fmt), result);
|
||||
/* AX_LOG_DEBUG("Parse error: %c(%d) at %d", *f, (int) (f - fmt), result); */
|
||||
return 0;
|
||||
(void) usec;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ax_todo__remove_line_break(char *description)
|
||||
{
|
||||
int move = 0;
|
||||
char c;
|
||||
|
||||
do {
|
||||
c = *description;
|
||||
|
||||
if (c == '\r' || c == '\n') {
|
||||
move++;
|
||||
continue;
|
||||
}
|
||||
|
||||
*(description - move) = c;
|
||||
|
||||
} while (c != '\0');
|
||||
}
|
||||
|
||||
|
||||
AislStatus
|
||||
ax_todo_task_set(AxTodoTask task, char *buf, ssize_t length)
|
||||
{
|
||||
@@ -362,11 +486,11 @@ ax_todo_task_set(AxTodoTask task, char *buf, ssize_t length)
|
||||
buf += l;
|
||||
}
|
||||
|
||||
l = ax_todo__get_dt(buf, (is_done) ? &task->completion : &task->creation);
|
||||
l = ax_todo__get_dt(buf, (is_done) ? &task->completed : &task->created);
|
||||
|
||||
if (l != 0) {
|
||||
buf += l;
|
||||
if (is_done && (l = ax_todo__get_dt(buf, &task->creation)) != 0) {
|
||||
if (is_done && (l = ax_todo__get_dt(buf, &task->created)) != 0) {
|
||||
buf += l;
|
||||
}
|
||||
}
|
||||
@@ -381,3 +505,20 @@ ax_todo_task_set(AxTodoTask task, char *buf, ssize_t length)
|
||||
return AISL_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ax_todo_project_free(AxTodoProject project)
|
||||
{
|
||||
if (project->name)
|
||||
free(project->name);
|
||||
free(project);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ax_todo_tag_free(AxTodoTag tag)
|
||||
{
|
||||
if (tag->name)
|
||||
free(tag->name);
|
||||
free(tag);
|
||||
}
|
||||
|
||||
+47
-10
@@ -22,28 +22,49 @@
|
||||
#include <aisl/aisl.h>
|
||||
#include <cStuff/list.h>
|
||||
|
||||
#define AX_TODO_ZERO_PRIORITY '_'
|
||||
|
||||
struct ax_todo {
|
||||
uuid_t id;
|
||||
FILE *fd;
|
||||
struct cstuff_list list;
|
||||
uuid_t list_id;
|
||||
const char *file;
|
||||
char *swap;
|
||||
/* todo: add file timestamp */
|
||||
};
|
||||
|
||||
typedef struct ax_todo * AxTodo;
|
||||
|
||||
|
||||
struct ax_todo_task {
|
||||
uuid_t list_id;
|
||||
uuid_t task_id;
|
||||
char priority;
|
||||
time_t completion;
|
||||
time_t creation;
|
||||
time_t completed;
|
||||
time_t created;
|
||||
char *description;
|
||||
bool is_done;
|
||||
bool is_done;
|
||||
char priority;
|
||||
};
|
||||
|
||||
typedef struct ax_todo_task * AxTodoTask;
|
||||
|
||||
|
||||
struct ax_todo_project {
|
||||
uuid_t project_id;
|
||||
time_t last_completed;
|
||||
char *name;
|
||||
uint32_t ref_count;
|
||||
};
|
||||
|
||||
typedef struct ax_todo_project * AxTodoProject;
|
||||
|
||||
|
||||
struct ax_todo_tag {
|
||||
uuid_t tag_id;
|
||||
char *name;
|
||||
uint32_t ref_count;
|
||||
};
|
||||
|
||||
typedef struct ax_todo_tag * AxTodoTag;
|
||||
|
||||
AislStatus
|
||||
ax_todo_init(AxTodo self, const char *file);
|
||||
|
||||
@@ -53,15 +74,15 @@ ax_todo_release(AxTodo self);
|
||||
|
||||
|
||||
AislStatus
|
||||
ax_todo_read(AxTodo self);
|
||||
ax_todo_read(AxTodo self, CStuffList tasks, CStuffList projs, CStuffList tags);
|
||||
|
||||
|
||||
AislStatus
|
||||
ax_todo_write(AxTodo self);
|
||||
ax_todo_write(AxTodo self, CStuffList list);
|
||||
|
||||
|
||||
AxTodoTask
|
||||
ax_todo_task_new(void);
|
||||
ax_todo_task_new(uuid_t list_id);
|
||||
|
||||
|
||||
void
|
||||
@@ -72,8 +93,24 @@ void
|
||||
ax_todo_task_free(AxTodoTask task);
|
||||
|
||||
|
||||
int
|
||||
ax_todo__get_dt(char *buf, time_t *p_dt);
|
||||
|
||||
|
||||
void
|
||||
ax_todo__remove_line_break(char *description);
|
||||
|
||||
|
||||
AislStatus
|
||||
ax_todo_task_set(AxTodoTask task, char *buf, ssize_t length);
|
||||
|
||||
|
||||
void
|
||||
ax_todo_project_free(AxTodoProject project);
|
||||
|
||||
|
||||
void
|
||||
ax_todo_tag_free(AxTodoTag tag);
|
||||
|
||||
|
||||
#endif /* !TODO_H */
|
||||
|
||||
Reference in New Issue
Block a user