summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dbhandling.c247
-rw-r--r--src/dbhandling.h30
-rw-r--r--src/enum.c11
-rw-r--r--src/enum.h29
-rw-r--r--src/main.c74
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;
+}