/* toradora.c - A terminal based todo list */ /* Using a sqlite database at ~/.toradora.db we will keep track of all the * entries */ /** FEATURES **/ /* * 1. Able to add tasks. (toradora -a "The task I want to add") * 2. Able to complete those tasks. (toradora -c 1 ) * 3. Able to edit those tasks. (toradora -e 1 "The previous task edited") * 4. Able to manifest those tasks. (toradora) * =============================== * >>> Today's Task <<< * 1. "task one" * 2. "task two" * * >>> Backlogs <<< * 3. "task three" * =============================== * 5. Able to manifest all the tasks in database. (toradora -z) * */ #include #include #include #include #define VERSION "0.1.0" #define MAX_PATH_LENGTH 4096 static void manifest_usage() { printf("toradora - a terminal based todo list\n\n"); printf("Usage:\n"); printf(" toradora Show today's tasks and backlog\n"); printf(" toradora -z Show all tasks ever recorded\n"); printf(" toradora -a \"task\" Add a new task\n"); printf(" toradora -c Mark task as complete\n"); printf(" toradora -e \"new task\" Edit task \n\n"); printf("Examples:\n"); printf(" toradora -a \"write usage function\"\n"); printf(" toradora -c 3\n"); printf(" toradora -e 3 \"write usage function (done)\"\n"); } static int callback_manifest(void *data, int argc, char **argv, char **az_col_name) { /* fprintf(stderr, "%s: ", (const char *)data); */ printf("%s. %s\n", argv[0], argv[1]); printf("\n"); return 0; } static void manifest_active_tasks(sqlite3 *DB) { int query_status; char *message_error_1; char *message_error_2; printf("----------------------------------------------\n"); printf(">>> Today's Task <<<\n"); char *manifest_query_1 = "SELECT ID, TASK FROM tasks WHERE STATUS = 0 " "AND created_at = CURRENT_DATE;"; query_status = sqlite3_exec(DB, manifest_query_1, callback_manifest, "Manifest callback", &message_error_1); if (query_status != SQLITE_OK) { printf("[Error]: Unexpected error during execution of query\n"); printf("%s\n", message_error_1); printf("[Help]: Check database sanity\n"); return; } printf(">>> Backlog <<<\n"); char *manifest_query_2 = "SELECT ID, TASK FROM tasks WHERE STATUS = 0 " "AND created_at != CURRENT_DATE;"; query_status = sqlite3_exec(DB, manifest_query_2, callback_manifest, "Manifest callback", &message_error_2); if (query_status != SQLITE_OK) { printf("[Error]: Unexpected error during execution of query\n"); printf("%s\n", message_error_2); printf("[Help]: Check database sanity\n"); return; } printf("----------------------------------------------\n"); } static void manifest_all_tasks(sqlite3 *DB) { int query_status; char *message_error; printf("----------------------------------------------\n"); printf(">>> All tasks ever recorded\n"); char *manifest_query = "SELECT ID, TASK FROM tasks;"; query_status = sqlite3_exec(DB, manifest_query, callback_manifest, "Manifest callback", &message_error); if (query_status != SQLITE_OK) { printf("[Error]: Unexpected error during execution of query\n"); printf("%s\n", message_error); printf("[Help]: Check database sanity\n"); return; } printf("----------------------------------------------\n"); } static void toradora_add_task(sqlite3 *DB, const char *todo) { sqlite3_stmt *stmt = NULL; int query_status; const char *add_query = "INSERT INTO TASKS (task) VALUES (?);"; query_status = sqlite3_prepare_v2(DB, add_query, -1, &stmt, NULL); if (query_status != SQLITE_OK) { printf("[Error]: Unexpected error during execution of query\n"); printf("[Help]: Check database sanity\n"); goto error; } sqlite3_bind_text(stmt, 1, todo, -1, SQLITE_STATIC); query_status = sqlite3_step(stmt); if (query_status != SQLITE_DONE) { printf("[Error]: Unexpected error during execution of query\n"); printf("[Help]: Check database sanity\n"); goto error; } error: sqlite3_finalize(stmt); } static void toradora_complete_task(sqlite3 *DB, const char *id) { sqlite3_stmt *stmt = NULL; int query_status; int curr; char *end_ptr; int row_affected; const char *complete_query = "UPDATE TASKS SET status = 1 WHERE id = ?;"; query_status = sqlite3_prepare_v2(DB, complete_query, -1, &stmt, NULL); if (query_status != SQLITE_OK) { printf("[Error]: Unexpected error during execution of query\n"); printf("[Help]: Check database sanity\n"); goto error; } curr = (int)strtol(id, &end_ptr, 10); if (*end_ptr != '\0') { printf("[Error]: Invalid argument"); manifest_usage(); goto error; } sqlite3_bind_int(stmt, 1, curr); query_status = sqlite3_step(stmt); if (query_status != SQLITE_DONE) { printf("[Error]: Unexpected error during execution of query\n"); printf("[Help]: Check database sanity\n"); goto error; } row_affected = sqlite3_changes(DB); if (row_affected == 0) { printf("[Info]: No rows were affected\n"); printf("[Help]: Did you entered valid task id?\n"); } error: sqlite3_finalize(stmt); } static void toradora_edit_task(sqlite3 *DB, const char *id, const char *new_task) { sqlite3_stmt *stmt = NULL; int query_status; int curr; char *end_ptr; int row_affected; const char *complete_query = "UPDATE TASKS SET task = ? WHERE id = ?;"; query_status = sqlite3_prepare_v2(DB, complete_query, -1, &stmt, NULL); if (query_status != SQLITE_OK) { printf("[Error]: Unexpected error during execution of query\n"); printf("[Help]: Check database sanity\n"); goto error; } curr = (int)strtol(id, &end_ptr, 10); if (*end_ptr != '\0') { printf("[Error]: Invalid argument"); manifest_usage(); goto error; } sqlite3_bind_text(stmt, 1, new_task, -1, SQLITE_STATIC); sqlite3_bind_int(stmt, 2, curr); query_status = sqlite3_step(stmt); if (query_status != SQLITE_DONE) { printf("[Error]: Unexpected error during execution of query\n"); printf("[Help]: Check database sanity\n"); goto error; } row_affected = sqlite3_changes(DB); if (row_affected == 0) { printf("[Info]: No rows were affected\n"); printf("[Help]: Did you entered valid task id?\n"); } error: sqlite3_finalize(stmt); } int main(int argc, char *argv[]) { char *home_path = getenv("HOME"); char *file_path = "/.toradora.db"; char database_path[MAX_PATH_LENGTH]; sqlite3 *DB; int db_exit = 0; int tab_exit = 0; char *message_error; if (home_path == NULL) { printf("[Error]: HOME environment variable not set.\n"); return -1; } snprintf(database_path, sizeof(database_path), "%s%s", home_path, file_path); db_exit = sqlite3_open(database_path, &DB); if (db_exit) { printf("[Error]: Database corrupted\n"); printf("[Help]: Delete database file and rerun the application"); return -1; } char *create_table = "CREATE TABLE IF NOT EXISTS tasks (" "id INTEGER PRIMARY KEY NOT NULL," "task TEXT NOT NULL," "status INTEGER NOT NULL DEFAULT 0," "created_at TEXT NOT NULL DEFAULT CURRENT_DATE" ");"; tab_exit = sqlite3_exec(DB, create_table, NULL, 0, &message_error); if (tab_exit != SQLITE_OK) { printf("[Error]: Table creation failed\n"); printf("%s\n", message_error); return -1; } switch (argc) { case 1: manifest_active_tasks(DB); break; case 2: if (0 == strcmp(argv[1], "-z")) { manifest_all_tasks(DB); } else { manifest_usage(); return 1; } break; case 3: if (0 == strcmp(argv[1], "-a")) { toradora_add_task(DB, argv[2]); } else if (0 == strcmp(argv[1], "-c")) { toradora_complete_task(DB, argv[2]); } else if (0 == strcmp(argv[1], "-h")) { manifest_usage(); } else { manifest_usage(); return 1; } break; case 4: if (0 == strcmp(argv[1], "-e")) { toradora_edit_task(DB, argv[2], argv[3]); } else { manifest_usage(); return 1; } break; default: manifest_usage(); return 1; } sqlite3_close(DB); return 0; }