restructures the code
This commit is contained in:
67
src/curl.c
Normal file
67
src/curl.c
Normal 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
src/curl.h
Normal file
40
src/curl.h
Normal 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
src/json.c
Normal file
70
src/json.c
Normal 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
src/json.h
Normal file
40
src/json.h
Normal 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
|
124
src/main.c
Normal file
124
src/main.c
Normal file
@ -0,0 +1,124 @@
|
||||
#include <curl/curl.h>
|
||||
#include <cjson/cJSON.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "curl.h"
|
||||
#include "json.h"
|
||||
|
||||
#define FILE_NAME "books.csv"
|
||||
|
||||
#define MAX_BUF_LEN 1024
|
||||
|
||||
void print_book(book_t* book)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
void write_to_file(book_t* book)
|
||||
{
|
||||
FILE* file;
|
||||
int file_exists;
|
||||
|
||||
/**
|
||||
* 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");
|
||||
fprintf(file, "isbn,title,authors,year of publication,page length\n");
|
||||
} else {
|
||||
file = fopen(FILE_NAME, "a");
|
||||
}
|
||||
|
||||
// now we write the information
|
||||
fprintf(file, "\"%s\",\"%s\",\"%s\",%d,%d\n",
|
||||
book->isbn, book->title, book->authors, book->year_of_publication, book->page_len);
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
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");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
size_t input_len = strlen(argv[1]);
|
||||
if (!(13 == input_len || 10 == input_len)) {
|
||||
fprintf(stderr, "Invalid ISBN submitted!");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* We must initialize cURL
|
||||
*/
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
|
||||
/**
|
||||
* Grab the ISBN from argv
|
||||
*/
|
||||
snprintf(isbn_buf, 14, "%s", argv[1]);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
string get_output;
|
||||
init_string(&get_output);
|
||||
|
||||
/**
|
||||
* Perform the get request
|
||||
*/
|
||||
res = perform_book_get(isbn_buf, &get_output);
|
||||
if (0 != res) {
|
||||
fprintf(stderr, "Failed to perform the get request!\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Now we want to parse the JSON input
|
||||
*/
|
||||
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;
|
||||
}
|
Reference in New Issue
Block a user