diff options
| author | yuzu-eva <cafebabe@disroot.org> | 2025-06-08 14:33:02 +0200 |
|---|---|---|
| committer | yuzu-eva <cafebabe@disroot.org> | 2025-06-08 14:33:02 +0200 |
| commit | 390cbf31635951e46a49ed8657cd2a1635757f19 (patch) | |
| tree | 89f1d51b926017cc5bbcdd88ad503fb20743223c /src | |
| parent | b7e05ac5c2cb8f169b1cf66926faddcf7f15b7cc (diff) | |
changed project structure, adjusted Makefilerefactor
Diffstat (limited to 'src')
| -rw-r--r-- | src/dbhandling.c | 247 | ||||
| -rw-r--r-- | src/dbhandling.h | 30 | ||||
| -rw-r--r-- | src/enum.c | 11 | ||||
| -rw-r--r-- | src/enum.h | 29 | ||||
| -rw-r--r-- | src/main.c | 74 |
5 files changed, 391 insertions, 0 deletions
diff --git a/src/dbhandling.c b/src/dbhandling.c new file mode 100644 index 0000000..0a588ca --- /dev/null +++ b/src/dbhandling.c @@ -0,0 +1,247 @@ +#include "dbhandling.h" +#include "enum.h" + +void exit_with_error(sqlite3 *db, const char *msg) +{ + fprintf(stderr, "%s: %s\n", msg, sqlite3_errmsg(db)); + sqlite3_close(db); + exit(69); +} + +/* + TODO: write function for preparing the statement + Should take entry_t *entry, args_e target (,args_e mode?) + I already differentiate the mode in main, so passing it here + would be redundant. Find another solution. +*/ + +/*POSSIBLE OTHER SOLUTION: + TODO: try to get rid of args_e target and args_e mode and instead + use a flag. 3 possible tables with 3 different modes = 9 bits. Maybe + do 16bits in preparation for additional modes and tables. Not sure how + to go about setting them, though... that will be one hell of an + if-else block, lmao. +*/ + +void select_from_table(sqlite3 *db, args_e target, entry_t *entry) +{ + char *sql; + int rc; + int found = 0; + + const unsigned char *name, *author, *value, *status; + const char *type; + + printf("Name: "); + fgets(entry->name, MAX_NAME_LEN, stdin); + + // remove newline char, otherwise it messes with the query + entry->name[strcspn(entry->name, "\n")] = 0; + + char *query_param = malloc(strlen(entry->name)); + switch (target) { + case ANIME: + type = "Episode"; + sql = "SELECT * FROM anime WHERE name LIKE ?1 ORDER BY id;"; + break; + case MANGA: + type = "Chapter"; + sql = "SELECT * FROM manga WHERE name LIKE ?1 ORDER BY id;"; + break; + case BOOK: + type = "Chapter"; + sql = "SELECT * FROM book WHERE name LIKE ?1 OR author LIKE ?1 ORDER BY id;"; + break; + default: + fprintf(stderr, "table does not exist...\n"); + sqlite3_close(db); + exit(69); + } + + sqlite3_stmt *stmt; + snprintf(query_param, strlen(entry->name) + 2, "%s%%", entry->name); + + rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0); + if (rc != SQLITE_OK) { + exit_with_error(db, "failure fetching data: "); + } + + sqlite3_bind_text(stmt, 1, query_param, -1, SQLITE_TRANSIENT); + + if (target == BOOK) { + while(sqlite3_step(stmt) == SQLITE_ROW) { + name = sqlite3_column_text(stmt, 1); + author = sqlite3_column_text(stmt, 2); + value = sqlite3_column_text(stmt, 3); + status = sqlite3_column_text(stmt, 4); + printf("%s - %s, %s %s, %s\n", author, name, type, value, status); + found = 1; + } + } else { + while(sqlite3_step(stmt) == SQLITE_ROW) { + name = sqlite3_column_text(stmt, 1); + value = sqlite3_column_text(stmt, 2); + status = sqlite3_column_text(stmt, 3); + printf("%s, %s %s, %s\n", name, type, value, status); + found = 1; + } + } + + if (!found) { + printf("no entry found...\n"); + } + + sqlite3_finalize(stmt); + free(query_param); +} + +void update_entry(sqlite3 *db, args_e target, entry_t *entry) +{ + char *sql; + int rc; + int res; + + sqlite3_stmt *stmt; + + printf("Name: "); + fgets(entry->name, MAX_NAME_LEN, stdin); + entry->name[strcspn(entry->name, "\n")] = 0; + + // status is currently never NULL, so the if-else makes no sense + // would be addressed by the TODO: switching to flags + // i'll just keep it as is for now... + switch (target) { + case ANIME: + printf("Episode: "); + fgets(entry->value, MAX_VALUE_LEN, stdin); + entry->value[strcspn(entry->value, "\n")] = 0; + if (entry->status == NULL) { + sql = "UPDATE anime SET episode=?1 WHERE name=?2;"; + } else { + printf("Status: "); + fgets(entry->status, MAX_STATUS_LEN, stdin); + entry->status[strcspn(entry->status, "\n")] = 0; + sql = "UPDATE anime SET episode=?1, status=?2 WHERE name=?3;"; + } + break; + case MANGA: + printf("Chapter: "); + fgets(entry->value, MAX_VALUE_LEN, stdin); + entry->value[strcspn(entry->value, "\n")] = 0; + if (entry->status == NULL) { + sql = "UPDATE manga SET chapter=?1 WHERE name=?2;"; + } else { + printf("Status: "); + fgets(entry->status, MAX_STATUS_LEN, stdin); + entry->status[strcspn(entry->status, "\n")] = 0; + sql = "UPDATE manga SET chapter=?1, status=?2 WHERE name=?3;"; + } + break; + case BOOK: + printf("Chapter: "); + fgets(entry->value, MAX_VALUE_LEN, stdin); + entry->value[strcspn(entry->value, "\n")] = 0; + if (entry->status == NULL) { + sql = "UPDATE book SET chapter=?1 WHERE name=?2;"; + } else { + printf("Status: "); + fgets(entry->status, MAX_STATUS_LEN, stdin); + entry->status[strcspn(entry->status, "\n")] = 0; + sql = "UPDATE book SET chapter=?1, status=?2 WHERE name=?3;"; + } + break; + default: + fprintf(stderr, "table does not exist...\n"); + sqlite3_close(db); + exit(69); + } + + rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0); + if (rc != SQLITE_OK) { + exit_with_error(db, "failure fetching data: "); + } + + if (entry->status == NULL) { + sqlite3_bind_text(stmt, 1, entry->value, -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 2, entry->name, -1, SQLITE_STATIC); + } else { + sqlite3_bind_text(stmt, 1, entry->value, -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 2, entry->status, -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 3, entry->name, -1, SQLITE_STATIC); + } + + rc = sqlite3_step(stmt); + res = sqlite3_changes(db); + if (!res) { + printf("no entry found...\n"); + } + sqlite3_finalize(stmt); +} + +void add_entry(sqlite3 *db, args_e target, entry_t *entry) +{ + char *sql; + int rc; + + sqlite3_stmt *stmt; + + printf("Name: "); + fgets(entry->name, MAX_NAME_LEN, stdin); + entry->name[strcspn(entry->name, "\n")] = 0; + switch (target) { + case ANIME: + printf("Episode: "); + fgets(entry->value, MAX_VALUE_LEN, stdin); + entry->value[strcspn(entry->value, "\n")] = 0; + printf("Status: "); + fgets(entry->status, MAX_STATUS_LEN, stdin); + entry->status[strcspn(entry->status, "\n")] = 0; + sql = "INSERT INTO anime (name, episode, status) VALUES (?1, ?2, ?3);"; + break; + case MANGA: + printf("Chapter: "); + fgets(entry->value, MAX_VALUE_LEN, stdin); + entry->value[strcspn(entry->value, "\n")] = 0; + printf("Status: "); + fgets(entry->status, MAX_STATUS_LEN, stdin); + entry->status[strcspn(entry->status, "\n")] = 0; + sql = "INSERT INTO manga (name, chapter, status) VALUES (?1, ?2, ?3);"; + break; + case BOOK: + printf("Author: "); + fgets(entry->author, MAX_AUTHOR_LEN, stdin); + entry->author[strcspn(entry->author, "\n")] = 0; + printf("Chapter: "); + fgets(entry->value, MAX_VALUE_LEN, stdin); + entry->value[strcspn(entry->value, "\n")] = 0; + printf("Status: "); + fgets(entry->status, MAX_STATUS_LEN, stdin); + entry->status[strcspn(entry->status, "\n")] = 0; + sql = "INSERT INTO book (name, author, chapter, status) VALUES (?1, ?2, ?3, ?4);"; + break; + default: + fprintf(stderr, "table does not exist...\n"); + sqlite3_close(db); + exit(69); + } + + rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0); + if (rc != SQLITE_OK) { + exit_with_error(db, "failure fetching data: "); + } + + if (target == BOOK) { + sqlite3_bind_text(stmt, 1, entry->name, -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 2, entry->author, -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 3, entry->value, -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 4, entry->status, -1, SQLITE_STATIC); + } else { + sqlite3_bind_text(stmt, 1, entry->name, -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 2, entry->value, -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 3, entry->status, -1, SQLITE_STATIC); + } + + rc = sqlite3_step(stmt); + printf("Entry %s added!\n", entry->name); + sqlite3_finalize(stmt); +} diff --git a/src/dbhandling.h b/src/dbhandling.h new file mode 100644 index 0000000..fd21579 --- /dev/null +++ b/src/dbhandling.h @@ -0,0 +1,30 @@ +#ifndef _DBHANDLING_ +#define _DBHANDLING_ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sqlite3.h> + +#include "enum.h" + +#define MAX_NAME_LEN 128 +#define MAX_AUTHOR_LEN 64 +#define MAX_VALUE_LEN 16 +#define MAX_STATUS_LEN 16 + +typedef struct { + char *name; + char *author; + char *value; + char *status; +} entry_t; + + +void exit_with_error(sqlite3 *db, const char *msg); +void select_from_table(sqlite3 *db, args_e target, entry_t *entry); +void update_entry(sqlite3 *db, args_e target, entry_t *entry); +void add_entry(sqlite3 *db, args_e target, entry_t *entry); + +#endif diff --git a/src/enum.c b/src/enum.c new file mode 100644 index 0000000..ba0828f --- /dev/null +++ b/src/enum.c @@ -0,0 +1,11 @@ +#include "enum.h" + +args_e str2enum(const char *str) +{ + for (size_t i = 0; i < sizeof(conversion_args) / sizeof(conversion_args[0]); ++i) { + if (!strcmp(str, conversion_args[i].str)) + return conversion_args[i].val; + } + return -1; +} + diff --git a/src/enum.h b/src/enum.h new file mode 100644 index 0000000..65cde6f --- /dev/null +++ b/src/enum.h @@ -0,0 +1,29 @@ +#ifndef _ENUM_ +#define _ENUM_ + +#include <string.h> + +typedef enum { + GET, + SET, + ADD, + ANIME, + MANGA, + BOOK, +} args_e; + +static const struct { + args_e val; + const char *str; +} conversion_args [] = { + {GET, "get"}, + {SET, "set"}, + {ADD, "add"}, + {ANIME, "anime"}, + {MANGA, "manga"}, + {BOOK, "book"}, +}; + +args_e str2enum(const char *str); + +#endif diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..9dfe71d --- /dev/null +++ b/src/main.c @@ -0,0 +1,74 @@ +#include <stdint.h> + +#include "dbhandling.h" +#include "enum.h" + +const uint8_t PATH_MAX = 64; +const char *filepath = ".local/share/sqlite"; +const char *filename = "library.db"; + +void print_help(void) +{ + printf("\n"); + printf("usage: myal MODE TARGET NAME [EPISODE|CHAPTER] \n"); + printf("possible modes are: get|set|add \n"); + printf("possible targets are: anime|manga|book \n"); + printf("EXAMPLES: myal get anime %% | Prints all anime \n"); + printf(" myal set manga Murcielago 10 | Set chapter of " \ + "Murcielago to 10\n"); + printf("mode get is fuzzy; set and add have to match exactly \n"); + printf("See more examples in the readme. \n"); + printf("\n"); +} + +int main(int argc, char **argv) +{ + if (argc < 3) { + fprintf(stderr, "missing argument...\n"); + print_help(); + exit(69); + } + + args_e mode; + mode = str2enum(argv[1]); + args_e target; + target = str2enum(argv[2]); + entry_t *entry = malloc(sizeof(entry_t)); + entry->name = malloc(MAX_NAME_LEN); + entry->author = malloc(MAX_AUTHOR_LEN); + entry->value = malloc(MAX_VALUE_LEN); + entry->status = malloc(MAX_STATUS_LEN); + + char fullpath[PATH_MAX]; + snprintf(fullpath, PATH_MAX, "%s/%s/%s", getenv("HOME"), filepath, filename); + + sqlite3 *db; + int rc; + + rc = sqlite3_open(fullpath, &db); + + if (rc) { + exit_with_error(db, "Can't open database: "); + } + + switch (mode) { + case GET: + select_from_table(db, target, entry); + break; + case SET: + update_entry(db, target, entry); + break; + case ADD: + add_entry(db, target, entry); + break; + default: + fprintf(stderr, "unknown option...\n"); + print_help(); + sqlite3_close(db); + exit(69); + } + + sqlite3_close(db); + free(entry); + return 0; +} |
