From ba2acb23ecaeb6b455775ad5bb3ed9a07d021e33 Mon Sep 17 00:00:00 2001 From: SuperNovaa41 Date: Wed, 31 Jan 2024 11:53:09 -0500 Subject: [PATCH] CSV is GONE, time for SQLITE CSV sucks and Datbases are the proper way to be doing stuff like this not to mention, it ditches a lot of potentially unsafe code because we're no longer doing lots of file operations --- Makefile | 2 +- build/books.db | Bin 0 -> 8192 bytes src/csv.c | 132 ------------------------------------------------- src/csv.h | 38 -------------- src/db.c | 102 ++++++++++++++++++++++++++++++++++++++ src/db.h | 25 ++++++++++ src/main.c | 31 +++++++----- 7 files changed, 147 insertions(+), 183 deletions(-) create mode 100644 build/books.db delete mode 100644 src/csv.c delete mode 100644 src/csv.h create mode 100644 src/db.c create mode 100644 src/db.h diff --git a/Makefile b/Makefile index 321fa65..902d6b4 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ all: src/*.c - gcc src/main.c src/json.c src/curl.c src/csv.c -lcurl -lcjson -o isbn -Wall + gcc src/main.c src/json.c src/curl.c src/db.c -lsqlite3 -lcurl -lcjson -o isbn -Wall mkdir -p build mv isbn build clean: diff --git a/build/books.db b/build/books.db new file mode 100644 index 0000000000000000000000000000000000000000..f845cadb8ab9a2a6703d4a351aa8b73dbcc540e8 GIT binary patch literal 8192 zcmeI#%}(Pm5CC8&Akhor=hEw}H~>;hBK%m`}l$FmVP^a22({3M;W5^TMV|n>rIyo?xM6otDV;NZpL`B9>yz ztxy?U2mSLF(S8ga67sfCePes>N&?GzS|Jj)OQDGbhz#3}#p0jagQ r`RjRORbAM$RgReyvF5sLE1h_;CnnyX-#y>&c6SEt+dNr%b6(y7ClHHf literal 0 HcmV?d00001 diff --git a/src/csv.c b/src/csv.c deleted file mode 100644 index 504142f..0000000 --- a/src/csv.c +++ /dev/null @@ -1,132 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "curl.h" -#include "json.h" -#include "csv.h" - -#define MAX_BUFFER_SIZE 1024 - -int get_next_id() -{ - size_t i; - char buffer[MAX_BUFFER_SIZE]; - FILE* csv; - char id[MAX_BUFFER_SIZE]; - - csv = fopen(FILE_NAME, "r"); - - while (fgets(buffer, sizeof(buffer), csv)); - - i = 0; - while(buffer[i] != ',') - i++; - - strncpy(id, buffer, i); - - return atoi(id) + 1; -} - -void update_line(char** line, int new_id) -{ - int i; - char* buffer; - for (i = 0; i < MAX_BUFFER_SIZE; i++) { - if ((*line)[i] == ',') - break; - } - - if (i == MAX_BUFFER_SIZE - 1) { - fprintf(stderr, "There was an error in the file: %s\n", FILE_NAME); - exit(EXIT_FAILURE); - } - - buffer = malloc(sizeof(char) * MAX_BUFFER_SIZE); - strncpy(buffer, (*line) + i, MAX_BUFFER_SIZE); - - snprintf(*line, MAX_BUFFER_SIZE, "%d%s", new_id, buffer); - free(buffer); -} - -void remove_line_from_file(int id_to_remove) -{ - int file_exists, line_count; - FILE* csv; - FILE* new_csv; - char* line = NULL; - size_t line_size = MAX_BUFFER_SIZE; - - file_exists = access(FILE_NAME, F_OK); - if (0 != file_exists) { - fprintf(stderr, "%s does not exist!\n", FILE_NAME); - exit(EXIT_FAILURE); - } - - csv = fopen(FILE_NAME, "r"); - if (NULL == csv) { - fprintf(stderr, "Failed to open %s!\n", FILE_NAME); - exit(EXIT_FAILURE); - } - - new_csv = fopen("temp.csv", "w"); - if (NULL == new_csv) { - fprintf(stderr, "Failed to create temp.csv!\n"); - exit(EXIT_FAILURE); - } - - line_count = 0; - while(getline(&line, &line_size, csv) != -1) { - if (id_to_remove > line_count) { - fprintf(new_csv, "%s", line); - } else if (id_to_remove < line_count) { - update_line(&line, line_count - 1); - fprintf(new_csv, "%s", line); - } - line_count++; - } - fclose(new_csv); - fclose(csv); - - free(line); // man pages say this should be freed - - remove(FILE_NAME); - rename("temp.csv", FILE_NAME); // new csv is now the original file, without that line -} - -void write_to_file(book_t* book) -{ - FILE* file; - int file_exists; - int book_id; - - /** - * We want to check if the file exists - * if it doesnt, we create a new one - * otherwise, we write to the existing one - */ - file_exists = access(FILE_NAME, F_OK); - if (0 != file_exists) { - file = fopen(FILE_NAME, "w"); - // write the csv headers to the file since we're making it - fprintf(file, "id,isbn,title,authors,imageurl,year-of-publication,page-length\n"); - book_id = 1; - } else { - file = fopen(FILE_NAME, "a"); - book_id = get_next_id(); - } - - if (NULL == file) { - fprintf(stderr, "Failed to open %s!\n", FILE_NAME); - exit(EXIT_FAILURE); - } - - // now we write the information - fprintf(file, "%d,\"%s\",\"%s\",\"%s\",\"%s\",%d,%d\n", - book_id, book->isbn, book->title, book->authors, book->image_url, book->year_of_publication, book->page_len); - - fclose(file); -} diff --git a/src/csv.h b/src/csv.h deleted file mode 100644 index 4982952..0000000 --- a/src/csv.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef CSV_H -#define CSV_H - -#define FILE_NAME "books.csv" - -/** - * int get_next_id - * - * Returns the next available ID so that we know what to assign to the book - */ -int get_next_id(); - -/** - * void write_to_file - * boot_t* book - A pointer to the book information struct - * - * Writes the book information to a CSV file - */ -void write_to_file(book_t* book); - -/** - * void remove_line_from_file - * int id_to_remove - The book ID that we don't want anymore - * - * Removes a book from the CSV file - */ -void remove_line_from_file(int id_to_remove); - -/** - * void update_line - * char** line - Pointer to the book entry string - * int new_id - The new ID that should be placed into this book entry - * - * Takes a book entry and changes the ID to the given one - */ -void update_line(char** line, int new_id); - -#endif diff --git a/src/db.c b/src/db.c new file mode 100644 index 0000000..38a6a62 --- /dev/null +++ b/src/db.c @@ -0,0 +1,102 @@ +#include +#include +#include +#include +#include +#include + + +#include "curl.h" +#include "json.h" +#include "db.h" + +void do_db_entry(enum DB_OPTIONS option, ...) +{ + int rc; + sqlite3* db; + va_list args; + + rc = sqlite3_open("books.db", &db); + if (rc != SQLITE_OK) { + fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db)); + sqlite3_close(db); + + exit(EXIT_FAILURE); + } + + setup_db(db); + + va_start(args, option); + if (ADD == option) { + add_to_db(va_arg(args, book_t*), db); + } else if (REMOVE == option) { + remove_from_db(va_arg(args, int), db); + } + va_end(args); + + sqlite3_close(db); +} + +void setup_db(sqlite3* db) +{ + int rc; + char* err_msg = 0; + char* sql; + + sql = "CREATE TABLE IF NOT EXISTS books (isbn TEXT, title TEXT, authors TEXT, imageurl TEXT, year_of_publication YEAR, page_length UNSIGNED INT);"; + + rc = sqlite3_exec(db, sql, 0, 0, &err_msg); + + if (rc != SQLITE_OK) { + fprintf(stderr, "SQL error: %s\n", err_msg); + + sqlite3_free(err_msg); + sqlite3_close(db); + + exit(EXIT_FAILURE); + } + +} + +void add_to_db(book_t* book, sqlite3* db) +{ + char* sql; + int asp_err, rc; + char* err_msg = 0; + + asp_err = asprintf(&sql, "INSERT INTO books (isbn, title, authors, imageurl, year_of_publication, page_length) VALUES(\"%s\", \"%s\", \"%s\", \"%s\", %d, %d);", book->isbn, book->title, book->authors, book->image_url, book->year_of_publication, book->page_len); + if (-1 == asp_err) { + fprintf(stderr, "asprintf failed!\n"); + exit(EXIT_FAILURE); + } + + rc = sqlite3_exec(db, sql, 0, 0, &err_msg); + if (rc != SQLITE_OK) { + fprintf(stderr, "SQL error: %s\n", err_msg); + sqlite3_free(err_msg); + sqlite3_close(db); + exit(EXIT_FAILURE); + } +} + +void remove_from_db(int id, sqlite3* db) +{ + char* sql; + int asp_err, rc; + char* err_msg = 0; + + asp_err = asprintf(&sql, "DELETE FROM books WHERE id = %d;", id); + if (-1 == asp_err) { + fprintf(stderr, "asprintf failed!\n"); + exit(EXIT_FAILURE); + } + + rc = sqlite3_exec(db, sql, 0, 0, &err_msg); + if (rc != SQLITE_OK) { + fprintf(stderr, "SQL error: %s\n", err_msg); + sqlite3_free(err_msg); + sqlite3_close(db); + exit(EXIT_FAILURE); + } +} + diff --git a/src/db.h b/src/db.h new file mode 100644 index 0000000..389c71d --- /dev/null +++ b/src/db.h @@ -0,0 +1,25 @@ +#ifndef DH_H +#define DH_H + +enum DB_OPTIONS { + ADD, + REMOVE +}; + +/** + * void do_db_entry + * + * enum DB_OPTIONS option - The type of transaction being made to the DB + * VA args + * - Expects book_t if option is ADD + * - Expects int if option is REMOVE + */ +void do_db_entry(enum DB_OPTIONS option, ...); + +void setup_db(sqlite3* db); + +void add_to_db(book_t* book, sqlite3* db); + +void remove_from_db(int id, sqlite3* db); + +#endif diff --git a/src/main.c b/src/main.c index d52b938..4c6e78c 100644 --- a/src/main.c +++ b/src/main.c @@ -3,11 +3,12 @@ #include #include #include +#include #include #include "curl.h" #include "json.h" -#include "csv.h" +#include "db.h" #define MAX_BUF_LEN 1024 @@ -49,7 +50,7 @@ void do_ISBN_get(char* argv[]) // Now we want to parse the JSON input parse_json(&get_output, isbn_buf, &new_book); - write_to_file(&new_book); + do_db_entry(ADD, &new_book); // we need to free these strings free(get_output.buf); @@ -57,18 +58,24 @@ void do_ISBN_get(char* argv[]) free(new_book.image_url); } +void print_help_menu(char* program) +{ + printf("%s - An ISBN lookup tool.\n", program); + printf("Author: Nathan Singer\n"); + + puts("\n"); + + puts("--help - Shows this message."); + puts("[isbn] -- Attempts to download a book from the given ISBN-10 or ISBN-13 input."); + puts("remove [id] -- Removes a book with the given ID from the book database."); +} + + void process_args(char* argv[]) { int id; if (0 == strcmp(argv[1], "--help")) { - printf("%s - An ISBN lookup tool.\n", argv[0]); - printf("Author: Nathan Singer\n"); - - puts("\n"); - - puts("--help - Shows this message."); - puts("[isbn] -- Attempts to download a book from the given ISBN-10 or ISBN-13 input."); - puts("remove [id] -- Removes a book with the given ID from the book database."); + print_help_menu(argv[0]); } else if (0 == strcmp(argv[1], "remove")) { if (NULL == argv[2]) { printf("Not enough arguments! Try typing %s --help\n", argv[0]); @@ -81,8 +88,7 @@ void process_args(char* argv[]) printf("Invalid book ID given!\n"); exit(EXIT_FAILURE); } - - remove_line_from_file(id); + do_db_entry(REMOVE, id); } else { // lets assume its an ISBN and let the other functions fail if its not do_ISBN_get(argv); @@ -99,6 +105,7 @@ int main(int argc, char* argv[]) } process_args(argv); + return 0; }