mirror of
https://github.com/michaeldv/pit.git
synced 2025-12-08 15:43:25 +00:00
Simpler data types; header and pit info; refactored options
This commit is contained in:
@@ -11,13 +11,13 @@ static void action_list()
|
||||
if (actions->number_of_records > 0) {
|
||||
ppager = pit_pager_initialize(PAGER_ACTION, actions->number_of_records);
|
||||
for_each_action(pa) {
|
||||
pit_pager_print(ppager, (uchar *)pa);
|
||||
pit_pager_print(ppager, (char *)pa);
|
||||
}
|
||||
pit_pager_flush(ppager);
|
||||
}
|
||||
}
|
||||
|
||||
void pit_action(ulong id, char *subject, char *message)
|
||||
void pit_action(int id, char *subject, char *message)
|
||||
{
|
||||
static Action action;
|
||||
|
||||
@@ -28,7 +28,7 @@ void pit_action(ulong id, char *subject, char *message)
|
||||
strncpy(action.username, current_user(), sizeof(action.username) - 1);
|
||||
strncpy(action.message, message, sizeof(action.message) - 1);
|
||||
|
||||
pit_table_insert(actions, (uchar *)&action);
|
||||
pit_table_insert(actions, (char *)&action);
|
||||
}
|
||||
|
||||
void pit_log(char *argv[])
|
||||
|
||||
@@ -28,9 +28,9 @@ char *pit_arg_string(char **arg, char *required)
|
||||
return *arg;
|
||||
}
|
||||
|
||||
ulong pit_arg_number(char **arg, char *required)
|
||||
int pit_arg_number(char **arg, char *required)
|
||||
{
|
||||
ulong number = 0L;
|
||||
int number = 0;
|
||||
|
||||
if (required && (!*arg || pit_arg_is_option(arg))) {
|
||||
die("missing %s", required);
|
||||
@@ -143,14 +143,15 @@ time_t pit_arg_date(char **arg, char *required)
|
||||
memset(&tm, 0, sizeof(tm));
|
||||
// printf("format: %s\n", format);
|
||||
if (strptime(*arg, format, &tm)) {
|
||||
printf("then: %s\n", asctime(&tm));
|
||||
// printf("then: %s\n", asctime(&tm));
|
||||
if (!tm.tm_mday) tm.tm_mday = ptm->tm_mday;
|
||||
if (!tm.tm_mon) tm.tm_mon = ptm->tm_mon;
|
||||
if (!tm.tm_year) tm.tm_year = ptm->tm_year;
|
||||
|
||||
tm.tm_isdst = -1;
|
||||
// printf(" now: %s\n", asctime(ptm));
|
||||
// printf(" adj: %s\n", asctime(&tm));
|
||||
seconds = mktime(&tm);
|
||||
// printf("ctime: %s", ctime(&seconds));
|
||||
if (seconds == (time_t)-1) {
|
||||
perish("invalid date");
|
||||
}
|
||||
|
||||
73
src/db.c
73
src/db.c
@@ -19,31 +19,41 @@ static char *pit_file_name()
|
||||
return file_name;
|
||||
}
|
||||
|
||||
static void read_header(FILE *file)
|
||||
static bool read_and_validate_header(FILE *file)
|
||||
{
|
||||
Header hd;
|
||||
header = (PHeader)calloc(1, sizeof(Header));
|
||||
|
||||
if (fread(&hd, sizeof(hd), 1, file)) {
|
||||
if (hd.signature[0] != 0x50 || hd.signature[1] != 0x49 || hd.signature[2] != 0x54) {
|
||||
die("invalid pit file");
|
||||
if (fread(header, sizeof(Header), 1, file)) {
|
||||
if (header->signature[0] != 0x50 || header->signature[1] != 0x49 || header->signature[2] != 0x54) {
|
||||
printf("pit: invalid pit file (%s)\n", pit_file_name());
|
||||
return FALSE;
|
||||
}
|
||||
if (hd.schema_version != 0x01) {
|
||||
die("invalid pit file version");
|
||||
if (header->schema_version != PIT_SCHEMA_VERSION) {
|
||||
printf("pit: invalid pit file version (%d)\n", header->schema_version);
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
die("couldn't read header");
|
||||
puts("pit: error reading pit file header");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void write_header(FILE *file)
|
||||
{
|
||||
Header hd;
|
||||
if (!header) header = (PHeader)calloc(1, sizeof(Header));
|
||||
|
||||
hd.signature[0] = 0x50; hd.signature[1] = 0x49; hd.signature[2] = 0x54;
|
||||
hd.schema_version = 0x01;
|
||||
memset(&hd.reserved, 0, sizeof(hd.reserved));
|
||||
header->signature[0] = 0x50; header->signature[1] = 0x49; header->signature[2] = 0x54;
|
||||
header->schema_version = PIT_SCHEMA_VERSION;
|
||||
if (!header->created_at) {
|
||||
header->created_at = time(NULL);
|
||||
strncpy(header->created_by, current_user(), sizeof(header->created_by) - 1);
|
||||
}
|
||||
header->updated_at = time(NULL);
|
||||
strncpy(header->updated_by, current_user(), sizeof(header->updated_by) - 1);
|
||||
|
||||
if (!fwrite(&hd, sizeof(hd), 1, file)) {
|
||||
if (!fwrite(header, sizeof(Header), 1, file)) {
|
||||
die("couldn't write header");
|
||||
}
|
||||
}
|
||||
@@ -66,6 +76,19 @@ void pit_init(char *argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
void pit_info(char *argv[])
|
||||
{
|
||||
pit_db_load();
|
||||
printf("Pit file name: %s\n", pit_file_name());
|
||||
printf("Created by: %s on %s", header->created_by, ctime(&header->created_at));
|
||||
printf("Last updated by: %s on %s", header->updated_by, ctime(&header->updated_at));
|
||||
printf("Schema version: %d\n", header->schema_version);
|
||||
printf("Projects: %d\n", projects->number_of_records);
|
||||
printf("Tasks: %d\n", tasks->number_of_records);
|
||||
printf("Notes: %d\n", notes->number_of_records);
|
||||
printf("Log entries: %d\n", actions->number_of_records);
|
||||
}
|
||||
|
||||
void pit_db_load() {
|
||||
char *file_name = pit_file_name();
|
||||
FILE *file = fopen(file_name, "r");
|
||||
@@ -73,20 +96,24 @@ void pit_db_load() {
|
||||
if (!file) {
|
||||
perish(file_name);
|
||||
} else {
|
||||
read_header(file);
|
||||
projects = pit_table_load(file);
|
||||
tasks = pit_table_load(file);
|
||||
notes = pit_table_load(file);
|
||||
actions = pit_table_load(file);
|
||||
fclose(file);
|
||||
if (read_and_validate_header(file)) {
|
||||
projects = pit_table_load(file);
|
||||
tasks = pit_table_load(file);
|
||||
notes = pit_table_load(file);
|
||||
actions = pit_table_load(file);
|
||||
fclose(file);
|
||||
} else {
|
||||
fclose(file);
|
||||
die(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pit_db_initialize() {
|
||||
projects = pit_table_initialize(sizeof(Project), TABLE_HAS_ID | TABLE_HAS_TIMESTAMPS);
|
||||
tasks = pit_table_initialize(sizeof(Task), TABLE_HAS_ID | TABLE_HAS_TIMESTAMPS);
|
||||
notes = pit_table_initialize(sizeof(Note), TABLE_HAS_ID | TABLE_HAS_TIMESTAMPS);
|
||||
actions = pit_table_initialize(sizeof(Action), TABLE_HAS_CREATED_AT);
|
||||
projects = pit_table_initialize(sizeof(Project), TABLE_HAS_ID | TABLE_HAS_TIMESTAMPS);
|
||||
tasks = pit_table_initialize(sizeof(Task), TABLE_HAS_ID | TABLE_HAS_TIMESTAMPS);
|
||||
notes = pit_table_initialize(sizeof(Note), TABLE_HAS_ID | TABLE_HAS_TIMESTAMPS);
|
||||
actions = pit_table_initialize(sizeof(Action), TABLE_HAS_CREATED_AT);
|
||||
|
||||
pit_action(0, "pit", "Initialized pit");
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <stdio.h>
|
||||
#include "pit.h"
|
||||
|
||||
void pit_note_delete(ulong id, PTask pt)
|
||||
void pit_note_delete(int id, PTask pt)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
45
src/object.h
45
src/object.h
@@ -2,40 +2,43 @@
|
||||
#define __MODELS_H__
|
||||
|
||||
typedef struct _Header {
|
||||
char signature[3];
|
||||
char schema_version;
|
||||
char reserved[16];
|
||||
char signature[3];
|
||||
int schema_version;
|
||||
char created_by[32];
|
||||
char updated_by[32];
|
||||
time_t created_at;
|
||||
time_t updated_at;
|
||||
} Header, *PHeader;
|
||||
|
||||
typedef struct _Project {
|
||||
ulong id;
|
||||
int id;
|
||||
char username[32]; /* User the project belongs to. */
|
||||
char name[128]; /* Project name. */
|
||||
char status[16]; /* Project status. */
|
||||
ulong number_of_tasks; /* Number of tasks for the project. */
|
||||
ulong created_by; /* Who created the project? */
|
||||
ulong updated_by; /* Who last updated the project? */
|
||||
int number_of_tasks; /* Number of tasks for the project. */
|
||||
int created_by; /* Who created the project? */
|
||||
int updated_by; /* Who last updated the project? */
|
||||
time_t created_at; /* When the project was created? */
|
||||
time_t updated_at; /* When the project was last updated? */
|
||||
} Project, *PProject;
|
||||
|
||||
typedef struct _Task {
|
||||
ulong id;
|
||||
ulong project_id; /* Which project the task belongs to? */
|
||||
int id;
|
||||
int project_id; /* Which project the task belongs to? */
|
||||
char username[32]; /* User the task belongs to. */
|
||||
char name[128]; /* Task name. */
|
||||
char status[16]; /* Task status. */
|
||||
char priority[16]; /* Task priority. */
|
||||
time_t date; /* Generic date/time, ex: task deadline. */
|
||||
time_t time; /* Generic time, ex: time spent on the task. */
|
||||
ulong number_of_notes; /* Number of notes for the task. */
|
||||
int number_of_notes; /* Number of notes for the task. */
|
||||
time_t created_at; /* When the task was created? */
|
||||
time_t updated_at; /* When the task was last updated? */
|
||||
} Task, *PTask;
|
||||
|
||||
typedef struct _Note {
|
||||
ulong id;
|
||||
ulong task_id; /* Task the note belongs to. */
|
||||
int id;
|
||||
int task_id; /* Task the note belongs to. */
|
||||
char username[32]; /* User the note belongs to. */
|
||||
char message[255]; /* The body of the note. */
|
||||
time_t created_at; /* When the note was created? */
|
||||
@@ -43,11 +46,27 @@ typedef struct _Note {
|
||||
} Note, *PNote;
|
||||
|
||||
typedef struct _Action {
|
||||
ulong subject_id; /* Reference to the specific Project, Task, or Note. */
|
||||
int subject_id; /* Reference to the specific Project, Task, or Note. */
|
||||
char subject[16]; /* Project, Task, or Note. */
|
||||
char username[32]; /* Who added the log message? */
|
||||
char message[255]; /* Log message. */
|
||||
time_t created_at; /* When log message was added? */
|
||||
} Action, *PAction;
|
||||
|
||||
typedef union _Options {
|
||||
struct {
|
||||
int id;
|
||||
char *name;
|
||||
char *status;
|
||||
char *priority;
|
||||
time_t date;
|
||||
time_t time;
|
||||
} task;
|
||||
struct {
|
||||
int id;
|
||||
char *name;
|
||||
char *status;
|
||||
} project;
|
||||
} Options, *POptions;
|
||||
|
||||
#endif
|
||||
|
||||
40
src/pager.c
40
src/pager.c
@@ -3,14 +3,14 @@
|
||||
#include <stdio.h>
|
||||
#include "pit.h"
|
||||
|
||||
#define for_each_entry(ppager, entry) for (entry = (uchar **)ppager->entries; (uchar *)*entry; entry++)
|
||||
#define for_each_entry(ppager, entry) for (entry = (char **)ppager->entries; (char *)*entry; entry++)
|
||||
#define TASK(attr) (((PTask)*pentry)->attr)
|
||||
#define PROJECT(attr) (((PProject)*pentry)->attr)
|
||||
#define ACTION(attr) (((PAction)*pentry)->attr)
|
||||
|
||||
static void print_actions(PPager ppager)
|
||||
{
|
||||
uchar **pentry;
|
||||
char **pentry;
|
||||
char format[64];
|
||||
|
||||
sprintf(format, "%%s (%%-%ds): %%s\n", ppager->max.action.username);
|
||||
@@ -21,10 +21,10 @@ static void print_actions(PPager ppager)
|
||||
|
||||
static void print_projects(PPager ppager)
|
||||
{
|
||||
uchar **pentry;
|
||||
char **pentry;
|
||||
char format[64];
|
||||
|
||||
sprintf(format, "%%c %%%dlu: (%%-%ds) [%%-%ds] %%-%ds (%%lu task%%s)\n",
|
||||
sprintf(format, "%%c %%%dd: (%%-%ds) [%%-%ds] %%-%ds (%%d task%%s)\n",
|
||||
ppager->max.project.id, ppager->max.project.username, ppager->max.project.status, ppager->max.project.name
|
||||
);
|
||||
for_each_entry(ppager, pentry) {
|
||||
@@ -42,10 +42,10 @@ static void print_projects(PPager ppager)
|
||||
|
||||
static void print_tasks(PPager ppager)
|
||||
{
|
||||
uchar **pentry;
|
||||
char **pentry;
|
||||
char format[64];
|
||||
|
||||
sprintf(format, "%%c %%%dlu: (%%-%ds) [%%-%ds] [%%-%ds] %%-%ds (%%lu note%%s)\n",
|
||||
sprintf(format, "%%c %%%dd: (%%-%ds) [%%-%ds] [%%-%ds] %%-%ds (%%d note%%s)\n",
|
||||
ppager->max.task.id, ppager->max.task.username, ppager->max.task.status, ppager->max.task.priority, ppager->max.task.name
|
||||
);
|
||||
for_each_entry(ppager, pentry) {
|
||||
@@ -64,10 +64,10 @@ static void print_tasks(PPager ppager)
|
||||
|
||||
static void print_tasks_with_date(PPager ppager)
|
||||
{
|
||||
uchar **pentry;
|
||||
char **pentry;
|
||||
char format[64];
|
||||
|
||||
sprintf(format, "%%c %%%dlu: (%%-%ds) [%%-%ds] [%%-%ds] %%-%ds %%-%ds (%%lu note%%s)\n",
|
||||
sprintf(format, "%%c %%%dd: (%%-%ds) [%%-%ds] [%%-%ds] %%-%ds %%-%ds (%%d note%%s)\n",
|
||||
ppager->max.task.id, ppager->max.task.username, ppager->max.task.status, ppager->max.task.priority, ppager->max.task.date, ppager->max.task.name
|
||||
);
|
||||
for_each_entry(ppager, pentry) {
|
||||
@@ -87,10 +87,10 @@ static void print_tasks_with_date(PPager ppager)
|
||||
|
||||
static void print_tasks_with_time(PPager ppager)
|
||||
{
|
||||
uchar **pentry;
|
||||
char **pentry;
|
||||
char format[64];
|
||||
|
||||
sprintf(format, "%%c %%%dlu: (%%-%ds) %%-%ds %%-%ds %%%ds %%-%ds (%%lu note%%s)\n",
|
||||
sprintf(format, "%%c %%%dd: (%%-%ds) %%-%ds %%-%ds %%%ds %%-%ds (%%d note%%s)\n",
|
||||
ppager->max.task.id, ppager->max.task.username, ppager->max.task.status, ppager->max.task.priority, ppager->max.task.time, ppager->max.task.name
|
||||
);
|
||||
for_each_entry(ppager, pentry) {
|
||||
@@ -110,10 +110,10 @@ static void print_tasks_with_time(PPager ppager)
|
||||
|
||||
static void print_tasks_with_date_and_time(PPager ppager)
|
||||
{
|
||||
uchar **pentry;
|
||||
char **pentry;
|
||||
char format[64];
|
||||
|
||||
sprintf(format, "%%c %%%dlu: (%%-%ds) [%%-%ds] [%%-%ds] %%-%ds %%%ds %%-%ds (%%lu note%%s)\n",
|
||||
sprintf(format, "%%c %%%dd: (%%-%ds) [%%-%ds] [%%-%ds] %%-%ds %%%ds %%-%ds (%%d note%%s)\n",
|
||||
ppager->max.task.id, ppager->max.task.username, ppager->max.task.status, ppager->max.task.priority, ppager->max.task.date, ppager->max.task.time, ppager->max.task.name
|
||||
);
|
||||
for_each_entry(ppager, pentry) {
|
||||
@@ -132,28 +132,28 @@ static void print_tasks_with_date_and_time(PPager ppager)
|
||||
}
|
||||
}
|
||||
|
||||
PPager pit_pager_initialize(ulong type, ulong number_of_entries)
|
||||
PPager pit_pager_initialize(int type, int number_of_entries)
|
||||
{
|
||||
PPager ppager = calloc(1, sizeof(Pager));
|
||||
|
||||
memset(ppager, 0, sizeof(Pager));
|
||||
ppager->type = type;
|
||||
ppager->entries = calloc(number_of_entries + 1, sizeof(uchar *));
|
||||
ppager->entries = calloc(number_of_entries + 1, sizeof(char *));
|
||||
|
||||
return ppager;
|
||||
}
|
||||
|
||||
void pit_pager_print(PPager ppager, uchar *entry)
|
||||
void pit_pager_print(PPager ppager, char *entry)
|
||||
{
|
||||
char str[32];
|
||||
|
||||
uchar **pentry = (uchar **)ppager->entries + ppager->number_of_entries++;
|
||||
char **pentry = (char **)ppager->entries + ppager->number_of_entries++;
|
||||
*pentry = entry;
|
||||
|
||||
for_each_entry(ppager, pentry) {
|
||||
switch(ppager->type) {
|
||||
case PAGER_TASK:
|
||||
sprintf(str, "%lu", TASK(id));
|
||||
sprintf(str, "%d", TASK(id));
|
||||
ppager->max.task.id = max(ppager->max.task.id, strlen(str));
|
||||
ppager->max.task.username = max(ppager->max.task.username, strlen(TASK(username)));
|
||||
ppager->max.task.name = max(ppager->max.task.name, strlen(TASK(name)));
|
||||
@@ -167,7 +167,7 @@ void pit_pager_print(PPager ppager, uchar *entry)
|
||||
}
|
||||
break;
|
||||
case PAGER_PROJECT:
|
||||
sprintf(str, "%lu", ((PProject)*pentry)->id);
|
||||
sprintf(str, "%d", ((PProject)*pentry)->id);
|
||||
ppager->max.project.id = max(ppager->max.project.id, strlen(str));
|
||||
ppager->max.project.username = max(ppager->max.project.username, strlen(((PProject)*pentry)->username));
|
||||
ppager->max.project.name = max(ppager->max.project.name, strlen(((PProject)*pentry)->name));
|
||||
@@ -220,3 +220,7 @@ void pit_pager_free(PPager ppager)
|
||||
free(ppager->entries);
|
||||
free(ppager);
|
||||
}
|
||||
|
||||
#undef TASK
|
||||
#undef PROJECT
|
||||
#undef ACTION
|
||||
|
||||
10
src/pager.h
10
src/pager.h
@@ -7,9 +7,9 @@
|
||||
#define PAGER_NOTE 8
|
||||
|
||||
typedef struct _Pager {
|
||||
ulong type;
|
||||
ulong number_of_entries;
|
||||
uchar *entries;
|
||||
int type;
|
||||
int number_of_entries;
|
||||
char *entries;
|
||||
union {
|
||||
struct {
|
||||
int id;
|
||||
@@ -33,8 +33,8 @@ typedef struct _Pager {
|
||||
} max;
|
||||
} Pager, *PPager;
|
||||
|
||||
PPager pit_pager_initialize(ulong type, ulong number_of_entries);
|
||||
void pit_pager_print(PPager ppager, uchar *entry);
|
||||
PPager pit_pager_initialize(int type, int number_of_entries);
|
||||
void pit_pager_print(PPager ppager, char *entry);
|
||||
void pit_pager_flush(PPager ppager);
|
||||
void pit_pager_free(PPager ppager);
|
||||
|
||||
|
||||
60
src/pit.c
60
src/pit.c
@@ -4,10 +4,19 @@
|
||||
#include <stdio.h>
|
||||
#include "pit.h"
|
||||
|
||||
PTable projects;
|
||||
PTable tasks;
|
||||
PTable notes;
|
||||
PTable actions;
|
||||
PHeader header;
|
||||
PTable projects;
|
||||
PTable tasks;
|
||||
PTable notes;
|
||||
PTable actions;
|
||||
|
||||
void free_externals() {
|
||||
if (header) free(header);
|
||||
if (actions) pit_table_free(actions);
|
||||
if (notes) pit_table_free(notes);
|
||||
if (projects) pit_table_free(projects);
|
||||
if (tasks) pit_table_free(tasks);
|
||||
}
|
||||
|
||||
/*
|
||||
** Suicide.
|
||||
@@ -17,11 +26,14 @@ void die(char *message, ...)
|
||||
char str[4096];
|
||||
va_list params;
|
||||
|
||||
va_start(params, message);
|
||||
vsnprintf(str, sizeof(str), message, params);
|
||||
fprintf(stderr, "pit: %s\n", str);
|
||||
va_end(params);
|
||||
if (message) {
|
||||
va_start(params, message);
|
||||
vsnprintf(str, sizeof(str), message, params);
|
||||
fprintf(stderr, "pit: %s\n", str);
|
||||
va_end(params);
|
||||
}
|
||||
|
||||
free_externals();
|
||||
exit(0);
|
||||
}
|
||||
/*
|
||||
@@ -34,26 +46,36 @@ void perish(char *prefix)
|
||||
fprintf(stderr, "%s - ", prefix);
|
||||
}
|
||||
perror(NULL);
|
||||
|
||||
free_externals();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void pit_status(char *argv[])
|
||||
void pit_version(char *argv[])
|
||||
{
|
||||
puts("pit: status is not implemented yet");
|
||||
printf("pit version %s\n", PIT_VERSION);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
register int i;
|
||||
char *commands[] = { "project", "task", "note", "log", "init", "status", "help" };
|
||||
void (*handlers[])(char *argv[]) = { pit_project, pit_task, pit_note, pit_log, pit_init, pit_status, pit_help };
|
||||
register int i, candidate = -1;
|
||||
char *command[] = { "project", "task", "note", "log", "init", "info", "help", "version" };
|
||||
void (*handler[])(char *argv[]) = { pit_project, pit_task, pit_note, pit_log, pit_init, pit_info, pit_help, pit_version };
|
||||
|
||||
if (argc == 1) argv[1] = "help";
|
||||
for(i = 0; i < ARRAY_SIZE(commands); i++) {
|
||||
if (strstr(commands[i], argv[1]) == commands[i]) {
|
||||
handlers[i](&argv[1]);
|
||||
return 1;
|
||||
for(i = 0; i < ARRAY_SIZE(command); i++) {
|
||||
if (strstr(command[i], argv[1]) == command[i]) {
|
||||
if (candidate < 0) {
|
||||
candidate = i;
|
||||
} else {
|
||||
die("ambiguous command (%s)", argv[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("invalid command: %s", argv[1]);
|
||||
return 0;
|
||||
|
||||
if (candidate < 0)
|
||||
die("invalid command (%s), run 'pit help' for help", argv[1]);
|
||||
|
||||
handler[candidate](&argv[1]);
|
||||
free_externals();
|
||||
return 1;
|
||||
}
|
||||
|
||||
25
src/pit.h
25
src/pit.h
@@ -1,9 +1,8 @@
|
||||
#if !defined(__PIT_H__)
|
||||
#define __PIT_H__
|
||||
#define PIT_VERSION "0.1.0"
|
||||
#define PIT_SCHEMA_VERSION 1
|
||||
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned long ulong;
|
||||
typedef unsigned char uchar;
|
||||
typedef int bool;
|
||||
|
||||
#include <time.h>
|
||||
@@ -11,7 +10,6 @@ typedef int bool;
|
||||
#include "table.h"
|
||||
#include "pager.h"
|
||||
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
||||
|
||||
#ifndef FALSE
|
||||
@@ -36,13 +34,15 @@ typedef int bool;
|
||||
#define for_each_action(ptr) PAction ptr; for (ptr = (PAction)actions->slots; (ptr - (PAction)actions->slots) < actions->number_of_records; ptr++)
|
||||
|
||||
/* Externals. */
|
||||
extern PTable actions;
|
||||
extern PTable notes;
|
||||
extern PTable projects;
|
||||
extern PTable tasks;
|
||||
extern PHeader header;
|
||||
extern PTable actions;
|
||||
extern PTable notes;
|
||||
extern PTable projects;
|
||||
extern PTable tasks;
|
||||
|
||||
/* Command handlers and database APIs */
|
||||
void pit_init(char *argv[]);
|
||||
void pit_info(char *argv[]);
|
||||
void pit_project(char *argv[]);
|
||||
void pit_task(char *argv[]);
|
||||
void pit_note(char *argv[]);
|
||||
@@ -52,16 +52,16 @@ void pit_help(char *argv[]);
|
||||
void pit_db_load();
|
||||
void pit_db_save();
|
||||
void pit_db_initialize();
|
||||
void pit_action(ulong id, char *subject, char *message);
|
||||
void pit_task_delete(ulong id, PProject pp);
|
||||
void pit_note_delete(ulong id, PTask pt);
|
||||
void pit_action(int id, char *subject, char *message);
|
||||
void pit_task_delete(int id, PProject pp);
|
||||
void pit_note_delete(int id, PTask pt);
|
||||
|
||||
|
||||
/* Argument parsing helpers */
|
||||
int pit_arg_is_option(char **arg);
|
||||
int pit_arg_option(char **arg);
|
||||
char *pit_arg_string(char **arg, char *required);
|
||||
ulong pit_arg_number(char **arg, char *required);
|
||||
int pit_arg_number(char **arg, char *required);
|
||||
time_t pit_arg_date(char **arg, char *required);
|
||||
time_t pit_arg_time(char **arg, char *required);
|
||||
|
||||
@@ -70,6 +70,7 @@ void die(char *msg, ...);
|
||||
void perish(char *prefix);
|
||||
char *str2str(char *str);
|
||||
char *mem2str(char *mem, int len);
|
||||
bool zero(char *mem, int len);
|
||||
char *current_user();
|
||||
char *home_dir(char *username, int len);
|
||||
char *expand_path(char *path, char *expanded);
|
||||
|
||||
135
src/project.c
135
src/project.c
@@ -3,17 +3,17 @@
|
||||
#include <stdio.h>
|
||||
#include "pit.h"
|
||||
|
||||
static void project_list(char *name, char *status);
|
||||
static void project_show(ulong id);
|
||||
static void project_create(char *name, char *status);
|
||||
static void project_update(ulong id, char *name, char *status);
|
||||
static void project_delete(ulong id);
|
||||
static void project_list(POptions po);
|
||||
static void project_show(int id);
|
||||
static void project_create(POptions po);
|
||||
static void project_update(int id, POptions po);
|
||||
static void project_delete(int id);
|
||||
static bool project_already_exist(char *name);
|
||||
static void project_find_current(PProject *ppp, ulong *pid);
|
||||
static void project_log_create(PProject pp, char *name, char *status);
|
||||
static void project_log_update(PProject pp, char *name, char *status);
|
||||
static void project_log_delete(ulong id, char *name, ulong number_of_tasks);
|
||||
static void project_parse_options(char **arg, char **name, char **status);
|
||||
static int project_find_current(int id, PProject *ppp);
|
||||
static void project_log_create(PProject pp, POptions po);
|
||||
static void project_log_update(PProject pp, POptions po);
|
||||
static void project_log_delete(int id, char *name, int number_of_tasks);
|
||||
static void project_parse_options(char **arg, POptions po);
|
||||
|
||||
/*
|
||||
** CREATING PROJECTS:
|
||||
@@ -32,7 +32,7 @@ static void project_parse_options(char **arg, char **name, char **status);
|
||||
** pit project -q [number | [-n name] [-s status]]
|
||||
*/
|
||||
|
||||
static void project_list(char *name, char *status)
|
||||
static void project_list(POptions po)
|
||||
{
|
||||
PPager ppager;
|
||||
|
||||
@@ -40,49 +40,50 @@ static void project_list(char *name, char *status)
|
||||
if (projects->number_of_records > 0) {
|
||||
ppager = pit_pager_initialize(PAGER_PROJECT, projects->number_of_records);
|
||||
for_each_project(pp) {
|
||||
pit_pager_print(ppager, (uchar *)pp);
|
||||
pit_pager_print(ppager, (char *)pp);
|
||||
}
|
||||
pit_pager_flush(ppager);
|
||||
}
|
||||
}
|
||||
|
||||
static void project_create(char *name, char *status)
|
||||
static void project_create(POptions po)
|
||||
{
|
||||
pit_db_load();
|
||||
|
||||
if (project_already_exist(name)) {
|
||||
if (project_already_exist(po->project.name)) {
|
||||
die("project with the same name already exists");
|
||||
} else {
|
||||
Project p, *pp;
|
||||
|
||||
memset(&p, 0, sizeof(p));
|
||||
|
||||
if (!status) status = "active";
|
||||
printf("creating project [%s], status [%s]\n", name, status);
|
||||
if (!po->project.status) po->project.status = "active";
|
||||
|
||||
strncpy(p.name, name, sizeof(p.name) - 1);
|
||||
strncpy(p.status, status, sizeof(p.status) - 1);
|
||||
strncpy(p.username, current_user(), sizeof(p.username) - 1);
|
||||
strncpy(p.name, po->project.name, sizeof(p.name) - 1);
|
||||
strncpy(p.status, po->project.status, sizeof(p.status) - 1);
|
||||
strncpy(p.username, current_user(), sizeof(p.username) - 1);
|
||||
|
||||
pp = (PProject)pit_table_insert(projects, (uchar *)&p);
|
||||
pp = (PProject)pit_table_insert(projects, (char *)&p);
|
||||
pit_table_mark(projects, pp->id);
|
||||
|
||||
project_log_create(pp, po);
|
||||
pit_db_save();
|
||||
}
|
||||
}
|
||||
|
||||
static void project_show(ulong id)
|
||||
static void project_show(int id)
|
||||
{
|
||||
PProject pp;
|
||||
|
||||
pit_db_load();
|
||||
pp = (PProject)pit_table_find(projects, id);
|
||||
if (pp) {
|
||||
printf("%lu: %s (%s, %lu task%s)\n",
|
||||
printf("%d: %s (%s, %d task%s)\n",
|
||||
pp->id, pp->name, pp->status, pp->number_of_tasks, (pp->number_of_tasks != 1 ? "s" : ""));
|
||||
if (pp->number_of_tasks > 0) {
|
||||
puts("Tasks:");
|
||||
for_each_task(pt) {
|
||||
printf(" %c %lu: %s (%lu notes)\n", (pt->id == tasks->current ? '*' : ' '), pt->id, pt->name, pt->number_of_notes);
|
||||
printf(" %c %d: %s (%d notes)\n", (pt->id == tasks->current ? '*' : ' '), pt->id, pt->name, pt->number_of_notes);
|
||||
}
|
||||
}
|
||||
pit_table_mark(projects, pp->id);
|
||||
@@ -92,27 +93,27 @@ static void project_show(ulong id)
|
||||
}
|
||||
}
|
||||
|
||||
static void project_update(ulong id, char *name, char *status)
|
||||
static void project_update(int id, POptions po)
|
||||
{
|
||||
PProject pp;
|
||||
|
||||
pit_db_load();
|
||||
project_find_current(&pp, &id);
|
||||
id = project_find_current(id, &pp);
|
||||
|
||||
if (name) strncpy(pp->name, name, sizeof(pp->name) - 1);
|
||||
if (status) strncpy(pp->status, status, sizeof(pp->status) - 1);
|
||||
if (po->project.name) strncpy(pp->name, po->project.name, sizeof(pp->name) - 1);
|
||||
if (po->project.status) strncpy(pp->status, po->project.status, sizeof(pp->status) - 1);
|
||||
pit_table_mark(projects, pp->id);
|
||||
|
||||
project_log_update(pp, name, status);
|
||||
project_log_update(pp, po);
|
||||
pit_db_save();
|
||||
}
|
||||
|
||||
static void project_delete(ulong id)
|
||||
static void project_delete(int id)
|
||||
{
|
||||
PProject pp;
|
||||
|
||||
pit_db_load();
|
||||
project_find_current(&pp, &id);
|
||||
id = project_find_current(id, &pp);
|
||||
/*
|
||||
** Delete project tasks.
|
||||
*/
|
||||
@@ -129,7 +130,7 @@ static void project_delete(ulong id)
|
||||
** name and number of tasks since we need these bits for logging.
|
||||
*/
|
||||
char *deleted_name = str2str(pp->name);
|
||||
ulong deleted_number_of_tasks = pp->number_of_tasks;
|
||||
int deleted_number_of_tasks = pp->number_of_tasks;
|
||||
|
||||
pp = (PProject)pit_table_delete(projects, id);
|
||||
if (pp) {
|
||||
@@ -152,70 +153,69 @@ static bool project_already_exist(char *name)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void project_find_current(PProject *ppp, ulong *pid)
|
||||
static int project_find_current(int id, PProject *ppp)
|
||||
{
|
||||
if (*pid) {
|
||||
*ppp = (PProject)pit_table_find(projects, *pid);
|
||||
if (!*ppp) die("could not find project %lu", *pid);
|
||||
if (id) {
|
||||
*ppp = (PProject)pit_table_find(projects, id);
|
||||
if (!*ppp) die("could not find project %d", id);
|
||||
} else {
|
||||
*ppp = (PProject)pit_table_current(projects);
|
||||
if (!*ppp) die("could not find current project");
|
||||
else *pid = (*(PProject *)ppp)->id;
|
||||
}
|
||||
return *ppp ? (*(PProject *)ppp)->id : 0;
|
||||
}
|
||||
|
||||
static void project_log_create(PProject pp, char *name, char *status)
|
||||
static void project_log_create(PProject pp, POptions po)
|
||||
{
|
||||
char str[256];
|
||||
|
||||
sprintf(str, "created project %lu: %s (status: %s)", pp->id, name, status);
|
||||
sprintf(str, "created project %d: %s (status: %s)", pp->id, po->project.name, po->project.status);
|
||||
puts(str);
|
||||
pit_action(pp->id, "project", str);
|
||||
}
|
||||
|
||||
static void project_log_update(PProject pp, char *name, char *status)
|
||||
static void project_log_update(PProject pp, POptions po)
|
||||
{
|
||||
char str[256];
|
||||
bool empty = TRUE;
|
||||
|
||||
sprintf(str, "updated project %lu:", pp->id);
|
||||
if (name) {
|
||||
sprintf(str + strlen(str), " (name: %s", name);
|
||||
sprintf(str, "updated project %d:", pp->id);
|
||||
if (po->project.name) {
|
||||
sprintf(str + strlen(str), " (name: %s", po->project.name);
|
||||
empty = FALSE;
|
||||
} else {
|
||||
sprintf(str + strlen(str), " %s (", pp->name);
|
||||
}
|
||||
if (status) {
|
||||
sprintf(str + strlen(str), "%sstatus: %s)", (empty ? "" : ", "), status);
|
||||
if (po->project.status) {
|
||||
sprintf(str + strlen(str), "%sstatus: %s)", (empty ? "" : ", "), po->project.status);
|
||||
}
|
||||
strcat(str, ")");
|
||||
puts(str);
|
||||
pit_action(pp->id, "project", str);
|
||||
}
|
||||
|
||||
static void project_log_delete(ulong id, char *name, ulong number_of_tasks)
|
||||
static void project_log_delete(int id, char *name, int number_of_tasks)
|
||||
{
|
||||
char str[256];
|
||||
|
||||
sprintf(str, "deleted project %lu: %s", id, name);
|
||||
sprintf(str, "deleted project %d: %s", id, name);
|
||||
if (number_of_tasks > 0) {
|
||||
sprintf(str + strlen(str), " with %lu task%s", number_of_tasks, (number_of_tasks == 1 ? "" : "s"));
|
||||
sprintf(str + strlen(str), " with %d task%s", number_of_tasks, (number_of_tasks == 1 ? "" : "s"));
|
||||
}
|
||||
puts(str);
|
||||
pit_action(id, "project", str);
|
||||
}
|
||||
|
||||
static void project_parse_options(char **arg, char **name, char **status)
|
||||
static void project_parse_options(char **arg, POptions po)
|
||||
{
|
||||
while(*++arg) {
|
||||
switch(pit_arg_option(arg)) {
|
||||
case 's':
|
||||
*status = pit_arg_string(++arg, "project status");
|
||||
break;
|
||||
case 'n':
|
||||
if (name) {
|
||||
*name = pit_arg_string(++arg, "project name");
|
||||
break;
|
||||
} /* else fall though */
|
||||
po->project.name = pit_arg_string(++arg, "project name");
|
||||
break;
|
||||
case 's':
|
||||
po->project.status = pit_arg_string(++arg, "project status");
|
||||
break;
|
||||
default:
|
||||
die("invalid project option: %s", *arg);
|
||||
}
|
||||
@@ -224,12 +224,13 @@ static void project_parse_options(char **arg, char **name, char **status)
|
||||
|
||||
void pit_project(char *argv[])
|
||||
{
|
||||
Options opt;
|
||||
char **arg = &argv[1];
|
||||
char *name = NULL, *status = NULL;
|
||||
ulong number = 0L;
|
||||
int number = 0;
|
||||
|
||||
memset(&opt, 0, sizeof(opt));
|
||||
if (!*arg) {
|
||||
project_list(name, status); /* Show all projects. */
|
||||
project_list(&opt); /* Show all projects. */
|
||||
} else { /* pit project [number] */
|
||||
number = pit_arg_number(arg, NULL);
|
||||
if (number) {
|
||||
@@ -237,18 +238,18 @@ void pit_project(char *argv[])
|
||||
} else {
|
||||
switch(pit_arg_option(arg)) {
|
||||
case 'c': /* pit project -c name [-s status] */
|
||||
name = pit_arg_string(++arg, "project name");
|
||||
project_parse_options(arg, NULL, &status);
|
||||
project_create(name, status);
|
||||
opt.project.name = pit_arg_string(++arg, "project name");
|
||||
project_parse_options(arg, &opt);
|
||||
project_create(&opt);
|
||||
break;
|
||||
case 'e': /* pit project -e [number] [-n name] [-s status] */
|
||||
number = pit_arg_number(++arg, NULL);
|
||||
if (!number) --arg;
|
||||
project_parse_options(arg, &name, &status);
|
||||
if (!name && !status) {
|
||||
project_parse_options(arg, &opt);
|
||||
if (zero((char *)&opt.project, sizeof(opt.project))) {
|
||||
die("nothing to update");
|
||||
} else {
|
||||
project_update(number, name, status);
|
||||
project_update(number, &opt);
|
||||
}
|
||||
break;
|
||||
case 'd': /* pit project -d [number] */
|
||||
@@ -260,11 +261,11 @@ void pit_project(char *argv[])
|
||||
if (number) {
|
||||
project_show(number);
|
||||
} else {
|
||||
project_parse_options(--arg, &name, &status);
|
||||
if (!name && !status) {
|
||||
project_parse_options(--arg, &opt);
|
||||
if (zero((char *)&opt.project, sizeof(opt.project))) {
|
||||
project_show(0); /* Show current project if any. */
|
||||
} else {
|
||||
project_list(name, status);
|
||||
project_list(&opt);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
74
src/table.c
74
src/table.c
@@ -7,7 +7,7 @@
|
||||
/*
|
||||
** Initialize the table by alloocating necessary memory chunks.
|
||||
*/
|
||||
PTable pit_table_initialize(ulong record_size, ulong flags) {
|
||||
PTable pit_table_initialize(int record_size, int flags) {
|
||||
PTable pt = calloc(1, sizeof(Table));
|
||||
|
||||
pt->flags = flags;
|
||||
@@ -17,7 +17,7 @@ PTable pit_table_initialize(ulong record_size, ulong flags) {
|
||||
pt->auto_increment = 0;
|
||||
pt->current = 0;
|
||||
pt->slots = calloc(TABLE_INCREMENT, pt->record_size);
|
||||
pt->index = calloc(TABLE_INCREMENT, sizeof(uchar *));
|
||||
pt->index = calloc(TABLE_INCREMENT, sizeof(char *));
|
||||
|
||||
return pt;
|
||||
}
|
||||
@@ -25,14 +25,14 @@ PTable pit_table_initialize(ulong record_size, ulong flags) {
|
||||
/*
|
||||
** Return the address of next avaiable slot within pt->slots chunk.
|
||||
*/
|
||||
static uchar *table_available_slot(PTable pt) {
|
||||
static char *table_available_slot(PTable pt) {
|
||||
return pt->slots + pt->number_of_records * pt->record_size;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the address of last stored record.
|
||||
*/
|
||||
static uchar *table_last_record(PTable pt) {
|
||||
static char *table_last_record(PTable pt) {
|
||||
if (pt->number_of_records == 0) {
|
||||
return pt->slots;
|
||||
} else {
|
||||
@@ -43,14 +43,14 @@ static uchar *table_last_record(PTable pt) {
|
||||
/*
|
||||
** Return the address of next available pointer within pt->index chunk.
|
||||
*/
|
||||
static uchar **table_available_index(PTable pt) {
|
||||
static char **table_available_index(PTable pt) {
|
||||
return pt->index + pt->auto_increment;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the address of last pointer within pt->index chunk.
|
||||
*/
|
||||
static uchar **table_last_index(PTable pt) {
|
||||
static char **table_last_index(PTable pt) {
|
||||
if (pt->auto_increment == 0) {
|
||||
return pt->index;
|
||||
} else {
|
||||
@@ -65,8 +65,8 @@ static uchar **table_last_index(PTable pt) {
|
||||
** existing indices to make them point to reallocated record slots.
|
||||
*/
|
||||
static PTable table_extend(PTable pt) {
|
||||
register ulong i;
|
||||
register uchar **pi;
|
||||
register int i;
|
||||
register char **pi;
|
||||
|
||||
pt->number_of_slots += TABLE_INCREMENT;
|
||||
/*
|
||||
@@ -93,7 +93,7 @@ static PTable table_extend(PTable pt) {
|
||||
/*
|
||||
** Find a record by id and return its address.
|
||||
*/
|
||||
uchar *pit_table_find(PTable pt, ulong id) {
|
||||
char *pit_table_find(PTable pt, int id) {
|
||||
// TODO: retrn NULL (or raise?) if table doesn't have id.
|
||||
if (pt->number_of_records == 0 || id <= 0 || id > pt->auto_increment) {
|
||||
return NULL;
|
||||
@@ -106,14 +106,14 @@ uchar *pit_table_find(PTable pt, ulong id) {
|
||||
** Delete a record by its ID. Return the address of deleted record or NULL
|
||||
** if the record was not found.
|
||||
*/
|
||||
uchar *pit_table_delete(PTable pt, ulong id) {
|
||||
char *pit_table_delete(PTable pt, int id) {
|
||||
// TODO: return NULL (or die?) if table doesn't have id.
|
||||
register uchar *pr = (uchar *)pit_table_find(pt, id);
|
||||
register char *pr = (char *)pit_table_find(pt, id);
|
||||
|
||||
if (pr) {
|
||||
register ulong i;
|
||||
register uchar **pi;
|
||||
register uchar *last = table_last_record(pt);
|
||||
register int i;
|
||||
register char **pi;
|
||||
register char *last = table_last_record(pt);
|
||||
/*
|
||||
** Overwrite current record by shifting over remaining records
|
||||
*/
|
||||
@@ -144,8 +144,8 @@ uchar *pit_table_delete(PTable pt, ulong id) {
|
||||
** Insert a record and return its address. The table gets extended
|
||||
** as necessary.
|
||||
*/
|
||||
uchar *pit_table_insert(PTable pt, uchar *record) {
|
||||
register uchar **pi;
|
||||
char *pit_table_insert(PTable pt, char *record) {
|
||||
register char **pi;
|
||||
register time_t now;
|
||||
|
||||
if (pt->number_of_records >= pt->number_of_slots) {
|
||||
@@ -163,7 +163,7 @@ uchar *pit_table_insert(PTable pt, uchar *record) {
|
||||
** record field of type "unsigned long".
|
||||
*/
|
||||
if (pt->flags & TABLE_HAS_ID) {
|
||||
*(ulong *)*pi = pt->auto_increment;
|
||||
*(int *)*pi = pt->auto_increment;
|
||||
}
|
||||
/*
|
||||
** Update created_at and/or updated_at which must be last one or two record
|
||||
@@ -182,14 +182,14 @@ uchar *pit_table_insert(PTable pt, uchar *record) {
|
||||
/*
|
||||
** Find current record.
|
||||
*/
|
||||
uchar *pit_table_current(PTable pt) {
|
||||
char *pit_table_current(PTable pt) {
|
||||
return pit_table_find(pt, pt->current);
|
||||
}
|
||||
|
||||
/*
|
||||
** Set current record as indicated by the id, then find and return it.
|
||||
*/
|
||||
uchar *pit_table_mark(PTable pt, ulong id) {
|
||||
char *pit_table_mark(PTable pt, int id) {
|
||||
return pit_table_find(pt, pt->current = id);
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ int pit_table_save(FILE *file, PTable pt) {
|
||||
** Save table header data: flags, record_size, number_of_slots,
|
||||
** number_of_records, and auto_increment, current.
|
||||
*/
|
||||
written += fwrite(pt, sizeof(ulong), 6, file);
|
||||
written += fwrite(pt, sizeof(int), 6, file);
|
||||
/*
|
||||
** Save the records. Note that we save the actual (not allocated) data.
|
||||
*/
|
||||
@@ -233,20 +233,20 @@ int pit_table_save(FILE *file, PTable pt) {
|
||||
PTable pit_table_load(FILE *file) {
|
||||
PTable pt;
|
||||
register int read = 0;
|
||||
register ulong i;
|
||||
uchar *pr, **pi;
|
||||
register int i;
|
||||
char *pr, **pi;
|
||||
|
||||
pt = calloc(1, sizeof(Table));
|
||||
/*
|
||||
** First read the header.
|
||||
*/
|
||||
read += fread(pt, sizeof(ulong), 6, file);
|
||||
read += fread(pt, sizeof(int), 6, file);
|
||||
/*
|
||||
** Now allocate slots and index based on the original number of slots.
|
||||
*/
|
||||
/*** printf("Allocating %lu slots\n", pt->number_of_slots); ***/
|
||||
/*** printf("Allocating %d slots\n", pt->number_of_slots); ***/
|
||||
pt->slots = pr = calloc(pt->number_of_slots, pt->record_size);
|
||||
pt->index = pi = calloc(pt->number_of_slots, sizeof(uchar *));
|
||||
pt->index = pi = calloc(pt->number_of_slots, sizeof(char *));
|
||||
/*
|
||||
** Now read the records into the slots and rebuild the index if the
|
||||
** table has primary key.
|
||||
@@ -254,7 +254,7 @@ PTable pit_table_load(FILE *file) {
|
||||
read += fread(pt->slots, pt->record_size, pt->number_of_records, file);
|
||||
if (pt->flags & TABLE_HAS_ID) {
|
||||
for(i = 1; i <= pt->number_of_slots; i++, pi++) {
|
||||
if ((ulong)*pr == i) {
|
||||
if ((int)*pr == i) {
|
||||
*pi = pr;
|
||||
pr += pt->record_size;
|
||||
}
|
||||
@@ -267,8 +267,8 @@ PTable pit_table_load(FILE *file) {
|
||||
#if defined(TEST)
|
||||
|
||||
typedef struct {
|
||||
ulong id;
|
||||
ulong value;
|
||||
int id;
|
||||
int value;
|
||||
char name[30];
|
||||
time_t created_at;
|
||||
time_t updated_at;
|
||||
@@ -276,8 +276,8 @@ typedef struct {
|
||||
|
||||
void dump(Record *prec) {
|
||||
if (prec) {
|
||||
printf("(%08lX) id: %08lu, value: %lu, created_at: %lu, updated_at: %lu\n",
|
||||
(ulong)prec, prec->id, prec->value, prec->created_at, prec->updated_at);
|
||||
printf("(%08lX) id: %08d, value: %d, created_at: %d, updated_at: %d\n",
|
||||
(int)prec, prec->id, prec->value, prec->created_at, prec->updated_at);
|
||||
} else {
|
||||
printf("(NULL)\n");
|
||||
}
|
||||
@@ -301,7 +301,7 @@ int main() {
|
||||
PTable pt;
|
||||
|
||||
Record rec, *prec;
|
||||
ulong i, total = 3;
|
||||
int i, total = 3;
|
||||
|
||||
pt = pit_table_initialize(sizeof(Record), TABLE_HAS_ID | TABLE_HAS_TIMESTAMPS);
|
||||
for(i = 0; i < total; i++) {
|
||||
@@ -310,20 +310,20 @@ int main() {
|
||||
strcpy(rec.name, "test");
|
||||
rec.created_at = rec.updated_at = (time_t)0;
|
||||
|
||||
prec = (Record *)pit_table_insert(pt, (uchar *)&rec);
|
||||
prec = (Record *)pit_table_insert(pt, (char *)&rec);
|
||||
dump(prec);
|
||||
}
|
||||
prec = (Record *)pit_table_find(pt, total - 1);
|
||||
pit_table_mark(pt, prec->id);
|
||||
printf("current: %lu\n", pt->current);
|
||||
printf("current: %d\n", pt->current);
|
||||
|
||||
// for (i = 20; i < total; i++) {
|
||||
// printf("Deleting %lu\n", i + 1);
|
||||
// printf("Deleting %d\n", i + 1);
|
||||
// prec = (Record *)pit_table_delete(pt, i + 1);
|
||||
// }
|
||||
printf("Deleting %lu\n", 1L);
|
||||
printf("Deleting %d\n", 1L);
|
||||
prec = (Record *)pit_table_delete(pt, 1);
|
||||
printf("current: %lu\n", pt->current);
|
||||
printf("current: %d\n", pt->current);
|
||||
dump_all(pt);
|
||||
|
||||
FILE *file = fopen("/tmp/.pit", "w");
|
||||
@@ -333,7 +333,7 @@ int main() {
|
||||
file = fopen("/tmp/.pit", "r");
|
||||
pt = pit_table_load(file);
|
||||
dump_all(pt);
|
||||
printf("current: %lu\n", pt->current);
|
||||
printf("current: %d\n", pt->current);
|
||||
fclose(file);
|
||||
|
||||
pit_table_free(pt);
|
||||
|
||||
28
src/table.h
28
src/table.h
@@ -7,24 +7,24 @@
|
||||
#define TABLE_HAS_TIMESTAMPS (TABLE_HAS_CREATED_AT | TABLE_HAS_UPDATED_AT)
|
||||
|
||||
typedef struct _Table {
|
||||
ulong flags; /* Bit mask with table flags. */
|
||||
ulong record_size; /* Record size in bytes; all records are of fixed size. */
|
||||
ulong number_of_slots; /* Number of slots allocated, each slot is 'record_size' long. */
|
||||
ulong number_of_records; /* Number of records currently stored in slots. */
|
||||
ulong auto_increment; /* Current value of record id. */
|
||||
ulong current; /* The id of currently selected record, one per table. */
|
||||
uchar *slots; /* Memory chunk to store records; compacted when a record gets deleted (no holes). */
|
||||
uchar **index; /* Memory chunk to store pointers to individual records, holes for deleted record IDs. */
|
||||
int flags; /* Bit mask with table flags. */
|
||||
int record_size; /* Record size in bytes; all records are of fixed size. */
|
||||
int number_of_slots; /* Number of slots allocated, each slot is 'record_size' long. */
|
||||
int number_of_records; /* Number of records currently stored in slots. */
|
||||
int auto_increment; /* Current value of record id. */
|
||||
int current; /* The id of currently selected record, one per table. */
|
||||
char *slots; /* Memory chunk to store records; compacted when a record gets deleted (no holes). */
|
||||
char **index; /* Memory chunk to store pointers to individual records, holes for deleted record IDs. */
|
||||
} Table, *PTable;
|
||||
|
||||
PTable pit_table_initialize(ulong record_size, ulong flags);
|
||||
PTable pit_table_initialize(int record_size, int flags);
|
||||
void pit_table_free(PTable pt);
|
||||
uchar *pit_table_find(PTable pt, ulong id);
|
||||
uchar *pit_table_delete(PTable pt, ulong id);
|
||||
uchar *pit_table_insert(PTable pt, uchar *record);
|
||||
char *pit_table_find(PTable pt, int id);
|
||||
char *pit_table_delete(PTable pt, int id);
|
||||
char *pit_table_insert(PTable pt, char *record);
|
||||
|
||||
uchar *pit_table_current(PTable pt);
|
||||
uchar *pit_table_mark(PTable pt, ulong id);
|
||||
char *pit_table_current(PTable pt);
|
||||
char *pit_table_mark(PTable pt, int id);
|
||||
|
||||
int pit_table_save(FILE *file, PTable pt);
|
||||
PTable pit_table_load(FILE *file);
|
||||
|
||||
174
src/task.c
174
src/task.c
@@ -2,16 +2,16 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "pit.h"
|
||||
|
||||
static void task_list(char *name, char *status, char *priority, time_t date, time_t time);
|
||||
static void task_show(ulong id);
|
||||
static void task_create(char *name, char *status, char *priority, time_t date, time_t time);
|
||||
static void task_update(ulong id, char *name, char *status, char *priority, time_t date, time_t time);
|
||||
static void task_find_current(PTask *ppt, ulong *pid);
|
||||
static void task_log_create(PTask pt, char *name, char *status, char *priority, time_t date, time_t time);
|
||||
static void task_log_update(PTask pt, char *name, char *status, char *priority, time_t date, time_t time);
|
||||
static void task_log_delete(ulong id, char *name, ulong number_of_notes);
|
||||
static void task_parse_options(char **arg, char **name, char **status, char **priority, time_t *date, time_t *time);
|
||||
|
||||
static void task_list(POptions po);
|
||||
static void task_show(int id);
|
||||
static void task_create(POptions po);
|
||||
static void task_update(int id, POptions po);
|
||||
static int task_find_current(int id, PTask *ppt);
|
||||
static void task_log_create(PTask pt, POptions po);
|
||||
static void task_log_update(PTask pt, POptions po);
|
||||
static void task_log_delete(int id, char *name, int number_of_notes);
|
||||
static void task_parse_options(char **arg, POptions po);
|
||||
|
||||
/*
|
||||
** CREATING TASKS:
|
||||
@@ -30,7 +30,7 @@ static void task_parse_options(char **arg, char **name, char **status, char **pr
|
||||
** pit task -q [number | [-n name] [-s status] [-p priority] [-d date] [-t time]]
|
||||
*/
|
||||
|
||||
static void task_list(char *name, char *status, char *priority, time_t date, time_t time)
|
||||
static void task_list(POptions po)
|
||||
{
|
||||
pit_db_load();
|
||||
if (tasks->number_of_records > 0) {
|
||||
@@ -41,21 +41,20 @@ static void task_list(char *name, char *status, char *priority, time_t date, tim
|
||||
if (pp && pt->project_id != pp->id) {
|
||||
continue;
|
||||
}
|
||||
pit_pager_print(ppager, (uchar *)pt);
|
||||
pit_pager_print(ppager, (char *)pt);
|
||||
}
|
||||
pit_pager_flush(ppager);
|
||||
}
|
||||
}
|
||||
|
||||
static void task_show(ulong id)
|
||||
static void task_show(int id)
|
||||
{
|
||||
printf("task_show(%lu)\n", id);
|
||||
printf("task_show(%d)\n", id);
|
||||
}
|
||||
|
||||
static void task_create(char *name, char *status, char *priority, time_t date, time_t time)
|
||||
static void task_create(POptions po)
|
||||
{
|
||||
pit_db_load();
|
||||
|
||||
PProject pp = (PProject)pit_table_current(projects);
|
||||
|
||||
if (!pp) {
|
||||
@@ -65,40 +64,40 @@ static void task_create(char *name, char *status, char *priority, time_t date, t
|
||||
|
||||
memset(&t, 0, sizeof(t));
|
||||
|
||||
if (!status) status = "open";
|
||||
if (!priority) priority = "normal";
|
||||
if (!po->task.status) po->task.status = "open";
|
||||
if (!po->task.priority) po->task.priority = "normal";
|
||||
|
||||
strncpy(t.name, name, sizeof(t.name) - 1);
|
||||
strncpy(t.status, status, sizeof(t.status) - 1);
|
||||
strncpy(t.priority, priority, sizeof(t.priority) - 1);
|
||||
strncpy(t.username, current_user(), sizeof(t.username) - 1);
|
||||
strncpy(t.name, po->task.name, sizeof(t.name) - 1);
|
||||
strncpy(t.status, po->task.status, sizeof(t.status) - 1);
|
||||
strncpy(t.priority, po->task.priority, sizeof(t.priority) - 1);
|
||||
strncpy(t.username, current_user(), sizeof(t.username) - 1);
|
||||
t.project_id = pp->id;
|
||||
t.date = date;
|
||||
t.time = time;
|
||||
t.date = po->task.date;
|
||||
t.time = po->task.time;
|
||||
|
||||
pt = (PTask)pit_table_insert(tasks, (uchar *)&t);
|
||||
pt = (PTask)pit_table_insert(tasks, (char *)&t);
|
||||
pit_table_mark(tasks, pt->id);
|
||||
pp->number_of_tasks++;
|
||||
task_log_create(pt, name, status, priority, date, time);
|
||||
task_log_create(pt, po);
|
||||
pit_db_save();
|
||||
}
|
||||
}
|
||||
|
||||
static void task_update(ulong id, char *name, char *status, char *priority, time_t date, time_t time)
|
||||
static void task_update(int id, POptions po)
|
||||
{
|
||||
PTask pt;
|
||||
|
||||
pit_db_load();
|
||||
task_find_current(&pt, &id);
|
||||
id = task_find_current(id, &pt);
|
||||
|
||||
if (name) strncpy(pt->name, name, sizeof(pt->name) - 1);
|
||||
if (status) strncpy(pt->status, status, sizeof(pt->status) - 1);
|
||||
if (priority) strncpy(pt->priority, priority, sizeof(pt->priority) - 1);
|
||||
if (date) pt->date = date;
|
||||
if (time) pt->time = time;
|
||||
if (po->task.name) strncpy(pt->name, po->task.name, sizeof(pt->name) - 1);
|
||||
if (po->task.status) strncpy(pt->status, po->task.status, sizeof(pt->status) - 1);
|
||||
if (po->task.priority) strncpy(pt->priority, po->task.priority, sizeof(pt->priority) - 1);
|
||||
if (po->task.date) pt->date = po->task.date;
|
||||
if (po->task.time) pt->time = po->task.time;
|
||||
pit_table_mark(tasks, pt->id);
|
||||
|
||||
task_log_update(pt, name, status, priority, date, time);
|
||||
task_log_update(pt, po);
|
||||
pit_db_save();
|
||||
}
|
||||
|
||||
@@ -106,13 +105,13 @@ static void task_update(ulong id, char *name, char *status, char *priority, time
|
||||
** A task could be deleted as standalone entity or as part of cascading project
|
||||
** delete. In later case we're going to have 'pp' set and the database loaded.
|
||||
*/
|
||||
void pit_task_delete(ulong id, PProject pp)
|
||||
void pit_task_delete(int id, PProject pp)
|
||||
{
|
||||
PTask pt;
|
||||
bool standalone = (pp == NULL);
|
||||
|
||||
if (standalone) pit_db_load();
|
||||
task_find_current(&pt, &id);
|
||||
id = task_find_current(id, &pt);
|
||||
if (standalone) pp = (PProject)pit_table_find(projects, pt->project_id);
|
||||
|
||||
if (pp) {
|
||||
@@ -132,7 +131,7 @@ void pit_task_delete(ulong id, PProject pp)
|
||||
** we need these for logging.
|
||||
*/
|
||||
char *deleted_name = str2str(pt->name);
|
||||
ulong deleted_number_of_notes = pt->number_of_notes;
|
||||
int deleted_number_of_notes = pt->number_of_notes;
|
||||
|
||||
pt = (PTask)pit_table_delete(tasks, id);
|
||||
if (pt) {
|
||||
@@ -145,100 +144,98 @@ void pit_task_delete(ulong id, PProject pp)
|
||||
free(deleted_name);
|
||||
} else {
|
||||
free(deleted_name);
|
||||
die("could not delete task %lu", id);
|
||||
die("could not delete task %d", id);
|
||||
}
|
||||
} else {
|
||||
die("could not find project for task %lu", id);
|
||||
die("could not find project for task %d", id);
|
||||
}
|
||||
}
|
||||
|
||||
static void task_find_current(PTask *ppt, ulong *pid)
|
||||
static int task_find_current(int id, PTask *ppt)
|
||||
{
|
||||
if (*pid) {
|
||||
*ppt = (PTask)pit_table_find(tasks, *pid);
|
||||
if (!*ppt) die("could not find task %lu", *pid);
|
||||
if (id) {
|
||||
*ppt = (PTask)pit_table_find(tasks, id);
|
||||
if (!*ppt) die("could not find task %d", id);
|
||||
} else {
|
||||
*ppt = (PTask)pit_table_current(tasks);
|
||||
if (!*ppt) die("could not find current task");
|
||||
else *pid = (*(PTask *)ppt)->id;
|
||||
}
|
||||
return *ppt ? (*(PTask *)ppt)->id : 0;
|
||||
}
|
||||
|
||||
static void task_log_create(PTask pt, char *name, char *status, char *priority, time_t date, time_t time)
|
||||
static void task_log_create(PTask pt, POptions po)
|
||||
{
|
||||
char str[256];
|
||||
|
||||
sprintf(str, "created task %lu: %s (status: %s, priority: %s", pt->id, name, status, priority);
|
||||
if (date) sprintf(str + strlen(str), ", date: %s", format_date(date));
|
||||
if (time) sprintf(str + strlen(str), ", time: %s", format_date(time));
|
||||
sprintf(str, "created task %d: %s (status: %s, priority: %s", pt->id, po->task.name, po->task.status, po->task.priority);
|
||||
if (po->task.date) sprintf(str + strlen(str), ", date: %s", format_date(po->task.date));
|
||||
if (po->task.time) sprintf(str + strlen(str), ", time: %s", format_time(po->task.time));
|
||||
strcat(str, ")");
|
||||
puts(str);
|
||||
pit_action(pt->id, "task", str);
|
||||
}
|
||||
|
||||
static void task_log_update(PTask pt, char *name, char *status, char *priority, time_t date, time_t time)
|
||||
static void task_log_update(PTask pt, POptions po)
|
||||
{
|
||||
char str[256];
|
||||
bool empty = TRUE;
|
||||
|
||||
sprintf(str, "updated task %lu:", pt->id);
|
||||
if (name) {
|
||||
sprintf(str + strlen(str), " (name: %s", name);
|
||||
sprintf(str, "updated task %d:", pt->id);
|
||||
if (po->task.name) {
|
||||
sprintf(str + strlen(str), " (name: %s", po->task.name);
|
||||
empty = FALSE;
|
||||
} else {
|
||||
sprintf(str + strlen(str), " %s (", pt->name);
|
||||
}
|
||||
if (status) {
|
||||
sprintf(str + strlen(str), "%sstatus: %s", (empty ? "" : ", "), status);
|
||||
if (po->task.status) {
|
||||
sprintf(str + strlen(str), "%sstatus: %s", (empty ? "" : ", "), po->task.status);
|
||||
empty = FALSE;
|
||||
}
|
||||
if (priority) {
|
||||
sprintf(str + strlen(str), "%spriority: %s", (empty ? "" : ", "), priority);
|
||||
if (po->task.priority) {
|
||||
sprintf(str + strlen(str), "%spriority: %s", (empty ? "" : ", "), po->task.priority);
|
||||
empty = FALSE;
|
||||
}
|
||||
if (date) {
|
||||
sprintf(str + strlen(str), "%sdate: %s", (empty ? "" : ", "), format_date(date));
|
||||
if (po->task.date) {
|
||||
sprintf(str + strlen(str), "%sdate: %s", (empty ? "" : ", "), format_date(po->task.date));
|
||||
empty = FALSE;
|
||||
}
|
||||
if (time) sprintf(str + strlen(str), "%stime: %s", (empty ? "" : ", "), format_date(time));
|
||||
if (po->task.time) sprintf(str + strlen(str), "%stime: %s", (empty ? "" : ", "), format_time(po->task.time));
|
||||
strcat(str, ")");
|
||||
puts(str);
|
||||
pit_action(pt->id, "task", str);
|
||||
}
|
||||
|
||||
static void task_log_delete(ulong id, char *name, ulong number_of_notes)
|
||||
static void task_log_delete(int id, char *name, int number_of_notes)
|
||||
{
|
||||
char str[256];
|
||||
|
||||
sprintf(str, "deleted task %lu: %s", id, name);
|
||||
sprintf(str, "deleted task %d: %s", id, name);
|
||||
if (number_of_notes > 0) {
|
||||
sprintf(str + strlen(str), " with %lu note%s", number_of_notes, (number_of_notes == 1 ? "" : "s"));
|
||||
sprintf(str + strlen(str), " with %d note%s", number_of_notes, (number_of_notes == 1 ? "" : "s"));
|
||||
}
|
||||
puts(str);
|
||||
pit_action(id, "task", str);
|
||||
}
|
||||
|
||||
static void task_parse_options(char **arg, char **name, char **status, char **priority, time_t *date, time_t *time)
|
||||
static void task_parse_options(char **arg, POptions po)
|
||||
{
|
||||
while(*++arg) {
|
||||
switch(pit_arg_option(arg)) {
|
||||
case 'n':
|
||||
po->task.name = pit_arg_string(++arg, "task name");
|
||||
break;
|
||||
case 's':
|
||||
*status = pit_arg_string(++arg, "task status");
|
||||
po->task.status = pit_arg_string(++arg, "task status");
|
||||
break;
|
||||
case 'p':
|
||||
*priority = pit_arg_string(++arg, "task priority");
|
||||
po->task.priority = pit_arg_string(++arg, "task priority");
|
||||
break;
|
||||
case 'd':
|
||||
*date = pit_arg_date(++arg, "task date");
|
||||
po->task.date = pit_arg_date(++arg, "task date");
|
||||
break;
|
||||
case 't':
|
||||
*time = pit_arg_time(++arg, "task time");
|
||||
po->task.time = pit_arg_time(++arg, "task time");
|
||||
break;
|
||||
case 'n':
|
||||
if (name) {
|
||||
*name = pit_arg_string(++arg, "task name");
|
||||
break;
|
||||
} /* else fall though */
|
||||
default:
|
||||
die("invalid task option: %s", *arg);
|
||||
}
|
||||
@@ -247,14 +244,13 @@ static void task_parse_options(char **arg, char **name, char **status, char **pr
|
||||
|
||||
void pit_task(char *argv[])
|
||||
{
|
||||
Options opt;
|
||||
int number = 0;
|
||||
char **arg = &argv[1];
|
||||
char *name = NULL, *status = NULL, *priority = NULL;
|
||||
time_t date = (time_t)0;
|
||||
time_t time = (time_t)0;
|
||||
ulong number = 0L;
|
||||
|
||||
memset(&opt, 0, sizeof(opt));
|
||||
if (!*arg) {
|
||||
task_list(name, status, priority, date, time); /* List all tasks (i.e. use default paramaters). */
|
||||
task_list(&opt); /* List all tasks (i.e. use default paramaters). */
|
||||
} else { /* pit task [number] */
|
||||
number = pit_arg_number(arg, NULL);
|
||||
if (number) {
|
||||
@@ -262,18 +258,18 @@ void pit_task(char *argv[])
|
||||
} else {
|
||||
switch(pit_arg_option(arg)) {
|
||||
case 'c': /* pit task -c name [-s status] [-p priority] [-d date] [-t time] */
|
||||
name = pit_arg_string(++arg, "task name");
|
||||
task_parse_options(arg, NULL, &status, &priority, &date, &time);
|
||||
task_create(name, status, priority, date, time);
|
||||
opt.task.name = pit_arg_string(++arg, "task name");
|
||||
task_parse_options(arg, &opt);
|
||||
task_create(&opt);
|
||||
break;
|
||||
case 'e': /* pit task -e [number] [-n name] [-s status] [-p priority] [-d date] [-t time] */
|
||||
number = pit_arg_number(++arg, NULL);
|
||||
if (!number) --arg;
|
||||
task_parse_options(arg, &name, &status, &priority, &date, &time);
|
||||
if (!name && !status && !priority && !date && !time) {
|
||||
task_parse_options(arg, &opt);
|
||||
if (!opt.task.name && !opt.task.status && !opt.task.priority && !opt.task.date && !opt.task.time) {
|
||||
die("nothing to update");
|
||||
} else {
|
||||
task_update(number, name, status, priority, date, time);
|
||||
task_update(number, &opt);
|
||||
}
|
||||
break;
|
||||
case 'd': /* pit task -d [number] */
|
||||
@@ -281,15 +277,15 @@ void pit_task(char *argv[])
|
||||
pit_task_delete(number, NULL); /* Delete the task, but keep its project. */
|
||||
break;
|
||||
case 'q': /* pit task -q [number | [-n name] [-s status] [-p priority] [-d date] [-t time]] */
|
||||
number = pit_arg_number(++arg, NULL);
|
||||
if (number) {
|
||||
task_show(number);
|
||||
opt.task.id = pit_arg_number(++arg, NULL);
|
||||
if (opt.task.id) {
|
||||
task_show(opt.task.id);
|
||||
} else {
|
||||
task_parse_options(--arg, &name, &status, &priority, &date, &time);
|
||||
if (!name && !status && !priority && !date && !time) {
|
||||
task_parse_options(--arg, &opt);
|
||||
if (!opt.task.name && !opt.task.status && !opt.task.priority && !opt.task.date && !opt.task.time) {
|
||||
task_show(0); /* Show current task if any. */
|
||||
} else {
|
||||
task_list(name, status, priority, date, time);
|
||||
task_list(&opt);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -18,6 +18,15 @@ char *mem2str(char *mem, int len) {
|
||||
return str;
|
||||
}
|
||||
|
||||
bool zero(char *mem, int len) {
|
||||
char *pch = mem;
|
||||
|
||||
while(pch - mem < len) {
|
||||
if (*pch++) return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
char *current_user() {
|
||||
static char *username = NULL;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user