diff options
author | Antony Kellermann | 2018-09-04 19:47:19 -0400 |
---|---|---|
committer | Antony Kellermann | 2018-09-04 19:47:19 -0400 |
commit | 5e2e750b4eb1adb25385ee13f6cb62c4b8868f78 (patch) | |
tree | 87e0297975a1e2b8a4c1b3aaa9cb3d1e6b4a417f | |
parent | 4166914b1a911c15fe2c18f345ac8d103155b583 (diff) | |
download | aur-5e2e750b4eb1adb25385ee13f6cb62c4b8868f78.tar.gz |
Refactoring
-rw-r--r-- | README.md | 7 | ||||
-rw-r--r-- | api.c | 165 | ||||
-rw-r--r-- | api.h | 99 | ||||
-rw-r--r-- | curses_win.c | 50 | ||||
-rw-r--r-- | gtk_win.c | 24 | ||||
-rw-r--r-- | portfolio.c | 10 |
6 files changed, 180 insertions, 175 deletions
diff --git a/README.md b/README.md index e1a857edd181..376394ec28da 100644 --- a/README.md +++ b/README.md @@ -133,4 +133,9 @@ the provided license for more information. * Implement Coinmarketcap v2 * Notes for portfolio securities * Search for securities -* History per session
\ No newline at end of file +* History per session +* Mutex on portfolio +* Add security without reloading every security +* Refactoring +* Cache ref-data +* streq
\ No newline at end of file @@ -1,6 +1,6 @@ #include "api.h" -Ref_Data* api_ref_data_init_from_length(size_t length) { +Ref_Data* ref_data_init_length(size_t length) { Ref_Data* pRef_Data = malloc(sizeof(Ref_Data)); pointer_alloc_check(pRef_Data); pRef_Data->symbols = malloc(length * sizeof(char*)); @@ -17,7 +17,7 @@ Ref_Data* api_ref_data_init_from_length(size_t length) { return pRef_Data; } -News* api_news_init(void) { +News* news_init(void) { News* pNews = malloc(sizeof(News)); pointer_alloc_check(pNews); *pNews = (News) { @@ -26,7 +26,7 @@ News* api_news_init(void) { return pNews; } -Info* api_info_init(void) { +Info* info_init(void) { Info* pInfo = malloc(sizeof(Info)); pointer_alloc_check(pInfo); *pInfo = (Info) { // Null terminate every string and set every value to EMPTY @@ -51,7 +51,7 @@ Info* api_info_init(void) { return pInfo; } -Info_Array* api_info_array_init(void) { +Info_Array* info_array_init(void) { Info_Array* pInfo_Array = malloc(sizeof(Info_Array)); pointer_alloc_check(pInfo_Array); *pInfo_Array = (Info_Array) { @@ -60,18 +60,18 @@ Info_Array* api_info_array_init(void) { return pInfo_Array; } -Info_Array* api_info_array_init_from_length(size_t length) { +Info_Array* info_array_init_length(size_t length) { if (length == 0) - return api_info_array_init(); + return info_array_init(); - Info_Array* pInfo_Array = api_info_array_init(); + Info_Array* pInfo_Array = info_array_init(); pInfo_Array->length = length; pInfo_Array->array = malloc(sizeof(Info*) * length); pointer_alloc_check(pInfo_Array->array); for (size_t i = 0; i < length; i++) - pInfo_Array->array[i] = api_info_init(); + pInfo_Array->array[i] = info_init(); - pInfo_Array->totals = api_info_init(); + pInfo_Array->totals = info_init(); strcpy(pInfo_Array->totals->symbol, "TOTALS"); return pInfo_Array; } @@ -79,11 +79,11 @@ Info_Array* api_info_array_init_from_length(size_t length) { void info_array_append(Info_Array* pInfo_Array, const char* symbol) { pInfo_Array->array = realloc(pInfo_Array->array, sizeof(char*) * (pInfo_Array->length + 1)); pInfo_Array->length++; - pInfo_Array->array[pInfo_Array->length - 1] = api_info_init(); + pInfo_Array->array[pInfo_Array->length - 1] = info_init(); strcpy(pInfo_Array->array[pInfo_Array->length - 1]->symbol, symbol); } -size_t api_string_writefunc(void* ptr, size_t size, size_t nmemb, String* pString) { +size_t string_writefunc(void* ptr, size_t size, size_t nmemb, String* pString) { size_t new_len = pString->len + size * nmemb; pString->data = realloc(pString->data, new_len + 1); pointer_alloc_check(pString->data); @@ -93,7 +93,7 @@ size_t api_string_writefunc(void* ptr, size_t size, size_t nmemb, String* pStrin return size * nmemb; } -String* api_curl_data(const char* url) { +String* api_curl_url(const char* url) { CURL* curl = curl_easy_init(); CURLcode res; if (!curl) // Error creating curl object @@ -102,7 +102,7 @@ String* api_curl_data(const char* url) { String* pString = string_init(); curl_easy_setopt(curl, CURLOPT_URL, url); // Set URL curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); // Needed for HTTPS - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, api_string_writefunc); // Specify writefunc for return data + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, string_writefunc); // Specify writefunc for return data curl_easy_setopt(curl, CURLOPT_WRITEDATA, &pString->data); // Specify object for return data res = curl_easy_perform(curl); curl_easy_cleanup(curl); @@ -114,7 +114,7 @@ String* api_curl_data(const char* url) { return pString; } -void iex_batch_store_data_info_array(Info_Array* pInfo_Array, Data_Level data_level) { +void api_iex_store_info_array(Info_Array* pInfo_Array, Data_Level data_level) { char** symbol_array = malloc(pInfo_Array->length * sizeof(char*)); pointer_alloc_check(symbol_array); for (size_t i = 0; i < pInfo_Array->length; i++) { @@ -123,9 +123,9 @@ void iex_batch_store_data_info_array(Info_Array* pInfo_Array, Data_Level data_le strcpy(symbol_array[i], pInfo_Array->array[i]->symbol); } - String* pString = iex_batch_get_data_string(symbol_array, pInfo_Array->length, data_level); + String* pString = api_iex_get_data_string(symbol_array, pInfo_Array->length, data_level); Json* jobj = json_tokener_parse(pString->data); - info_array_store_all_from_json(pInfo_Array, jobj); + info_array_store_endpoints_json(pInfo_Array, jobj); for (size_t i = 0; i < pInfo_Array->length; i++) free(symbol_array[i]); @@ -135,36 +135,36 @@ void iex_batch_store_data_info_array(Info_Array* pInfo_Array, Data_Level data_le string_destroy(&pString); } -void iex_batch_store_data_info(Info* pInfo, Data_Level data_level) { +void api_iex_store_info(Info* pInfo, Data_Level data_level) { char* symbol_array = malloc(SYMBOL_MAX_LENGTH); pointer_alloc_check(symbol_array); strcpy(symbol_array, pInfo->symbol); - String* pString = iex_batch_get_data_string(&symbol_array, 1, data_level); + String* pString = api_iex_get_data_string(&symbol_array, 1, data_level); Json* jobj = json_tokener_parse(pString->data); Json* jsymbol = json_object_object_get(jobj, pInfo->symbol); if (jsymbol != NULL) - info_store_all_from_json(pInfo, jsymbol); + info_store_endpoints_json(pInfo, jsymbol); free(symbol_array); json_object_put(jobj); string_destroy(&pString); } -String* iex_batch_get_data_string(char* symbol_array[SYMBOL_MAX_LENGTH], size_t len, - Data_Level data_level) { +String* api_iex_get_data_string(char** symbol_array, size_t len, + Data_Level data_level) { char endpoints[128]; - if (data_level == ALL) + if (data_level == DATA_LEVEL_ALL) strcpy(endpoints, "quote,chart,company,stats,peers,news,earnings&range=5y"); - else if (data_level == CHECK) + else if (data_level == DATA_LEVEL_CHECK) strcpy(endpoints, "quote,chart"); - else if (data_level == MISC) + else if (data_level == DATA_LEVEL_MISC) strcpy(endpoints, "company,stats,peers,news,earnings&range=5y"); else strcpy(endpoints, "news"); size_t num_partitions = len / 100 + (len % 100 > 0), idx; char iex_api_string[num_partitions][URL_MAX_LENGTH * 2]; - char symbol_list_string[num_partitions][INFO_TEXT_MAX]; - memset(symbol_list_string, '\0', num_partitions * INFO_TEXT_MAX); + char symbol_list_string[num_partitions][INFO_MAX_LENGTH]; + memset(symbol_list_string, '\0', num_partitions * INFO_MAX_LENGTH); String* string_array[num_partitions]; pthread_t threads[num_partitions]; for (size_t i = 0; i < num_partitions; i++) { @@ -181,7 +181,7 @@ String* iex_batch_get_data_string(char* symbol_array[SYMBOL_MAX_LENGTH], size_t sprintf(iex_api_string[i], "https://api.iextrading.com/1.0/stock/market/batch?symbols=%s&types=%s", symbol_list_string[i], endpoints); - if (pthread_create(&threads[i], NULL, (void* (*)(void*)) api_curl_data, + if (pthread_create(&threads[i], NULL, (void* (*)(void*)) api_curl_url, (void*) iex_api_string[i])) EXIT_MSG("Error creating thread!"); } @@ -209,7 +209,7 @@ String* iex_batch_get_data_string(char* symbol_array[SYMBOL_MAX_LENGTH], size_t return string_array[0]; } -void* morningstar_store_info(void* vpInfo) { +void* api_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]; time_t now = time(NULL); @@ -223,7 +223,7 @@ void* morningstar_store_info(void* vpInfo) { "http://globalquote.morningstar.com/globalcomponent/RealtimeHistoricalStockData.ashx?showVol=true&dtype=his" "&f=d&curry=USD&isD=true&isS=true&hasF=true&ProdCode=DIRECT&ticker=%s&range=%s|%s", symbol_info->symbol, five_year_str, today_str); - String* pString = api_curl_data(morningstar_api_string); + String* pString = api_curl_url(morningstar_api_string); if (pString == NULL) return NULL; @@ -232,7 +232,7 @@ void* morningstar_store_info(void* vpInfo) { return NULL; } - symbol_info->api_provider = MORNINGSTAR; + symbol_info->api_provider = API_PROVIDER_MORNINGSTAR; Json* jobj = json_tokener_parse(pString->data); Json* datapoints = json_object_object_get( @@ -257,7 +257,7 @@ void* morningstar_store_info(void* vpInfo) { return vpInfo; } -void* alphavantage_store_info(void* vpInfo) { +void* api_alphavantage_store_info(void* vpInfo) { Info* symbol_info = vpInfo; if (symbol_info->symbol[0] == '\0') return NULL; @@ -266,7 +266,7 @@ void* alphavantage_store_info(void* vpInfo) { sprintf(alphavantage_api_string, "https://www.alphavantage.co/query?function=TIME_SERIES_DAILY" "&symbol=%s&apikey=DFUMLJ1ILOM2G7IH&outputsize=full&datatype" "=csv", symbol_info->symbol); - String* pString = api_curl_data(alphavantage_api_string); + String* pString = api_curl_url(alphavantage_api_string); if (pString == NULL) return NULL; @@ -275,7 +275,7 @@ void* alphavantage_store_info(void* vpInfo) { return NULL; } - symbol_info->api_provider = ALPHAVANTAGE; + symbol_info->api_provider = API_PROVIDER_ALPHAVANTAGE; size_t len = string_get_num_lines(pString) - 1, idx = 0; if (len > 1260) // 5 years @@ -303,11 +303,11 @@ void* alphavantage_store_info(void* vpInfo) { return vpInfo; } -void* coinmarketcap_store_info(void* vpInfo) { +void* api_coinmarketcap_store_info(void* vpInfo) { Info* symbol_info = vpInfo; char coinmarketcap_api_string[URL_MAX_LENGTH]; sprintf(coinmarketcap_api_string, "https://api.coinmarketcap.com/v1/ticker/%s", symbol_info->symbol); - String* pString = api_curl_data(coinmarketcap_api_string); + String* pString = api_curl_url(coinmarketcap_api_string); if (pString == NULL) return NULL; @@ -316,7 +316,7 @@ void* coinmarketcap_store_info(void* vpInfo) { return NULL; } - symbol_info->api_provider = COINMARKETCAP; + symbol_info->api_provider = API_PROVIDER_COINMARKETCAP; Json* jobj = json_tokener_parse(pString->data); Json* data = json_object_array_get_idx(jobj, 0); @@ -338,8 +338,8 @@ void* coinmarketcap_store_info(void* vpInfo) { return vpInfo; } -void api_info_array_store_data_batch(Info_Array* pInfo_Array, Data_Level data_level) { - iex_batch_store_data_info_array(pInfo_Array, data_level); +void api_store_info_array(Info_Array* pInfo_Array, Data_Level data_level) { + api_iex_store_info_array(pInfo_Array, data_level); // All IEX securities are accounted for Info* pInfo; @@ -351,9 +351,9 @@ void api_info_array_store_data_batch(Info_Array* pInfo_Array, Data_Level data_le if (pInfo->api_provider == EMPTY && strcmp(pInfo->symbol, "USD$") != 0) { open_threads[i] = 1; if (strlen(pInfo->symbol) > 5 && pthread_create(&threads[i], NULL, - coinmarketcap_store_info, pInfo)) { // Crypto + api_coinmarketcap_store_info, pInfo)) { // Crypto EXIT_MSG("Error creating thread!"); - } else if (pthread_create(&threads[i], NULL, alphavantage_store_info, pInfo)) { + } else if (pthread_create(&threads[i], NULL, api_alphavantage_store_info, pInfo)) { EXIT_MSG("Error creating thread!"); } } @@ -371,7 +371,7 @@ void api_info_array_store_data_batch(Info_Array* pInfo_Array, Data_Level data_le // Crypto with 5 char or less name if (pInfo->api_provider == EMPTY && strcmp(pInfo->symbol, "USD$") != 0 && - pthread_create(&threads[i], NULL, coinmarketcap_store_info, pInfo)) + pthread_create(&threads[i], NULL, api_coinmarketcap_store_info, pInfo)) EXIT_MSG("Error creating thread!"); } @@ -383,21 +383,22 @@ void api_info_array_store_data_batch(Info_Array* pInfo_Array, Data_Level data_le open_threads[i] = 0; } - info_store_check_data(pInfo_Array->array[i]); + info_store_portfolio_data(pInfo_Array->array[i]); } info_array_store_totals(pInfo_Array); } -void api_info_store_data_batch(Info* pInfo, Data_Level data_level) { - iex_batch_store_data_info(pInfo, data_level); - if (data_level == NEWS || (pInfo->api_provider == EMPTY && - alphavantage_store_info(pInfo) == NULL && coinmarketcap_store_info(pInfo) == NULL)) +void api_store_info(Info* pInfo, Data_Level data_level) { + api_iex_store_info(pInfo, data_level); + if (data_level == DATA_LEVEL_NEWS || (pInfo->api_provider == EMPTY && + api_alphavantage_store_info(pInfo) == NULL && + api_coinmarketcap_store_info(pInfo) == NULL)) return; - info_store_check_data(pInfo); + info_store_portfolio_data(pInfo); } -void info_store_check_data(Info* pInfo) { +void info_store_portfolio_data(Info* pInfo) { if (strcmp(pInfo->symbol, "USD$") != 0) { if (pInfo->amount != EMPTY) { pInfo->current_value = pInfo->amount * pInfo->price; @@ -450,13 +451,13 @@ void info_array_store_totals(Info_Array* pInfo_Array) { pInfo_Array->totals->total_spent; } -Ref_Data* iex_get_valid_symbols(void) { - String* pString = api_curl_data("https://api.iextrading.com/1.0/ref-data/symbols"); +Ref_Data* api_iex_store_ref_data(void) { + String* pString = api_curl_url("https://api.iextrading.com/1.0/ref-data/symbols"); if (pString == NULL) return NULL; Json* jobj = json_tokener_parse(pString->data), * idx; - Ref_Data* pRef_Data = api_ref_data_init_from_length(json_object_array_length(jobj)); + Ref_Data* pRef_Data = ref_data_init_length(json_object_array_length(jobj)); for (size_t i = 0; i < pRef_Data->length; i++) { idx = json_object_array_get_idx(jobj, i); strcpy(pRef_Data->symbols[i], json_object_get_string(json_object_object_get(idx, @@ -471,18 +472,18 @@ Ref_Data* iex_get_valid_symbols(void) { return pRef_Data; } -void info_array_store_all_from_json(Info_Array* pInfo_Array, const Json* jobj) { +void info_array_store_endpoints_json(Info_Array* pInfo_Array, const Json* jobj) { Json* jsymbol; for (size_t i = 0; i < pInfo_Array->length; i++) { jsymbol = json_object_object_get(jobj, pInfo_Array->array[i]->symbol); if (jsymbol != NULL) - info_store_all_from_json(pInfo_Array->array[i], jsymbol); + info_store_endpoints_json(pInfo_Array->array[i], jsymbol); } } -void info_store_all_from_json(Info* pInfo, const Json* jsymbol) { +void info_store_endpoints_json(Info* pInfo, const Json* jsymbol) { Json* jquote, * jchart, * jcompany, * jstats, * jpeers, * jnews, * jearnings; - pInfo->api_provider = IEX; + pInfo->api_provider = API_PROVIDER_IEX; jquote = json_object_object_get(jsymbol, "quote"); jchart = json_object_object_get(jsymbol, "chart"); jcompany = json_object_object_get(jsymbol, "company"); @@ -491,22 +492,22 @@ void info_store_all_from_json(Info* pInfo, const Json* jsymbol) { jnews = json_object_object_get(jsymbol, "news"); jearnings = json_object_object_get(jsymbol, "earnings"); if (jquote != NULL) - info_store_quote_from_json(pInfo, jquote); + info_store_quote_json(pInfo, jquote); if (jchart != NULL) - info_store_chart_from_json(pInfo, jchart); + info_store_chart_json(pInfo, jchart); if (jcompany != NULL) - info_store_company_from_json(pInfo, jcompany); + info_store_company_json(pInfo, jcompany); if (jstats != NULL) - info_store_stats_from_json(pInfo, jstats); + info_store_stats_json(pInfo, jstats); if (jpeers != NULL) - info_store_peers_from_json(pInfo, jpeers); + info_store_peers_json(pInfo, jpeers); if (jnews != NULL) - info_store_news_from_json(pInfo, jnews); + info_store_news_json(pInfo, jnews); if (jearnings != NULL) - info_store_earnings_from_json(pInfo, jearnings); + info_store_earnings_json(pInfo, jearnings); } -void info_store_quote_from_json(Info* pInfo, const Json* jquote) { +void info_store_quote_json(Info* pInfo, const Json* jquote) { if (json_object_get_int64(json_object_object_get(jquote, "extendedPriceTime")) > json_object_get_int64(json_object_object_get(jquote, "latestUpdate"))) { pInfo->price = json_object_get_double(json_object_object_get(jquote, "extendedPrice")); @@ -526,7 +527,7 @@ void info_store_quote_from_json(Info* pInfo, const Json* jquote) { } -void info_store_chart_from_json(Info* pInfo, const Json* jchart) { +void info_store_chart_json(Info* pInfo, const Json* jchart) { free(pInfo->points); size_t len = json_object_array_length(jchart); pInfo->points = calloc(len + 1, sizeof(double)); @@ -544,7 +545,7 @@ void info_store_chart_from_json(Info* pInfo, const Json* jchart) { pInfo->price_30d = pInfo->points[0]; } -void info_store_company_from_json(Info* pInfo, const Json* jcompany) { +void info_store_company_json(Info* pInfo, const Json* jcompany) { Json* jsymbol, * jname, * jindustry, * jwebsite, * jdescription, * jceo, * jtype, * jsector; jsymbol = json_object_object_get(jcompany, "symbol"); jname = json_object_object_get(jcompany, "companyName"); @@ -575,7 +576,7 @@ void info_store_company_from_json(Info* pInfo, const Json* jcompany) { strcpy(pInfo->sector, json_object_get_string(jsector)); } -void info_store_stats_from_json(Info* pInfo, const Json* jstats) { +void info_store_stats_json(Info* pInfo, const Json* jstats) { pInfo->div_yield = json_object_get_double(json_object_object_get(jstats, "dividendYield")); pInfo->revenue = json_object_get_int64(json_object_object_get(jstats, "revenue")); pInfo->gross_profit = json_object_get_int64(json_object_object_get(jstats, "grossProfit")); @@ -583,23 +584,20 @@ void info_store_stats_from_json(Info* pInfo, const Json* jstats) { pInfo->debt = json_object_get_int64(json_object_object_get(jstats, "debt")); } -void info_store_peers_from_json(Info* pInfo, const Json* jpeers) { +void info_store_peers_json(Info* pInfo, const Json* jpeers) { size_t len = json_object_array_length(jpeers); if (len == 0) return; - if (len > MAX_PEERS) - len = MAX_PEERS; - - pInfo->peers = api_info_array_init_from_length(len); + pInfo->peers = info_array_init_length(len); for (size_t i = 0; i < pInfo->peers->length; i++) strcpy(pInfo->peers->array[i]->symbol, json_object_get_string( json_object_array_get_idx(jpeers, i))); - api_info_array_store_data_batch(pInfo->peers, CHECK); + api_store_info_array(pInfo->peers, DATA_LEVEL_CHECK); } -void info_store_news_from_json(Info* pInfo, const Json* jnews) { +void info_store_news_json(Info* pInfo, const Json* jnews) { Json* idx, * headline, * source, * date, * summary, * url, * related; size_t len = json_object_array_length(jnews); if (len < (unsigned) pInfo->num_articles) @@ -627,7 +625,7 @@ void info_store_news_from_json(Info* pInfo, const Json* jnews) { break; } - pInfo->articles[i] = api_news_init(); + pInfo->articles[i] = news_init(); if (headline != NULL) strcpy(pInfo->articles[i]->headline, json_object_get_string(headline)); if (source != NULL) @@ -654,7 +652,7 @@ void info_store_news_from_json(Info* pInfo, const Json* jnews) { } } -void info_store_earnings_from_json(Info* pInfo, const Json* jearnings) { +void info_store_earnings_json(Info* pInfo, const Json* jearnings) { // ETFs don't report earnings if (!json_object_is_type(json_object_object_get(jearnings, "earnings"), json_type_array)) return; @@ -733,7 +731,7 @@ Info* info_array_find_symbol_recursive(const Info_Array* pInfo_Array, const char return NULL; } -void api_ref_data_destroy(Ref_Data** phRef_Data) { +void ref_data_destroy(Ref_Data** phRef_Data) { if (*phRef_Data == NULL) return; @@ -748,7 +746,7 @@ void api_ref_data_destroy(Ref_Data** phRef_Data) { *phRef_Data = NULL; } -void api_news_destroy(News** phNews) { +void news_destroy(News** phNews) { if (*phNews == NULL) return; @@ -756,7 +754,7 @@ void api_news_destroy(News** phNews) { *phNews = NULL; } -void api_info_destroy(Info** phInfo) { +void info_destroy(Info** phInfo) { if (*phInfo == NULL) return; @@ -764,26 +762,25 @@ void api_info_destroy(Info** phInfo) { free(pInfo->points); if (pInfo->articles != NULL) for (int i = 0; i < pInfo->num_articles; i++) - api_news_destroy(&pInfo->articles[i]); + news_destroy(&pInfo->articles[i]); if (pInfo->peers != NULL) - api_info_array_destroy(&pInfo->peers); + info_array_destroy(&pInfo->peers); free(pInfo->articles); free(*phInfo); *phInfo = NULL; } -void api_info_array_destroy(Info_Array** phInfo_Array) { +void info_array_destroy(Info_Array** phInfo_Array) { if (*phInfo_Array == NULL) return; Info_Array* pInfo_Array = *phInfo_Array; for (size_t i = 0; i < pInfo_Array->length; i++) - api_info_destroy(&pInfo_Array->array[i]); + info_destroy(&pInfo_Array->array[i]); free(pInfo_Array->array); - if (pInfo_Array->totals != NULL) - api_info_destroy(&pInfo_Array->totals); + info_destroy(&pInfo_Array->totals); free(*phInfo_Array); *phInfo_Array = NULL; }
\ No newline at end of file @@ -9,24 +9,24 @@ #define TICK_API_H typedef enum api_providers { - IEX, MORNINGSTAR, ALPHAVANTAGE, COINMARKETCAP + API_PROVIDER_IEX, API_PROVIDER_MORNINGSTAR, + API_PROVIDER_ALPHAVANTAGE, API_PROVIDER_COINMARKETCAP } Api_Provider; typedef enum data_level { - ALL, CHECK, MISC, NEWS + DATA_LEVEL_ALL, DATA_LEVEL_CHECK, DATA_LEVEL_MISC, DATA_LEVEL_NEWS } Data_Level; -#define QUARTERS 4 -#define DATE_MAX_LENGTH 32 #define CELL_MAX_LENGTH 16 +#define DATE_MAX_LENGTH 32 #define SYMBOL_MAX_LENGTH 32 #define NAME_MAX_LENGTH 128 #define URL_MAX_LENGTH 2048 -#define INFO_TEXT_MAX 2048 +#define INFO_MAX_LENGTH 2048 #define NEWS_MAX_LENGTH 10500 + +#define QUARTERS 4 #define EMPTY (-999) -#define DEFAULT_NUM_ARTICLES 3 -#define MAX_PEERS 12 #include <stddef.h> #include <curl/curl.h> @@ -41,19 +41,17 @@ typedef struct ref_data { } Ref_Data; typedef struct news_article { - char headline[INFO_TEXT_MAX]; - char source[INFO_TEXT_MAX]; + char headline[INFO_MAX_LENGTH]; + char source[INFO_MAX_LENGTH]; char date[DATE_MAX_LENGTH]; - char summary[INFO_TEXT_MAX]; + char summary[INFO_MAX_LENGTH]; char url[URL_MAX_LENGTH]; - char related[INFO_TEXT_MAX]; + char related[INFO_MAX_LENGTH]; } News; -typedef struct info Info; - typedef struct info_array Info_Array; -struct info { +typedef struct info { int api_provider; // IEX, MORNINGSTAR, ALPHAVANTAGE, COINMARKETCAP /** API DATA **/ @@ -62,7 +60,7 @@ struct info { char name[NAME_MAX_LENGTH]; // ex. Apple Inc. char industry[NAME_MAX_LENGTH]; // ex. Computer Hardware char website[URL_MAX_LENGTH]; // ex. apple.com - char description[INFO_TEXT_MAX]; // Paragraph description of company + char description[INFO_MAX_LENGTH]; // Paragraph description of company char ceo[NAME_MAX_LENGTH]; // ex. Timothy D. Cook char issue_type[3]; /* ad – American Depository Receipt (ADR’s) re – Real Estate Investment Trust (REIT’s) @@ -141,7 +139,7 @@ struct info { char fprofit_7d_percent[CELL_MAX_LENGTH]; // Profit since seven days ago % char fprofit_30d[CELL_MAX_LENGTH]; // Profit since thirty days ago char fprofit_30d_percent[CELL_MAX_LENGTH]; // Profit since thirty days ago % -}; +} Info; struct info_array { Info** array; @@ -149,33 +147,38 @@ struct info_array { Info* totals; }; -Ref_Data* api_ref_data_init_from_length(size_t length); +/** + * Allocates a Ref_Data struct with length and returns a pointer to it. + * @param length + * @return Ref_Data* + */ +Ref_Data* ref_data_init_length(size_t length); /** * Allocates a News struct and returns a pointer to it. * @return News* */ -News* api_news_init(void); +News* 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. * @return Info* */ -Info* api_info_init(void); +Info* info_init(void); /** * Allocates an Info_Array struct with length 0. * @return Info_Array* */ -Info_Array* api_info_array_init(void); +Info_Array* info_array_init(void); /** * Allocates an Info_Array struct with allocated length. * @param length number of Info pointers to allocate * @return Info_Array* */ -Info_Array* api_info_array_init_from_length(size_t length); +Info_Array* info_array_init_length(size_t length); /** * Appends a security to an Info_Array. @@ -185,31 +188,31 @@ Info_Array* api_info_array_init_from_length(size_t length); void info_array_append(Info_Array* pInfo_Array, const char* symbol); /** - * writefunction for cURL HTTP GET/POST + * writefunction for cURL HTTP GET * stolen from a nice man on stackoverflow */ -size_t api_string_writefunc(void* ptr, size_t size, size_t nmemb, String* pString); +size_t string_writefunc(void* ptr, size_t size, size_t nmemb, String* pString); /** * Performs a HTTP GET. Response data is stored and returned in an allocated String*. * @param url API url to GET * @return NULL if error or no response from server. Otherwise, String* containing data. */ -String* api_curl_data(const char* url); +String* api_curl_url(const char* url); /** * Calls IEX's batch API to store data in pInfo_Array. symbol must be a valid string in each Info * @param pInfo_Array the Info_Array to fill * @param data_level the level of data to store */ -void iex_batch_store_data_info_array(Info_Array* pInfo_Array, Data_Level data_level); +void api_iex_store_info_array(Info_Array* pInfo_Array, Data_Level data_level); /** * Calls IEX's batch API to store data in pInfo. symbol must be a valid string in pInfo * @param pInfo the Info to fill * @param data_level the level of data to store */ -void iex_batch_store_data_info(Info* pInfo, Data_Level data_level); +void api_iex_store_info(Info* pInfo, Data_Level data_level); /** * This function will only store stock and ETF data. @@ -221,8 +224,8 @@ void iex_batch_store_data_info(Info* pInfo, Data_Level data_level); * @param pInfo_Array the Info_Array * @param data_level endpoints to query */ -String* iex_batch_get_data_string(char* symbol_array[SYMBOL_MAX_LENGTH], size_t len, - Data_Level data_level); +String* api_iex_get_data_string(char** symbol_array, size_t len, + Data_Level data_level); /** * Designed for threading * @@ -231,7 +234,7 @@ String* iex_batch_get_data_string(char* symbol_array[SYMBOL_MAX_LENGTH], size_t * @param vpInfo Info* * @return vpInfo on success, NULL on error */ -void* morningstar_store_info(void* vpInfo); +void* api_morningstar_store_info(void* vpInfo); /** * Designed for threading @@ -241,7 +244,7 @@ void* morningstar_store_info(void* vpInfo); * @param vpInfo Info* * @return vpInfo on Success, NULL on error */ -void* alphavantage_store_info(void* vpInfo); +void* api_alphavantage_store_info(void* vpInfo); /** * Designed for threading @@ -251,7 +254,7 @@ void* alphavantage_store_info(void* vpInfo); * @param vpInfo Info* * @return vpInfo on success, NULL on error */ -void* coinmarketcap_store_info(void* vpInfo); +void* api_coinmarketcap_store_info(void* vpInfo); /** * Queries IEX, AlphaVantage, and Coinmarketcap to store api data in pInfo_Array. data_level will @@ -259,7 +262,7 @@ void* coinmarketcap_store_info(void* vpInfo); * @param pInfo_Array the Info_Array * @param data_level the data level to store */ -void api_info_array_store_data_batch(Info_Array* pInfo_Array, Data_Level data_level); +void api_store_info_array(Info_Array* pInfo_Array, Data_Level data_level); /** * Queries IEX, AlphaVantage, and Coinmarketcap to store api data in pInfo. data_level will @@ -267,14 +270,14 @@ void api_info_array_store_data_batch(Info_Array* pInfo_Array, Data_Level data_le * @param pInfo * @param data_level */ -void api_info_store_data_batch(Info* pInfo, Data_Level data_level); +void api_store_info(Info* pInfo, Data_Level data_level); /** * After API data and portfolio have already been collected, uses them to populate the Info fields current_value and * all the profit fields. * @param pInfo Info* */ -void info_store_check_data(Info* pInfo); +void info_store_portfolio_data(Info* pInfo); /** * Adds up values of Info array and sets values in totals. @@ -286,21 +289,21 @@ void info_array_store_totals(Info_Array* pInfo_Array); * Returns a pointer to an Info_Array containing a list of all iex listed securities. * @return Info_Array* */ -Ref_Data* iex_get_valid_symbols(void); +Ref_Data* api_iex_store_ref_data(void); /** * Stores the data found in IEX formatted jobj in the Info_Array. * @param pInfo_Array * @param jobj */ -void info_array_store_all_from_json(Info_Array* pInfo_Array, const Json* jobj); +void info_array_store_endpoints_json(Info_Array* pInfo_Array, const Json* jobj); /** * Stores the data found in IEX formatted jsymbol in the Info_Array. * @param pInfo * @param jsymbol */ -void info_store_all_from_json(Info* pInfo, const Json* jsymbol); +void info_store_endpoints_json(Info* pInfo, const Json* jsymbol); /** * IEX quote endpoint. @@ -308,7 +311,7 @@ void info_store_all_from_json(Info* pInfo, const Json* jsymbol); * @param pInfo * @param jquote */ -void info_store_quote_from_json(Info* pInfo, const Json* jquote); +void info_store_quote_json(Info* pInfo, const Json* jquote); /** * IEX chart endpoint. @@ -316,7 +319,7 @@ void info_store_quote_from_json(Info* pInfo, const Json* jquote); * @param pInfo * @param jchart */ -void info_store_chart_from_json(Info* pInfo, const Json* jchart); +void info_store_chart_json(Info* pInfo, const Json* jchart); /** * IEX company endpoint. @@ -324,7 +327,7 @@ void info_store_chart_from_json(Info* pInfo, const Json* jchart); * @param pInfo * @param jcompany */ -void info_store_company_from_json(Info* pInfo, const Json* jcompany); +void info_store_company_json(Info* pInfo, const Json* jcompany); /** * IEX stats endpoint. @@ -332,7 +335,7 @@ void info_store_company_from_json(Info* pInfo, const Json* jcompany); * @param pInfo * @param jstats */ -void info_store_stats_from_json(Info* pInfo, const Json* jstats); +void info_store_stats_json(Info* pInfo, const Json* jstats); /** * IEX peers endpoint. @@ -340,7 +343,7 @@ void info_store_stats_from_json(Info* pInfo, const Json* jstats); * @param pInfo * @param jpeers */ -void info_store_peers_from_json(Info* pInfo, const Json* jpeers); +void info_store_peers_json(Info* pInfo, const Json* jpeers); /** * IEX news endpoint. @@ -348,7 +351,7 @@ void info_store_peers_from_json(Info* pInfo, const Json* jpeers); * @param pInfo * @param jnews */ -void info_store_news_from_json(Info* pInfo, const Json* jnews); +void info_store_news_json(Info* pInfo, const Json* jnews); /** * IEX earnings endpoint. @@ -356,7 +359,7 @@ void info_store_news_from_json(Info* pInfo, const Json* jnews); * @param pInfo * @param jearnings */ -void info_store_earnings_from_json(Info* pInfo, const Json* jearnings); +void info_store_earnings_json(Info* pInfo, const Json* jearnings); /** * Searches through an Info_Array and returns a ponter to the Info which has the same symbol as @@ -403,24 +406,24 @@ Info* info_array_find_symbol_recursive(const Info_Array* pInfo_Array, const char * Destroys Ref_Data object and frees memory. Sets the pointer of the Ref_Data to NULL * @param phRef_Data the Ref_Data to destroy */ -void api_ref_data_destroy(Ref_Data** phRef_Data); +void ref_data_destroy(Ref_Data** phRef_Data); /** * Destroys News object and frees memory. Sets the pointer of the News to NULL * @param phNews the News to destroy */ -void api_news_destroy(News** phNews); +void news_destroy(News** phNews); /** * Destroys Info object and frees memory. Sets the pointer to the Info to NULL * @param phInfo the Info to destroy */ -void api_info_destroy(Info** phInfo); +void info_destroy(Info** phInfo); /** * Destroys Info_Array object and frees memory. Sets the pointer to the Info to NULL * @param phInfo_Array the Info_Array to destroy */ -void api_info_array_destroy(Info_Array** phInfo_Array); +void info_array_destroy(Info_Array** phInfo_Array); #endif
\ No newline at end of file diff --git a/curses_win.c b/curses_win.c index 3dad17f33eb8..a611da435548 100644 --- a/curses_win.c +++ b/curses_win.c @@ -8,9 +8,9 @@ void portfolio_printw(void) { Info_Array* portfolio_data = portfolio_info_array_init_from_portfolio_string( pString); if (portfolio_data != NULL) { - api_info_array_store_data_batch(portfolio_data, CHECK); + api_store_info_array(portfolio_data, DATA_LEVEL_CHECK); info_array_portfolio_printw(portfolio_data); - api_info_array_destroy(&portfolio_data); + info_array_destroy(&portfolio_data); } string_destroy(&pString); } @@ -34,7 +34,7 @@ void info_array_portfolio_printw(Info_Array* portfolio_data) { if (cols < 110) { endwin(); puts("Terminal too small."); - api_info_array_destroy(&portfolio_data); + info_array_destroy(&portfolio_data); return; } @@ -160,13 +160,13 @@ void portfolio_print_stock(const char* symbol) { if (i == len) GOTO_CLEAN_MSG("Your portfolio does not contain any of this security.") - Info* info = api_info_init(); + Info* info = info_init(); strcpy(info->symbol, symbol); - api_info_store_data_batch(info, CHECK); + api_store_info(info, DATA_LEVEL_CHECK); info->amount = json_object_get_double(json_object_object_get(json_object_array_get_idx(jobj, i), "Shares")); info->total_spent = json_object_get_double(json_object_object_get(json_object_array_get_idx(jobj, i), "USD_Spent")); - info_store_check_data(info); + info_store_portfolio_data(info); printf(" AMOUNT SYMBOL VALUE SPENT PROFIT (%%) 24H (%%) 7D " " (%%) 30D " " (%%)\n%8.2lf %6s %8.2lf %8.2lf %8.2lf (%6.2lf%%) %8.2lf (%6.2lf%%) %8.2lf (%6.2lf%%) %8.2lf (%6.2lf%%)\n", @@ -174,24 +174,24 @@ void portfolio_print_stock(const char* symbol) { info->profit_total_percent, info->profit_last_close, info->profit_last_close_percent, info->profit_7d, info->profit_7d_percent, info->profit_30d, info->profit_30d_percent); - api_info_destroy(&info); + info_destroy(&info); cleanup: json_object_put(jobj); string_destroy(&pString); } void interface_print(const char* symbol) { - Info* symbol_info = api_info_init(); + Info* symbol_info = info_init(); strcpy(symbol_info->symbol, symbol); - api_info_store_data_batch(symbol_info, ALL); + api_store_info(symbol_info, DATA_LEVEL_ALL); if (symbol_info->api_provider == EMPTY) { - api_info_destroy(&symbol_info); + info_destroy(&symbol_info); RET_MSG("Invalid symbol.") } if (symbol_info->points == NULL || symbol_info->name[0] == '\0') { // If not IEX print to stdout info_print(symbol_info); - api_info_destroy(&symbol_info); + info_destroy(&symbol_info); return; } @@ -238,7 +238,7 @@ void interface_print(const char* symbol) { cleanup: endwin(); - api_info_destroy(&symbol_info); + info_destroy(&symbol_info); } void header_printw(WINDOW* window, const Info* symbol_info) { @@ -355,19 +355,19 @@ 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."); - Info* symbol_info = api_info_init(); + Info* symbol_info = info_init(); strcpy(symbol_info->symbol, symbol); symbol_info->num_articles = num_articles; - api_info_store_data_batch(symbol_info, NEWS); + api_store_info(symbol_info, DATA_LEVEL_NEWS); if (symbol_info->api_provider == EMPTY) { - api_info_destroy(&symbol_info); + info_destroy(&symbol_info); RET_MSG("Invalid symbol"); } 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); + info_destroy(&symbol_info); } void news_printw(WINDOW* window, const Info* symbol_info) { @@ -396,21 +396,21 @@ void peers_printw(WINDOW* window, const Info* symbol_info) { } void graph_print(const char* symbol, const char* symbol2) { - Info* symbol_info = api_info_init(), * symbol_info2 = NULL; + Info* symbol_info = info_init(), * symbol_info2 = NULL; strcpy(symbol_info->symbol, symbol); - api_info_store_data_batch(symbol_info, CHECK); + api_store_info(symbol_info, DATA_LEVEL_CHECK); if (symbol_info->api_provider == EMPTY || symbol_info->points == NULL) { - api_info_destroy(&symbol_info); + info_destroy(&symbol_info); RET_MSG("Invalid symbol") } if (symbol2 != NULL) { - symbol_info2 = api_info_init(); + symbol_info2 = info_init(); strcpy(symbol_info2->symbol, symbol2); - api_info_store_data_batch(symbol_info2, CHECK); + api_store_info(symbol_info2, DATA_LEVEL_CHECK); if (symbol_info2->api_provider == EMPTY || symbol_info2->points == NULL) { - api_info_destroy(&symbol_info); - api_info_destroy(&symbol_info2); + info_destroy(&symbol_info); + info_destroy(&symbol_info2); RET_MSG("Invalid symbol") } } @@ -421,8 +421,8 @@ void graph_print(const char* symbol, const char* symbol2) { } graph_printw(stdscr, symbol_info, symbol_info2); - api_info_destroy(&symbol_info); - api_info_destroy(&symbol_info2); + info_destroy(&symbol_info); + info_destroy(&symbol_info2); endwin(); } diff --git a/gtk_win.c b/gtk_win.c index bb10bf6a3634..78ed4b74b3e2 100644 --- a/gtk_win.c +++ b/gtk_win.c @@ -11,7 +11,7 @@ void window_main(void) { app.portfolio_data = NULL; app.portfolio_string = NULL; app.builder = gtk_builder_new(); - app.info_cache = api_info_array_init(); + app.info_cache = info_array_init(); app.iex_ref_data = NULL; app.password[0] = '\0'; app.last_reload = 0; @@ -36,7 +36,7 @@ void window_main(void) { void check_list_create_from_string(void) { GtkListStore* pListStore = GTK_LIST_STORE(GET_OBJECT("check_list")); gtk_list_store_clear(pListStore); // Clear in case reloading - api_info_array_destroy(&app.portfolio_data); // Destroy in case reloading + info_array_destroy(&app.portfolio_data); // Destroy in case reloading app.portfolio_data = portfolio_info_array_init_from_portfolio_string(app.portfolio_string); if (app.portfolio_data == NULL) // Empty JSON array return; @@ -138,12 +138,12 @@ void on_load_button_clicked(GtkButton* button) { } // Destroy and create a new Info_Array with portfolio and api data - api_info_array_destroy(&app.portfolio_data); + info_array_destroy(&app.portfolio_data); app.portfolio_data = portfolio_info_array_init_from_portfolio_string(app.portfolio_string); if (app.portfolio_data != NULL) { // If file is not a length 0 JSON array check_list_create_from_string(); app.last_reload = now; - api_info_array_store_data_batch(app.portfolio_data, CHECK); + api_store_info_array(app.portfolio_data, DATA_LEVEL_CHECK); check_list_add_api_data(); } @@ -331,8 +331,8 @@ void on_check_window_destroy(void) { // Destroy String and Info_Array and exit main GTK loop string_destroy(&app.portfolio_string); - api_info_array_destroy(&app.portfolio_data); - api_ref_data_destroy(&app.iex_ref_data); + info_array_destroy(&app.portfolio_data); + ref_data_destroy(&app.iex_ref_data); gtk_main_quit(); } @@ -367,7 +367,7 @@ void on_search_entry_focus_in_event(GtkWidget* search_entry, GdkEvent* event) { if (app.iex_ref_data != NULL) // If ref data has already been loaded return return; - app.iex_ref_data = iex_get_valid_symbols(); + app.iex_ref_data = api_iex_store_ref_data(); GtkListStore* list_store = GTK_LIST_STORE(GET_OBJECT("search_entry_completion_store")); GtkTreeIter iter; for (size_t i = 0; i < app.iex_ref_data->length; i++) { @@ -395,8 +395,8 @@ void symbol_show_info(const char* symbol) { if (pInfo == NULL) { // Append to cache if (app.info_cache->length == INFO_ARRAY_CACHE_MAX) { - api_info_array_destroy(&app.info_cache); - app.info_cache = api_info_array_init(); + info_array_destroy(&app.info_cache); + app.info_cache = info_array_init(); } info_array_append(app.info_cache, symbol); @@ -404,9 +404,9 @@ void symbol_show_info(const char* symbol) { } if (pInfo->price == EMPTY) - api_info_store_data_batch(pInfo, ALL); + api_store_info(pInfo, DATA_LEVEL_ALL); else if (pInfo->name[0] == '\0') - api_info_store_data_batch(pInfo, MISC); + api_store_info(pInfo, DATA_LEVEL_MISC); if (pInfo->peers != NULL) format_cells(pInfo->peers); @@ -497,7 +497,7 @@ void list_store_update(void) { // Recreate Info_Array check_list_create_from_string(); // Will set app.portfolio_data if success if (app.portfolio_data != NULL) { - api_info_array_store_data_batch(app.portfolio_data, CHECK); + api_store_info_array(app.portfolio_data, DATA_LEVEL_CHECK); check_list_add_api_data(); } } diff --git a/portfolio.c b/portfolio.c index 83ad3f7987bd..9bbc6e1944c6 100644 --- a/portfolio.c +++ b/portfolio.c @@ -82,15 +82,15 @@ int portfolio_modify_string(String* pString, const char* symbol, double quantity } if (strcmp("USD$", symbol) != 0) { // Check that the symbol is valid, except if it's USD - Info* data = api_info_init(); + Info* data = info_init(); strcpy(data->symbol, symbol); - api_info_store_data_batch(data, CHECK); + api_store_info(data, DATA_LEVEL_CHECK); if (data->api_provider == EMPTY) {// If NULL response from APIs, it's invalid - api_info_destroy(&data); + info_destroy(&data); status = 1; GOTO_CLEAN_MSG("Invalid symbol.") } - api_info_destroy(&data); + info_destroy(&data); } Json* new_object = json_object_new_object(); // Creates new array index and adds values to it @@ -153,7 +153,7 @@ Info_Array* portfolio_info_array_init_from_portfolio_string(String* pString) { RETNULL_MSG("Your portfolio is empty."); } - Info_Array* portfolio_data = api_info_array_init_from_length(length); + Info_Array* portfolio_data = info_array_init_length(length); portfolio_data->totals->total_spent = 0; for (size_t i = 0; i < portfolio_data->length; i++) { strcpy(portfolio_data->array[i]->symbol, |