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:
parent
d904118c4f
commit
9fc68e1b72
2
Makefile
2
Makefile
@ -1,4 +1,4 @@
|
|||||||
all: main.c
|
all: main.c
|
||||||
gcc main.c -lcurl -lcjson -o isbn -Wall
|
gcc main.c json.c curl.c -lcurl -lcjson -o isbn -Wall
|
||||||
clean:
|
clean:
|
||||||
rm isbn
|
rm isbn
|
||||||
|
67
curl.c
Normal file
67
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
curl.h
Normal file
40
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
json.c
Normal file
70
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
json.h
Normal file
40
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
|
206
main.c
206
main.c
@ -1,115 +1,27 @@
|
|||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
|
#include <cjson/cJSON.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.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 FILE_NAME "books.csv"
|
||||||
|
|
||||||
#define MAX_BUF_LEN 1024
|
#define MAX_BUF_LEN 1024
|
||||||
|
|
||||||
/**
|
void print_book(book_t* book)
|
||||||
* 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)
|
|
||||||
{
|
{
|
||||||
s->len = 0;
|
printf("ISBN: %s\n", book->isbn);
|
||||||
s->buf = malloc(s->len + 1);
|
printf("Title: %s\n", book->title);
|
||||||
|
printf("Author(s): %s\n", book->authors);
|
||||||
if (NULL == s->buf) {
|
printf("(First) Year of Publication: %d\n", book->year_of_publication);
|
||||||
fprintf(stderr, "malloc() failed\n"); exit(EXIT_FAILURE);
|
printf("Page length: %d\n", book->page_len);
|
||||||
}
|
|
||||||
s->buf[0] = '\0';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void write_to_file(book_t* book)
|
||||||
* 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)
|
|
||||||
{
|
{
|
||||||
FILE* file;
|
FILE* file;
|
||||||
int file_exists;
|
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
|
// 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);
|
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[])
|
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 isbn_buf[14]; // want to hold a max of 14 so we can hold up to ISBN13s
|
||||||
char options[2];
|
char options[2];
|
||||||
CURLcode res;
|
CURLcode res;
|
||||||
|
book_t new_book;
|
||||||
|
|
||||||
if (3 != argc) {
|
if (3 != argc) {
|
||||||
printf("Usage: isbn [isbn] [options]\n");
|
printf("Usage: isbn [isbn] [options]\n");
|
||||||
@ -227,6 +64,7 @@ int main(int argc, char* argv[])
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We must initialize cURL
|
* We must initialize cURL
|
||||||
*/
|
*/
|
||||||
@ -241,6 +79,11 @@ int main(int argc, char* argv[])
|
|||||||
* Grab the formatting options from argv
|
* Grab the formatting options from argv
|
||||||
*/
|
*/
|
||||||
snprintf(options, 2, "%s", argv[2]);
|
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
|
* Setup the output string
|
||||||
@ -257,16 +100,25 @@ int main(int argc, char* argv[])
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Now we want to parse the JSON input
|
* 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
|
* We need to free this string
|
||||||
*/
|
*/
|
||||||
free(get_output.buf);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user