aboutsummarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorAntony Kellermann2018-05-29 20:53:07 -0400
committerAntony Kellermann2018-05-29 20:53:07 -0400
commiteedb9c51064050dc7021a97560d7ff8c2f4eb821 (patch)
treebdfa4add22f56da0d5b5802136e283de4a2ce1d0
parent4638bd317573fa8a8cd9ecebb822196f84c871d0 (diff)
downloadaur-eedb9c51064050dc7021a97560d7ff8c2f4eb821.tar.gz
Added News struct to easily store news and moved news API call as a threadable function to api.c
-rw-r--r--api.c84
-rw-r--r--api.h20
-rw-r--r--info.c69
-rw-r--r--info.h4
-rw-r--r--main.c6
5 files changed, 119 insertions, 64 deletions
diff --git a/api.c b/api.c
index 0ad300054bab..9af23494d74f 100644
--- a/api.c
+++ b/api.c
@@ -1,5 +1,11 @@
#include "api.h"
+News* api_news_init(void) {
+ News* pNews = malloc(sizeof(News));
+ pointer_alloc_check(pNews);
+ return pNews;
+}
+
Info* api_info_init(void) {
Info* pInfo = malloc(sizeof(Info));
pointer_alloc_check(pInfo);
@@ -10,7 +16,7 @@ Info* api_info_init(void) {
.gross_profit = EMPTY, .cash = EMPTY, .debt = EMPTY, .eps = {EMPTY, EMPTY, EMPTY, EMPTY},
.fiscal_period[0][0] = '\0', .fiscal_period[1][0] = '\0', .fiscal_period[2][0] = '\0',
.fiscal_period[3][0] = '\0', .eps_year_ago = {EMPTY, EMPTY, EMPTY, EMPTY}, .change_1d = EMPTY,
- .change_7d = EMPTY, .change_30d = EMPTY, .points = NULL
+ .change_7d = EMPTY, .change_30d = EMPTY, .points = NULL, .articles = NULL, .num_articles = EMPTY
};
return pInfo;
}
@@ -197,6 +203,60 @@ void* iex_store_chart(void* vpInfo) {
return NULL;
}
+void* iex_store_news(void* vpInfo) {
+ Info* symbol_info = vpInfo;
+ if (symbol_info->symbol[0] == '\0')
+ return NULL;
+
+ if (symbol_info->num_articles == EMPTY)
+ symbol_info->num_articles = DEFAULT_NUM_ARTICLES;
+
+ char iex_api_string[URL_MAX_LENGTH];
+ sprintf(iex_api_string, "https://api.iextrading.com/1.0/stock/%s/news/last/%d", symbol_info->symbol,
+ symbol_info->num_articles);
+ String* pString = api_curl_data(iex_api_string);
+ if (pString == NULL)
+ return NULL;
+
+ Json* jobj = json_tokener_parse(pString->data), * idx;
+ if (jobj == NULL) { // Invalid symbol
+ string_destroy(&pString);
+ return NULL;
+ }
+ size_t len = json_object_array_length(jobj);
+ if (len < (unsigned) symbol_info->num_articles)
+ symbol_info->num_articles = (int)len;
+
+ symbol_info->articles = malloc(sizeof(News*) * symbol_info->num_articles);
+ pointer_alloc_check(symbol_info->articles);
+
+ for (int i = 0; i < symbol_info->num_articles; i++) {
+ symbol_info->articles[i] = api_news_init();
+ pointer_alloc_check(symbol_info->articles[i]);
+ idx = json_object_array_get_idx(jobj, (size_t) i);
+ strcpy(symbol_info->articles[i]->headline, json_object_get_string(json_object_object_get(idx, "headline")));
+ strcpy(symbol_info->articles[i]->source, json_object_get_string(json_object_object_get(idx, "source")));
+ strncpy(symbol_info->articles[i]->date, json_object_get_string(json_object_object_get(idx, "datetime")), 10);
+ symbol_info->articles[i]->date[10] = '\0';
+ strcpy(symbol_info->articles[i]->summary, json_object_get_string(json_object_object_get(idx, "summary")));
+ strip_tags(symbol_info->articles[i]->summary); // Summary will be html formatted, so must strip tags
+ strcpy(symbol_info->articles[i]->url, json_object_get_string(json_object_object_get(idx, "url")));
+ strcpy(symbol_info->articles[i]->related, json_object_get_string(json_object_object_get(idx, "related")));
+ int related_num = 0;
+ for (size_t j = 0; j < strlen(symbol_info->articles[i]->related); j++) { // List only first five related symbols
+ if (symbol_info->articles[i]->related[j] == ',')
+ related_num++;
+ if (related_num == 5) {
+ symbol_info->articles[i]->related[j] = '\0';
+ break;
+ }
+ }
+ }
+ json_object_put(jobj);
+ string_destroy(&pString);
+ return NULL;
+}
+
void* morningstar_store_info(void* vpInfo) {
Info* symbol_info = vpInfo;
char today_str[DATE_MAX_LENGTH], five_year_str[DATE_MAX_LENGTH], morningstar_api_string[URL_MAX_LENGTH];
@@ -273,15 +333,15 @@ void* coinmarketcap_store_info(void* vpInfo) {
Info* iex_get_info(const char* symbol) {
Info* symbol_info = api_info_init();
strcpy(symbol_info->symbol, symbol);
- pthread_t threads[5];
- void* (*funcs[5]) (void*) = {
- iex_store_company, iex_store_quote, iex_store_stats, iex_store_earnings, iex_store_chart
+ pthread_t threads[6];
+ void* (*funcs[6]) (void*) = {
+ iex_store_company, iex_store_quote, iex_store_stats, iex_store_earnings, iex_store_chart, iex_store_news
};
- for (int i = 0; i < 5; i++)
+ for (int i = 0; i < 6; i++)
if (pthread_create(&threads[i], NULL, funcs[i], symbol_info))
EXIT_MSG("Error creating thread!");
- for (int i = 0; i < 5; i++)
+ for (int i = 0; i < 6; i++)
if (pthread_join(threads[i], NULL))
EXIT_MSG("Error joining thread!");
@@ -357,8 +417,18 @@ Info* api_get_info(const char* symbol) {
return coinmarketcap_get_info(symbol);
}
+void api_news_destroy(News** phNews) {
+ free(*phNews);
+ *phNews = NULL;
+}
+
void api_info_destroy(Info** phInfo) {
- free((*phInfo)->points);
+ Info* pInfo = *phInfo;
+ free(pInfo->points);
+ if (pInfo->articles != NULL)
+ for (int i = 0; i < pInfo->num_articles; i++)
+ api_news_destroy(&pInfo->articles[i]);
+ free(pInfo->articles);
free(*phInfo);
*phInfo = NULL;
} \ No newline at end of file
diff --git a/api.h b/api.h
index 9ad31595b9a9..5f2009805802 100644
--- a/api.h
+++ b/api.h
@@ -14,6 +14,7 @@
#define URL_MAX_LENGTH 2048
#define INFO_TEXT_MAX 2048
#define EMPTY (-999)
+#define DEFAULT_NUM_ARTICLES 3
#include <stddef.h>
#include <curl/curl.h>
@@ -21,6 +22,15 @@
#include <pthread.h>
#include "string-tick.h"
+typedef struct news_article {
+ char headline[INFO_TEXT_MAX];
+ char source[INFO_TEXT_MAX];
+ char date[DATE_MAX_LENGTH];
+ char summary[INFO_TEXT_MAX];
+ char url[URL_MAX_LENGTH];
+ char related[INFO_TEXT_MAX];
+} News;
+
typedef struct info {
/* Company */
char symbol[SYMBOL_MAX_LENGTH]; // ex. AAPL
@@ -65,8 +75,14 @@ typedef struct info {
double change_7d; // Percent change since 7 days ago
double change_30d; // Percent change since 30 days ago
double* points; // Array of one price per day, startings five years previously
+
+ /* News */
+ News** articles; // Array of News pointers
+ int num_articles; // Number of News pointers in array
} Info;
+News* api_news_init(void);
+
/**
* Allocates an Info struct and returns a pointer to it. All numbers are set to EMPTY, all strings are NULL
* terminated at length 0, and all pointers are set to NULL.
@@ -137,6 +153,8 @@ void* iex_store_earnings(void* vpInfo);
*/
void* iex_store_chart(void* vpInfo);
+void* iex_store_news(void* vpInfo);
+
/**
* Designed for threading
*
@@ -204,6 +222,8 @@ Info* api_get_check_info(const char* symbol);
*/
Info* api_get_info(const char* symbol);
+void api_news_destroy(News** phNews);
+
/**
* Destroys Info object and frees memory. Sets the pointer to the Info to NULL
* @param phInfo the Info to destroy
diff --git a/info.c b/info.c
index d97e2f2afee5..9505521fbc3b 100644
--- a/info.c
+++ b/info.c
@@ -20,7 +20,7 @@ void symbol_print_info(const char* symbol) {
time_t time = symbol_info->intraday_time / 1000; // divide into second instead of milliseconds
struct tm* ts = localtime(&time);
strftime(time_str, 32, "%F %T", ts);
- mvprintw(0, 13, "%s", time_str);
+ mvprintw(0, 18, "%s", time_str);
}
mvprintw(0, (int) (28 + strlen(symbol_info->name) + strlen(symbol_info->symbol)), "24H 7D ");
if (symbol_info->change_30d != EMPTY)
@@ -77,7 +77,7 @@ void symbol_print_info(const char* symbol) {
else mvwprintw(company_win, getcury(company_win), getmaxx(company_win) / 2, "Volume unavailable.\n");
if (symbol_info->pe_ratio != EMPTY)
- wprintw(company_win, "P/E Ratio: %ld", symbol_info->pe_ratio);
+ wprintw(company_win, "P/E Ratio: %lf", symbol_info->pe_ratio);
else wprintw(company_win, "P/E Ratio unavailable.");
if (symbol_info->div_yield != EMPTY)
@@ -109,65 +109,30 @@ void symbol_print_info(const char* symbol) {
WINDOW* graph_win = newwin(GRAPH_HEIGHT, GRAPH_WIDTH, GRAPH_Y, GRAPH_X);
graph_printw(graph_win, symbol_info, NULL);
}
- while (getch() != 'q');
endwin();
api_info_destroy(&symbol_info);
}
-void symbol_print_news(const char* symbol, int num_articles) {
- if (num_articles > 50)
+void news_print(const char* symbol, int num_articles) {
+ if (num_articles > 50 || num_articles < 1)
RET_MSG("You cannot request more than 50 articles.");
- char iex_api_string[URL_MAX_LENGTH];
- sprintf(iex_api_string, "https://api.iextrading.com/1.0/stock/%s/news/last/%d", symbol, num_articles);
- String* pString = api_curl_data(iex_api_string);
- if (pString == NULL)
- return;
-
- if (strcmp(pString->data, "Unknown symbol") == 0) { // Invalid symbol
- string_destroy(&pString);
- RET_MSG("Invalid symbol.");
- }
-
- Json* jobj = json_tokener_parse(pString->data);
- size_t len = json_object_array_length(jobj);
- if (len == 0) {
- json_object_put(jobj);
- string_destroy(&pString);
- RET_MSG("No articles available.");
- }
-
- Json* idx;
- const char* headline, * source, *url;
- char date[DATE_MAX_LENGTH];
- for (size_t i = 0; i < len; i++) {
- idx = json_object_array_get_idx(jobj, i);
- headline = json_object_get_string(json_object_object_get(idx, "headline")); // Headline
- source = json_object_get_string(json_object_object_get(idx, "source")); // Source
- strncpy(date, json_object_get_string(json_object_object_get(idx, "datetime")), 10); // Date
- date[10] = '\0'; // null terminate date before time
- char summary[strlen(json_object_get_string(json_object_object_get(idx, "summary")))]; // Summary
- strcpy(summary, json_object_get_string(json_object_object_get(idx, "summary")));
- strip_tags(summary); // Summary will be html formatted, so must strip tags
- url = json_object_get_string(json_object_object_get(idx, "url")); // URL
- char related[strlen(json_object_get_string(json_object_object_get(idx, "related")))]; // Related
- strcpy(related, json_object_get_string(json_object_object_get(idx, "related")));
- int related_num = 0;
- for (size_t j = 0; j < strlen(related); j++) { // List only first five related symbols
- if (related[j] == ',')
- related_num++;
- if (related_num == 5) {
- related[j] = '\0';
- break;
- }
- }
- printf("%s | %s | %s\n%s\n%s | Related: %s\n\n", headline, source, date, summary, url, related);
+ Info* symbol_info = api_info_init();
+ strcpy(symbol_info->symbol, symbol);
+ symbol_info->num_articles = num_articles;
+ iex_store_news(symbol_info);
+ if (symbol_info->articles == NULL) {
+ api_info_destroy(&symbol_info);
+ RET_MSG("Invalid symbol");
}
- json_object_put(jobj);
- string_destroy(&pString);
+ for (int i = 0; i < symbol_info->num_articles; i++)
+ printf("%s | %s | %s\n%s\n%s | Related: %s\n\n",
+ symbol_info->articles[i]->headline, symbol_info->articles[i]->source, symbol_info->articles[i]->date,
+ symbol_info->articles[i]->summary, symbol_info->articles[i]->url, symbol_info->articles[i]->related);
+ api_info_destroy(&symbol_info);
}
-void symbol_graph(const char* symbol, const char* symbol2) {
+void graph_print(const char* symbol, const char* symbol2) {
Info* symbol_info = api_get_check_info(symbol), *symbol_info2 = NULL;
if (symbol_info == NULL)
RET_MSG("Invalid symbol")
diff --git a/info.h b/info.h
index 17679ca7500d..a2c28b1dfeb3 100644
--- a/info.h
+++ b/info.h
@@ -47,14 +47,14 @@ void symbol_print_info(const char* symbol);
* @param symbol stock/etf symbol
* @param num_articles number of articles to print (max 50)
*/
-void symbol_print_news(const char* symbol, int num_articles);
+void news_print(const char* symbol, int num_articles);
/**
* Graphs a security in stdscr. If symbol2 is not NULL, also graphs that security.
* @param symbol security to graph
* @param symbol2 optional second security
*/
-void symbol_graph(const char* symbol, const char* symbol2);
+void graph_print(const char* symbol, const char* symbol2);
/**
* -- Main input loop for graphing --
diff --git a/main.c b/main.c
index 5fead678d7dc..ed9dc7e6acb6 100644
--- a/main.c
+++ b/main.c
@@ -32,7 +32,7 @@ int main(int argc, char* argv[]) {
int num_articles = 3; // Default
if (argc == 4)
num_articles = (int) strtol(argv[3], NULL, 10);
- symbol_print_news(sym, num_articles);
+ news_print(sym, num_articles);
}
//Encrypt/decrypt
@@ -45,14 +45,14 @@ int main(int argc, char* argv[]) {
// Graph
else if (strcmp(cmd, "graph") == 0 && argc == 3)
- symbol_graph(sym, NULL);
+ graph_print(sym, NULL);
// Compare
else if (strcmp(cmd, "cmp") == 0 && argc == 4) {
char sym2[strlen(argv[3]) + 1];
strcpy(sym2, argv[3]);
strtoupper(sym2);
- symbol_graph(sym, sym2);
+ graph_print(sym, sym2);
}
// Check