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
This commit is contained in:
parent
43e69fa342
commit
ba2acb23ec
2
Makefile
2
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:
|
||||
|
BIN
build/books.db
Normal file
BIN
build/books.db
Normal file
Binary file not shown.
132
src/csv.c
132
src/csv.c
@ -1,132 +0,0 @@
|
||||
#include <cjson/cJSON.h>
|
||||
#include <curl/curl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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);
|
||||
}
|
38
src/csv.h
38
src/csv.h
@ -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
|
102
src/db.c
Normal file
102
src/db.c
Normal file
@ -0,0 +1,102 @@
|
||||
#include <stdio.h>
|
||||
#include <sqlite3.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <cjson/cJSON.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
|
25
src/db.h
Normal file
25
src/db.h
Normal file
@ -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
|
23
src/main.c
23
src/main.c
@ -3,11 +3,12 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sqlite3.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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,11 +58,9 @@ void do_ISBN_get(char* argv[])
|
||||
free(new_book.image_url);
|
||||
}
|
||||
|
||||
void process_args(char* argv[])
|
||||
void print_help_menu(char* program)
|
||||
{
|
||||
int id;
|
||||
if (0 == strcmp(argv[1], "--help")) {
|
||||
printf("%s - An ISBN lookup tool.\n", argv[0]);
|
||||
printf("%s - An ISBN lookup tool.\n", program);
|
||||
printf("Author: Nathan Singer\n");
|
||||
|
||||
puts("\n");
|
||||
@ -69,6 +68,14 @@ void process_args(char* argv[])
|
||||
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")) {
|
||||
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);
|
||||
@ -100,5 +106,6 @@ int main(int argc, char* argv[])
|
||||
|
||||
process_args(argv);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user