Cleans up the code

Separates some functions into their own files
separates some big functions in to smaller ones to help improve the code
cleans up some stuff
This commit is contained in:
SuperNovaa41 2024-01-13 21:29:52 -05:00
parent d904118c4f
commit 9fc68e1b72
6 changed files with 247 additions and 178 deletions

View File

@ -1,4 +1,4 @@
all: main.c
gcc main.c -lcurl -lcjson -o isbn -Wall
gcc main.c json.c curl.c -lcurl -lcjson -o isbn -Wall
clean:
rm isbn

67
curl.c Normal file
View File

@ -0,0 +1,67 @@
#include <curl/curl.h>
#include <curl/easy.h>
#include <stdlib.h>
#include <string.h>
#include "curl.h"
#define BASE_URL_SIZE 38
void init_string(string* s)
{
s->len = 0;
s->buf = malloc(s->len + 1);
if (NULL == s->buf) {
fprintf(stderr, "malloc() failed!\n");
exit(EXIT_FAILURE);
}
s->buf[0] = '\0';
}
size_t writefunc(void* ptr, size_t size, size_t nmemb, string* s)
{
size_t new_len = s->len + (size * nmemb);
s->buf = realloc(s->buf, new_len + 1);
if (NULL == s->buf) {
fprintf(stderr, "realloc() failed!\n");
exit(EXIT_FAILURE);
}
memcpy(s->buf + s->len, ptr, size * nmemb);
s->buf[new_len] = '\0';
s->len = new_len;
return size * nmemb;
}
CURLcode perform_book_get(char* isbn, string* s)
{
CURL* handler;
char* base_url;
size_t finalurl_size = BASE_URL_SIZE + 15;
char finalurl[finalurl_size];
CURLcode result;
handler = curl_easy_init();
if (!handler) {
fprintf(stderr, "cURL failed to initialize!\n");
exit(EXIT_FAILURE);
}
base_url = "https://openlibrary.org/search.json?q=";
// Setup the URL for the request
snprintf(finalurl, finalurl_size, "%s%s", base_url, isbn);
curl_easy_setopt(handler, CURLOPT_URL, finalurl);
curl_easy_setopt(handler, CURLOPT_HTTPGET, 1L);
curl_easy_setopt(handler, CURLOPT_WRITEFUNCTION, writefunc);
curl_easy_setopt(handler, CURLOPT_WRITEDATA, s);
result = curl_easy_perform(handler);
// Always clean up
curl_easy_cleanup(handler);
return result;
}

40
curl.h Normal file
View File

@ -0,0 +1,40 @@
#ifndef CURL_H
#define CURL_H
/**
* struct string_t
* char* buf - The buffer containing the string data
* size_t len - The length of the buffer
*/
typedef struct string_t {
char* buf;
size_t len;
} string;
/**
* void init_string
* string* s - The string struct
*
* Initializes the string struct
*/
void init_string(string* s);
/**
* size_t writefunc
*
* The arguments from CURLOPT_WRITEFUNCTION
*
* Writes the cURL get into the string struct
*/
size_t writefunc(void* ptr, size_t size, size_t nmemb, string* s);
/**
* CURLcode perform_book_get
* char* isbn - The ISBN
* string* s - The string struct to place the GET output in
*
* Performs a GET request with the ISBN
*/
CURLcode perform_book_get(char* isbn, string* s);
#endif

70
json.c Normal file
View File

@ -0,0 +1,70 @@
#include <curl/curl.h>
#include <cjson/cJSON.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "curl.h"
#include "json.h"
#define MAX_BUF_LEN 1024
void check_valid_query(cJSON* numfound)
{
if (0 != numfound->valueint)
return;
fprintf(stderr, "No ISBN found!\n");
exit(EXIT_FAILURE);
}
void get_authors(cJSON* bookinfo, char authors[256])
{
char* temp_author;
size_t new_len;
cJSON* author_arr = cJSON_GetObjectItemCaseSensitive(bookinfo, "author_name")->child;
snprintf(authors, strlen(author_arr->valuestring) + 1, "%s", author_arr->valuestring);
author_arr = author_arr->next;
while (NULL != author_arr) {
// The plus 1 is for the \0, the plus 2 is for the ", "
new_len = strlen(authors) + strlen(author_arr->valuestring) + 1 + 2;
temp_author = malloc(sizeof(char) * new_len);
snprintf(temp_author, new_len, "%s, %s", authors, author_arr->valuestring);
memcpy(authors, temp_author, new_len);
free(temp_author);
author_arr = author_arr->next;
}
}
void parse_json(string* s, char* isbn, book_t* book)
{
char authors[MAX_BUF_LEN];
cJSON* json = cJSON_Parse(s->buf);
if (NULL == json) {
const char* error_ptr = cJSON_GetErrorPtr();
if (NULL != error_ptr)
fprintf(stderr, "JSON error: %s\n", error_ptr);
cJSON_Delete(json);
exit(EXIT_FAILURE);
}
check_valid_query(cJSON_GetObjectItemCaseSensitive(json, "numFound"));
cJSON* bookinfo = cJSON_GetObjectItemCaseSensitive(json, "docs")->child;
book->isbn = isbn;
book->title = cJSON_GetObjectItemCaseSensitive(bookinfo, "title")->valuestring;
book->year_of_publication = cJSON_GetObjectItemCaseSensitive(bookinfo, "first_publish_year")->valueint;
book->page_len = cJSON_GetObjectItemCaseSensitive(bookinfo, "number_of_pages_median")->valueint;
get_authors(bookinfo, authors);
// Need to malloc, because we need to copy authors into the book struct
book->authors = (char*) malloc(sizeof(char) * (strlen(authors) + 1));
memcpy(book->authors, authors, strlen(authors) + 1);
}

40
json.h Normal file
View File

@ -0,0 +1,40 @@
#ifndef JSON_H
#define JSON_H
#define MAX_BUF_LEN 1024
typedef struct book_t {
char* isbn;
char* title;
char* authors;
int year_of_publication;
int page_len;
} book_t;
/**
* void check_valid_query
* cJSON* numfound - The json entry that contains the numFound value
*
* Checks if there are any search results in this json entry
*/
void check_valid_query(cJSON* numfound);
/**
* void get_authors
* cJSON* bookinfo - The JSON entry that has all of the information about the book
* char* authors - The string to fill
*
* Takes the JSON entry from bookinfo and combines all of the authors into one final string
*/
void get_authors(cJSON* bookinfo, char* authors);
/**
* void parse_json
* string* s - The string struct
* char* isbn - The ISBN
* book_t* book - The struct to fill with book information
*
* Parses through the given JSON entry and gathers all of the information we need
*/
void parse_json(string* s, char* isbn, book_t* book);
#endif

206
main.c
View File

@ -1,115 +1,27 @@
#include <curl/curl.h>
#include <cjson/cJSON.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <cjson/cJSON.h>
#include "curl.h"
#include "json.h"
#define BASE_URL_SIZE 38
#define FILE_NAME "books.csv"
#define MAX_BUF_LEN 1024
/**
* struct string_t
* char* buf - The buffer containing the string data
* size_t len - The length of the buffer
*/
typedef struct string_t {
char* buf;
size_t len;
} string;
/**
* void init_string
* string* s - The string struct
*
* Initializes the string struct */
void init_string (string* s)
void print_book(book_t* book)
{
s->len = 0;
s->buf = malloc(s->len + 1);
if (NULL == s->buf) {
fprintf(stderr, "malloc() failed\n"); exit(EXIT_FAILURE);
}
s->buf[0] = '\0';
printf("ISBN: %s\n", book->isbn);
printf("Title: %s\n", book->title);
printf("Author(s): %s\n", book->authors);
printf("(First) Year of Publication: %d\n", book->year_of_publication);
printf("Page length: %d\n", book->page_len);
}
/**
* size_t writefunc
*
* The arguments come from CURLOPT_WRITEFUNCTION
*
* Writes the cURL get into the string struct
*/
size_t writefunc(void* ptr, size_t size, size_t nmemb, string* s)
{
size_t new_len = s->len + (size * nmemb);
s->buf = realloc(s->buf, new_len + 1);
if (NULL == s->buf) {
fprintf(stderr, "realloc() failed\n");
exit(EXIT_FAILURE);
}
memcpy(s->buf + s->len, ptr, size * nmemb);
s->buf[new_len] = '\0';
s->len = new_len;
return size * nmemb;
}
/**
* CURLcode perform_book_get
* char isbn_buf[14] - The ISBN
* string* s - The string struct to place the GET output in
*
* Perforrms a GET request with the ISBN
*/
CURLcode perform_book_get(char isbn_buf[14], string* s)
{
CURL* handler;
char *base_url;
size_t finalurl_size = BASE_URL_SIZE + 15;
char finalurl[finalurl_size];
CURLcode result;
handler = curl_easy_init();
if (!handler) {
fprintf(stderr, "cURL failed to initialize!\n");
exit(EXIT_FAILURE);
}
base_url = "https://openlibrary.org/search.json?q=";
/**
* Setup the URL for the request
*/
snprintf(finalurl, finalurl_size, "%s%s", base_url, isbn_buf);
curl_easy_setopt(handler, CURLOPT_URL, finalurl);
curl_easy_setopt(handler, CURLOPT_HTTPGET, 1L);
curl_easy_setopt(handler, CURLOPT_WRITEFUNCTION, writefunc);
curl_easy_setopt(handler, CURLOPT_WRITEDATA, s);
result = curl_easy_perform(handler);
// Always clean up
curl_easy_cleanup(handler);
return result;
}
void print_book(char* isbn, char* title, char* authors, int year, int page_len)
{
printf("ISBN: %s\n", isbn);
printf("Title: %s\n", title);
printf("Author(s): %s\n", authors);
printf("(First) Year of Publication: %d\n", year);
printf("Page length: %d\n", page_len);
}
void write_to_file(char* isbn, char* title, char* authors, int year, int page_len)
void write_to_file(book_t* book)
{
FILE* file;
int file_exists;
@ -128,93 +40,18 @@ void write_to_file(char* isbn, char* title, char* authors, int year, int page_le
}
// now we write the information
fprintf(file, "\"%s\",\"%s\",\"%s\",%d,%d\n", isbn, title, authors, year, page_len);
fprintf(file, "\"%s\",\"%s\",\"%s\",%d,%d\n",
book->isbn, book->title, book->authors, book->year_of_publication, book->page_len);
fclose(file);
}
/**
* void parse_json
* string* s - Pointer to the string struct
*
* Parses the JSON inside of s.buf and prints the information we're looking for
*/
void parse_json(string* s, char* options, char* isbn_buf)
{
char *title, *temp_author;
int year, page_len, new_len;
char authors[MAX_BUF_LEN];
cJSON* json = cJSON_Parse(s->buf);
if (NULL == json) {
const char* error_ptr = cJSON_GetErrorPtr();
if (NULL != error_ptr)
fprintf(stderr, "JSON error: %s\n", error_ptr);
cJSON_Delete(json);
exit(EXIT_FAILURE);
}
/**
* if there are no results, we should exit
* if theres too many, we should just treat it normally
*/
cJSON* numFound = cJSON_GetObjectItemCaseSensitive(json, "numFound");
if (0 == numFound->valueint) {
fprintf(stderr, "No ISBN found!\n");
exit(EXIT_FAILURE);
}
cJSON* docs = cJSON_GetObjectItemCaseSensitive(json, "docs");
cJSON* child = docs->child; // this is the JSON object that stores all of the books information
title = cJSON_GetObjectItemCaseSensitive(child, "title")->valuestring;
year = cJSON_GetObjectItemCaseSensitive(child, "first_publish_year")->valueint;
page_len = cJSON_GetObjectItemCaseSensitive(child, "number_of_pages_median")->valueint;
/**
* The author value is a linked list, so we want to loop through each value
*/
cJSON* authors_json = cJSON_GetObjectItemCaseSensitive(child, "author_name");
cJSON* authorarr = authors_json->child;
// we want to do this first out of the loop, because of formatting
snprintf(authors, strlen(authorarr->valuestring) + 1, "%s", authorarr->valuestring);
authorarr = authorarr->next;
while (NULL != authorarr) {
// The plus one is for the \0, the plus two is for the ", "
new_len = strlen(authors) + strlen(authorarr->valuestring) + 1 + 2;
/**
* So first we make a new string to hold the new string temporarily
*
* Then we want to add formatting by using the existing authors string
* along with the next string
*
* Then we memcpy the temp string into the original string
*/
temp_author = malloc(sizeof(char) * new_len);
snprintf(temp_author, new_len, "%s, %s", authors, authorarr->valuestring);
memcpy(authors, temp_author, new_len);
// Free since we malloc'd
free(temp_author);
authorarr = authorarr->next;
}
if (0 == strcmp(options, "r"))
print_book(isbn_buf, title, authors, year, page_len);
else if (0 == strcmp(options, "w"))
write_to_file(isbn_buf, title, authors, year, page_len);
else
fprintf(stderr, "Improper option provided!");
}
int main(int argc, char* argv[])
{
char isbn_buf[14]; // want to hold a max of 14 so we can hold up to ISBN13s
char options[2];
CURLcode res;
book_t new_book;
if (3 != argc) {
printf("Usage: isbn [isbn] [options]\n");
@ -227,6 +64,7 @@ int main(int argc, char* argv[])
return EXIT_FAILURE;
}
/**
* We must initialize cURL
*/
@ -241,6 +79,11 @@ int main(int argc, char* argv[])
* Grab the formatting options from argv
*/
snprintf(options, 2, "%s", argv[2]);
if (!(('w' == options[0]) || ('r' == options[0]))) {
fprintf(stderr, "Invalid option submitted!\n");
return EXIT_FAILURE;
}
/**
* Setup the output string
@ -257,16 +100,25 @@ int main(int argc, char* argv[])
return EXIT_FAILURE;
}
/**
* Now we want to parse the JSON input
*/
parse_json(&get_output, options, isbn_buf);
parse_json(&get_output, isbn_buf, &new_book);
/**
* We need to free this string
*/
free(get_output.buf);
/**
* NOW we either print or save the book
*/
if (options[0] == 'w')
write_to_file(&new_book);
else if (options[0] == 'r')
print_book(&new_book);
return 0;
}