aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFranklin Wei <git@fwei.tk>2015-05-12 19:59:44 -0400
committerFranklin Wei <git@fwei.tk>2015-05-12 19:59:44 -0400
commitb05123ca8b967a31cd074792ca920a3a74f61bc4 (patch)
tree0053b98f2815243b881e477787a98326dbde1f0e
parent9082eb2a10f935a23e140e0089fae26570081883 (diff)
downloadmarket-sim-b05123ca8b967a31cd074792ca920a3a74f61bc4.zip
market-sim-b05123ca8b967a31cd074792ca920a3a74f61bc4.tar.gz
market-sim-b05123ca8b967a31cd074792ca920a3a74f61bc4.tar.bz2
market-sim-b05123ca8b967a31cd074792ca920a3a74f61bc4.tar.xz
split into multiple files
-rw-r--r--src/buy.c88
-rw-r--r--src/globals.h20
-rw-r--r--src/load.c75
-rw-r--r--src/main.c461
-rw-r--r--src/save.c37
-rw-r--r--src/sell.c79
-rw-r--r--src/util.c177
7 files changed, 477 insertions, 460 deletions
diff --git a/src/buy.c b/src/buy.c
new file mode 100644
index 0000000..7419bbf
--- /dev/null
+++ b/src/buy.c
@@ -0,0 +1,88 @@
+#include "globals.h"
+
+void buy_handler(struct player_t *player)
+{
+ char *sym = malloc(16);
+ printf("Enter the ticker symbol of the stock you wish to purchase: ");
+ scanf("%15s", sym);
+ all_upper(sym);
+
+ struct money_t price;
+
+ printf("Getting stock information...\n");
+
+ char *name;
+
+ if(!get_stock_info(sym, &price, &name))
+ {
+ printf("Failed to get query information for '%s'.\n", sym);
+ return;
+ }
+
+ printf("Stock name: %s\n", name);
+ printf("Price per share: $%llu.%02llu\n", price.cents / 100, price.cents % 100);
+ printf("Enter the number of shares to be purchased (maximum %llu): ", player->cash.cents / price.cents);
+
+ ullong count = 0;
+
+ scanf("%llu", &count);
+
+ if(count <= 0)
+ {
+ printf("Purchase cancelled.\n");
+ return;
+ }
+
+ ullong cost = price.cents * count;
+
+ if(cost > player->cash.cents)
+ {
+ printf("Not enough money!\n");
+ return;
+ }
+
+ printf("This will cost $%llu.%02llu. Are you sure? ", cost / 100, cost % 100);
+ char response[16];
+ scanf("%15s", response);
+ all_lower(response);
+
+ if(response[0] == 'y')
+ {
+ printf("Confirmed.\n");
+
+ /* add the stock to the portfolio or increase the count of a stock */
+
+ for(uint i = 0; i < player->portfolio_len; ++i)
+ {
+ if(strcmp(player->portfolio[i].symbol, sym) == 0)
+ {
+ struct stock_t *stock = player->portfolio + i;
+ stock->count += count;
+ stock->current_price.cents = price.cents;
+ goto done;
+ }
+ }
+
+ /* not found, add a new one */
+ player->portfolio_len += 1;
+ player->portfolio = realloc(player->portfolio, player->portfolio_len * sizeof(struct stock_t));
+ player->need_to_free_portfolio = true;
+
+ printf("sym: %s\n", sym);
+ printf("name: %s\n", name);
+ player->portfolio[player->portfolio_len - 1].symbol = sym;
+ player->portfolio[player->portfolio_len - 1].fullname = name;
+ player->portfolio[player->portfolio_len - 1].count = count;
+ player->portfolio[player->portfolio_len - 1].current_price.cents = price.cents;
+ done:
+
+ player->cash.cents -= cost;
+
+ /* sort the portfolio alphabetically by ticker symbol */
+ qsort(player->portfolio, player->portfolio_len, sizeof(struct stock_t), compare_stocks);
+ }
+ else
+ {
+ printf("Not confirmed.\n");
+ }
+}
diff --git a/src/globals.h b/src/globals.h
index a220d79..cecb62b 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -1,5 +1,9 @@
+#include <ctype.h>
#include <stdbool.h>
#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#define ARRAYLEN(x) (sizeof(x) / sizeof(x[0]))
@@ -27,3 +31,19 @@ struct player_t {
struct stock_t *portfolio;
bool need_to_free_portfolio;
};
+
+/*** prototypes ***/
+void cleanup(void);
+int compare_stocks(const void*, const void*);
+void all_lower(char*);
+void all_upper(char*);
+bool get_stock_info(char *sym, struct money_t*, char **name);
+uint64_t to_sys64(uint64_t);
+uint64_t to_be64(uint64_t);
+
+void buy_handler(struct player_t*);
+void sell_handler(struct player_t*);
+void update_handler(struct player_t*);
+void save_handler(struct player_t*);
+void load_handler(struct player_t*);
+void quit_handler(struct player_t*);
diff --git a/src/load.c b/src/load.c
new file mode 100644
index 0000000..34acd73
--- /dev/null
+++ b/src/load.c
@@ -0,0 +1,75 @@
+#include "globals.h"
+
+/* NOTE: integers are represented internally by unsigned long long ints, but in the save they are always 64 bits */
+
+void load_handler(struct player_t *player)
+{
+ printf("Enter the file to load portfolio from: ");
+ char buf[128];
+ scanf("%127s", buf);
+
+ printf("Loading portfolio...\n");
+
+ if(player->need_to_free_portfolio)
+ free(player->portfolio);
+ player->portfolio_len = 0;
+
+ FILE *f = fopen(buf, "r");
+ char magic[6];
+ if(!f || fread(magic, 1, sizeof(magic), f) != 6 || memcmp(magic, "PORTv1", sizeof(magic)) != 0)
+ {
+ printf("FATAL: Failed to load save.");
+ exit(EXIT_FAILURE);
+ }
+
+ uint64_t cash;
+ if(fread(&cash, sizeof(cash), 1, f) != 1)
+ {
+ printf("FATAL: Failed to load save.");
+ exit(EXIT_FAILURE);
+ }
+ cash = to_sys64(cash);
+
+ player->cash.cents = cash;
+
+ fflush(stdout);
+ do {
+ /* read portfolio data */
+
+ player->portfolio_len += 1;
+ player->portfolio = realloc(player->portfolio, player->portfolio_len * sizeof(struct stock_t));
+ player->need_to_free_portfolio = true;
+
+ uint64_t symlen;
+ if(fread(&symlen, sizeof(symlen), 1, f) != 1)
+ {
+ printf("FATAL: Save is corrupted (symbol length too short).\n");
+ exit(EXIT_FAILURE);
+ }
+ symlen = to_sys64(symlen);
+ char *sym = malloc(symlen + 1);
+ if(fread(sym, symlen + 1, 1, f) != 1)
+ {
+ printf("FATAL: Save is corrupted (symbol too short).\n");
+ exit(EXIT_FAILURE);
+ }
+
+ player->portfolio[player->portfolio_len - 1].symbol = sym;
+
+ uint64_t count;
+ if(fread(&count, sizeof(count), 1, f) != 1)
+ {
+ printf("FATAL: Save is corrupted (count too short).\n");
+ exit(EXIT_FAILURE);
+ }
+ count = to_sys64(count);
+
+ player->portfolio[player->portfolio_len - 1].count = count;
+
+ int junk = fgetc(f);
+ ungetc(junk, f);
+
+ } while (!feof(f) && !ferror(f));
+
+ update_handler(player);
+}
diff --git a/src/main.c b/src/main.c
index b8685b7..9cda381 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,400 +1,14 @@
#include "globals.h"
-#include <curl/curl.h>
-
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-/*** prototypes ***/
-
-void buy_handler(struct player_t*);
-void sell_handler(struct player_t*);
-void update_handler(struct player_t*);
-void save_handler(struct player_t*);
-void load_handler(struct player_t*);
-void quit_handler(struct player_t*);
+#include <curl/curl.h>
/*** utility functions ***/
-void cleanup(void)
-{
- curl_global_cleanup();
-}
-
-struct data_buffer_t {
- char *data;
- uint back;
-};
-
-void all_upper(char *str)
-{
- while(*str)
- {
- *str = toupper(*str);
- ++str;
- }
-}
-
-void all_lower(char *str)
-{
- while(*str)
- {
- *str = tolower(*str);
- ++str;
- }
-}
-
-size_t download_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
-{
- struct data_buffer_t *buf = userdata;
-
- buf->data = realloc(buf->data, buf->back + size * nmemb);
-
- memcpy(buf->data + buf->back, ptr, size * nmemb);
-
- buf->back += size * nmemb;
-
- return size * nmemb;
-}
-
-bool get_stock_info(char *symbol, struct money_t *price, char **name_ret)
-{
- CURL *curl = curl_easy_init();
- if(!curl)
- {
- return false;
- }
-
- char url[256];
- snprintf(url, sizeof(url), "http://download.finance.yahoo.com/d/quotes.csv?s=%s&f=nl1&e=.csv", symbol);
-
- curl_easy_setopt(curl, CURLOPT_URL, url);
-
- struct data_buffer_t buf;
- memset(&buf, 0, sizeof(buf));
-
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, download_callback);
-
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buf);
-
- CURLcode res = curl_easy_perform(curl);
-
- curl_easy_cleanup(curl);
-
- /** now parse the data **/
-
- /* the stock name is in quotes, find it! */
-
- /* check for validity */
- if(buf.back == 0 || buf.data[0] != '"' || res != CURLE_OK)
- {
- printf("Failed to retrieve stock data.\n");
- if(res != CURLE_OK)
- {
- printf("Download library error (%d): '%s'\n", res, curl_easy_strerror(res));
- }
- return false;
- }
-
- uint name_len = 0;
- for(uint i = 1; i < buf.back; ++i)
- {
- if(buf.data[i] == '"')
- break;
- ++name_len;
- }
-
- const uint name_offs = 1;
- uint price_offs = name_len + 3;
- uint price_len = buf.back - price_offs;
-
- char *name = malloc(name_len + 1);
- memcpy(name, buf.data + name_offs, name_len);
- name[name_len] = '\0';
-
- *name_ret = name;
-
- /* get price */
-
- char *pricebuf = malloc(price_len + 1);
- memcpy(pricebuf, buf.data + price_offs, price_len);
- pricebuf[price_len] = '\0';
-
- free(buf.data);
-
- /* remove the decimal point */
-
- for(int i = 0; i < price_len; ++i)
- {
- if(pricebuf[i] == '.')
- memmove(pricebuf + i, pricebuf + i + 1, price_len - i);
- }
-
- price->cents = strtoull(pricebuf, NULL, 10);
-
- free(pricebuf);
-
- return true;
-}
-
-int compare_stocks(const void *a, const void *b)
-{
- const struct stock_t *a1 = a, *b1 = b;
- return strcmp(a1->symbol,
- b1->symbol);
-}
-
-static enum { OTHER = 0, LITTLE = 1, BIG = 2 } endianness;
-
-static void detect_endianness(void)
-{
- ulong test = 0x12345678;
- uchar *ptr = (uchar*)&test;
- if(*ptr == 0x12)
- endianness = BIG;
- else if(*ptr == 0x78)
- endianness = LITTLE;
- else
- {
- printf("FATAL: failed to detect system endianness!\n");
- exit(EXIT_FAILURE);
- }
-}
-
-uint64_t to_be64(ullong n)
-{
- if(!endianness)
- {
- detect_endianness();
- }
-
- if(BIG)
- {
- n = (n & 0x00000000FFFFFFFF) << 32 | (n & 0xFFFFFFFF00000000) >> 32;
- n = (n & 0x0000FFFF0000FFFF) << 16 | (n & 0xFFFF0000FFFF0000) >> 16;
- n = (n & 0x00FF00FF00FF00FF) << 8 | (n & 0xFF00FF00FF00FF00) >> 8;
- }
- return n;
-}
-
-uint64_t to_sys64(ullong n)
-{
- if(!endianness)
- {
- detect_endianness();
- }
-
- if(endianness == BIG)
- return n;
- else
- return to_be64(n);
-}
-
-/*** driver functions ***/
-
-void buy_handler(struct player_t *player)
-{
- char *sym = malloc(16);
- printf("Enter the ticker symbol of the stock you wish to purchase: ");
- scanf("%15s", sym);
- all_upper(sym);
-
- struct money_t price;
-
- printf("Getting stock information...\n");
-
- char *name;
-
- if(!get_stock_info(sym, &price, &name))
- {
- printf("Failed to get query information for '%s'.\n", sym);
- return;
- }
-
- printf("Stock name: %s\n", name);
- printf("Price per share: $%llu.%02llu\n", price.cents / 100, price.cents % 100);
- printf("Enter the number of shares to be purchased (maximum %llu): ", player->cash.cents / price.cents);
-
- ullong count = 0;
-
- scanf("%llu", &count);
-
- if(count <= 0)
- {
- printf("Purchase cancelled.\n");
- return;
- }
-
- ullong cost = price.cents * count;
-
- if(cost > player->cash.cents)
- {
- printf("Not enough money!\n");
- return;
- }
-
- printf("This will cost $%llu.%02llu. Are you sure? ", cost / 100, cost % 100);
- char response[16];
- scanf("%15s", response);
- all_lower(response);
-
- if(response[0] == 'y')
- {
- printf("Confirmed.\n");
-
- /* add the stock to the portfolio or increase the count of a stock */
-
- for(uint i = 0; i < player->portfolio_len; ++i)
- {
- if(strcmp(player->portfolio[i].symbol, sym) == 0)
- {
- struct stock_t *stock = player->portfolio + i;
- stock->count += count;
- stock->current_price.cents = price.cents;
- goto done;
- }
- }
-
- /* not found, add a new one */
- player->portfolio_len += 1;
- player->portfolio = realloc(player->portfolio, player->portfolio_len * sizeof(struct stock_t));
- player->need_to_free_portfolio = true;
-
- printf("sym: %s\n", sym);
- printf("name: %s\n", name);
- player->portfolio[player->portfolio_len - 1].symbol = sym;
- player->portfolio[player->portfolio_len - 1].fullname = name;
- player->portfolio[player->portfolio_len - 1].count = count;
- player->portfolio[player->portfolio_len - 1].current_price.cents = price.cents;
- done:
-
- player->cash.cents -= cost;
-
- /* sort the portfolio alphabetically by ticker symbol */
- qsort(player->portfolio, player->portfolio_len, sizeof(struct stock_t), compare_stocks);
- }
- else
- {
- printf("Not confirmed.\n");
- }
-}
-
-void sell_handler(struct player_t *player)
-{
- char *sym = malloc(16);
- printf("Enter the ticker symbol of the stock you wish to sell: ");
- scanf("%15s", sym);
- all_upper(sym);
-
- printf("Getting stock information...\n");
-
- struct stock_t *stock = NULL;
- uint stock_idx;
-
- for(stock_idx = 0; stock_idx < player->portfolio_len; ++stock_idx)
- {
- if(strcmp(player->portfolio[stock_idx].symbol, sym) == 0)
- {
- stock = player->portfolio + stock_idx;
- break;
- }
- }
-
- if(!stock)
- {
- printf("Couldn't find '%s' in portfolio.\n", sym);
- return;
- }
-
- update_handler(player);
-
- printf("You currently own %llu shares of '%s' (%s) valued at $%llu.%02llu each.\n",
- stock->count, stock->fullname, stock->symbol, stock->current_price.cents / 100, stock->current_price.cents % 100);
-
- ullong sell = 0;
- printf("How many shares do you wish to sell? ");
- scanf("%llu", &sell);
-
- if(!sell)
- {
- printf("Sale cancelled.\n");
- return;
- }
-
- if(stock->count < sell)
- {
- printf("You don't own enough shares!\n");
- return;
- }
-
- ullong sell_total = stock->current_price.cents * sell;
-
- printf("This will sell %llu shares for $%llu.%02llu total. Proceed? ", sell, sell_total / 100, sell_total % 100);
-
- char response[16];
- scanf("%15s", response);
- all_lower(response);
-
- if(response[0] == 'y')
- {
- stock->count -= sell;
-
- if(stock->count == 0)
- {
- /* remove this item from the portfolio */
- memmove(player->portfolio + stock_idx, player->portfolio + stock_idx + 1, sizeof(struct stock_t) * (player->portfolio_len - stock_idx - 1));
- player->portfolio_len -= 1;
- player->portfolio = realloc(player->portfolio, sizeof(struct stock_t) * player->portfolio_len);
- }
-
- player->cash.cents += sell_total;
-
- printf("%llu shares sold for $%llu.%02llu total.\n", sell, sell_total / 100, sell_total % 100);
- }
- else
- {
- printf("Not confirmed.\n");
- }
-}
-
-/* NOTE: integers are represented internally by unsigned long long ints, but in the save they are always 64 bits */
-
-void save_handler(struct player_t *player)
-{
- printf("Enter the file to save your portfolio in: ");
-
- char buf[128];
- scanf("%127s", buf);
-
- printf("Writing data...\n");
- FILE *f = fopen(buf, "w");
-
- const char *magic = "PORTv1";
- fwrite(magic, strlen(magic), 1, f);
-
- ullong be_cash = to_be64(player->cash.cents);
-
- fwrite(&be_cash, sizeof(be_cash), 1, f);
-
- for(uint i = 0; i < player->portfolio_len; ++i)
- {
- struct stock_t *stock = player->portfolio + i;
-
- ullong be_symlen = to_be64(strlen(stock->symbol));
- fwrite(&be_symlen, sizeof(be_symlen), 1, f);
- fwrite(stock->symbol, strlen(stock->symbol) + 1, 1, f);
-
- ullong be_count = to_be64(stock->count);
- fwrite(&be_count, sizeof(be_count), 1, f);
- }
-
- fclose(f);
-
- printf("Done saving.");
-}
-
void update_handler(struct player_t *player)
{
printf("Updating stock prices...\n");
@@ -406,79 +20,6 @@ void update_handler(struct player_t *player)
}
}
-void load_handler(struct player_t *player)
-{
- printf("Enter the file to load portfolio from: ");
- char buf[128];
- scanf("%127s", buf);
-
- printf("Loading portfolio...\n");
-
- if(player->need_to_free_portfolio)
- free(player->portfolio);
- player->portfolio_len = 0;
-
- FILE *f = fopen(buf, "r");
- char magic[6];
- if(!f || fread(magic, 1, sizeof(magic), f) != 6 || memcmp(magic, "PORTv1", sizeof(magic)) != 0)
- {
- printf("FATAL: Failed to load save.");
- exit(EXIT_FAILURE);
- }
-
- ullong cash;
- if(fread(&cash, sizeof(cash), 1, f) != 1)
- {
- printf("cash: %llu\n", cash);
- printf("FATAL: Failed to load save.");
- exit(EXIT_FAILURE);
- }
- cash = to_sys64(cash);
-
- player->cash.cents = cash;
-
- fflush(stdout);
- do {
- /* read portfolio data */
-
- player->portfolio_len += 1;
- player->portfolio = realloc(player->portfolio, player->portfolio_len * sizeof(struct stock_t));
- player->need_to_free_portfolio = true;
-
- ullong symlen;
- if(fread(&symlen, sizeof(symlen), 1, f) != 1)
- {
- printf("FATAL: Save is corrupted (symbol length too short).\n");
- exit(EXIT_FAILURE);
- }
- symlen = to_sys64(symlen);
- char *sym = malloc(symlen + 1);
- if(fread(sym, symlen + 1, 1, f) != 1)
- {
- printf("FATAL: Save is corrupted (symbol too short).\n");
- exit(EXIT_FAILURE);
- }
-
- player->portfolio[player->portfolio_len - 1].symbol = sym;
-
- ullong count;
- if(fread(&count, sizeof(count), 1, f) != 1)
- {
- printf("FATAL: Save is corrupted (count too short).\n");
- exit(EXIT_FAILURE);
- }
- count = to_sys64(count);
-
- player->portfolio[player->portfolio_len - 1].count = count;
-
- int junk = fgetc(f);
- ungetc(junk, f);
-
- } while (!feof(f) && !ferror(f));
-
- update_handler(player);
-}
-
void quit_handler(struct player_t *player)
{
exit(EXIT_SUCCESS);
diff --git a/src/save.c b/src/save.c
new file mode 100644
index 0000000..989ab60
--- /dev/null
+++ b/src/save.c
@@ -0,0 +1,37 @@
+#include "globals.h"
+
+/* NOTE: integers are represented internally by unsigned long long ints, but in the save they are always 64 bits */
+
+void save_handler(struct player_t *player)
+{
+ printf("Enter the file to save your portfolio in: ");
+
+ char buf[128];
+ scanf("%127s", buf);
+
+ printf("Writing data...\n");
+ FILE *f = fopen(buf, "w");
+
+ const char *magic = "PORTv1";
+ fwrite(magic, strlen(magic), 1, f);
+
+ uint64_t be_cash = to_be64(player->cash.cents);
+
+ fwrite(&be_cash, sizeof(be_cash), 1, f);
+
+ for(uint i = 0; i < player->portfolio_len; ++i)
+ {
+ struct stock_t *stock = player->portfolio + i;
+
+ uint64_t be_symlen = to_be64(strlen(stock->symbol));
+ fwrite(&be_symlen, sizeof(be_symlen), 1, f);
+ fwrite(stock->symbol, strlen(stock->symbol) + 1, 1, f);
+
+ uint64_t be_count = to_be64(stock->count);
+ fwrite(&be_count, sizeof(be_count), 1, f);
+ }
+
+ fclose(f);
+
+ printf("Done saving.");
+}
diff --git a/src/sell.c b/src/sell.c
new file mode 100644
index 0000000..1a04adc
--- /dev/null
+++ b/src/sell.c
@@ -0,0 +1,79 @@
+#include "globals.h"
+
+void sell_handler(struct player_t *player)
+{
+ char *sym = malloc(16);
+ printf("Enter the ticker symbol of the stock you wish to sell: ");
+ scanf("%15s", sym);
+ all_upper(sym);
+
+ printf("Getting stock information...\n");
+
+ struct stock_t *stock = NULL;
+ uint stock_idx;
+
+ for(stock_idx = 0; stock_idx < player->portfolio_len; ++stock_idx)
+ {
+ if(strcmp(player->portfolio[stock_idx].symbol, sym) == 0)
+ {
+ stock = player->portfolio + stock_idx;
+ break;
+ }
+ }
+
+ if(!stock)
+ {
+ printf("Couldn't find '%s' in portfolio.\n", sym);
+ return;
+ }
+
+ update_handler(player);
+
+ printf("You currently own %llu shares of '%s' (%s) valued at $%llu.%02llu each.\n",
+ stock->count, stock->fullname, stock->symbol, stock->current_price.cents / 100, stock->current_price.cents % 100);
+
+ ullong sell = 0;
+ printf("How many shares do you wish to sell? ");
+ scanf("%llu", &sell);
+
+ if(!sell)
+ {
+ printf("Sale cancelled.\n");
+ return;
+ }
+
+ if(stock->count < sell)
+ {
+ printf("You don't own enough shares!\n");
+ return;
+ }
+
+ ullong sell_total = stock->current_price.cents * sell;
+
+ printf("This will sell %llu shares for $%llu.%02llu total. Proceed? ", sell, sell_total / 100, sell_total % 100);
+
+ char response[16];
+ scanf("%15s", response);
+ all_lower(response);
+
+ if(response[0] == 'y')
+ {
+ stock->count -= sell;
+
+ if(stock->count == 0)
+ {
+ /* remove this item from the portfolio */
+ memmove(player->portfolio + stock_idx, player->portfolio + stock_idx + 1, sizeof(struct stock_t) * (player->portfolio_len - stock_idx - 1));
+ player->portfolio_len -= 1;
+ player->portfolio = realloc(player->portfolio, sizeof(struct stock_t) * player->portfolio_len);
+ }
+
+ player->cash.cents += sell_total;
+
+ printf("%llu shares sold for $%llu.%02llu total.\n", sell, sell_total / 100, sell_total % 100);
+ }
+ else
+ {
+ printf("Not confirmed.\n");
+ }
+}
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..cf5283f
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,177 @@
+#include "globals.h"
+
+#include <curl/curl.h>
+
+void cleanup(void)
+{
+ curl_global_cleanup();
+}
+
+struct data_buffer_t {
+ char *data;
+ uint back;
+};
+
+void all_upper(char *str)
+{
+ while(*str)
+ {
+ *str = toupper(*str);
+ ++str;
+ }
+}
+
+void all_lower(char *str)
+{
+ while(*str)
+ {
+ *str = tolower(*str);
+ ++str;
+ }
+}
+
+size_t download_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
+{
+ struct data_buffer_t *buf = userdata;
+
+ buf->data = realloc(buf->data, buf->back + size * nmemb);
+
+ memcpy(buf->data + buf->back, ptr, size * nmemb);
+
+ buf->back += size * nmemb;
+
+ return size * nmemb;
+}
+
+bool get_stock_info(char *symbol, struct money_t *price, char **name_ret)
+{
+ CURL *curl = curl_easy_init();
+ if(!curl)
+ {
+ return false;
+ }
+
+ char url[256];
+ snprintf(url, sizeof(url), "http://download.finance.yahoo.com/d/quotes.csv?s=%s&f=nl1&e=.csv", symbol);
+
+ curl_easy_setopt(curl, CURLOPT_URL, url);
+
+ struct data_buffer_t buf;
+ memset(&buf, 0, sizeof(buf));
+
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, download_callback);
+
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buf);
+
+ CURLcode res = curl_easy_perform(curl);
+
+ curl_easy_cleanup(curl);
+
+ /** now parse the data **/
+
+ /* the stock name is in quotes, find it! */
+
+ /* check for validity */
+ if(buf.back == 0 || buf.data[0] != '"' || res != CURLE_OK)
+ {
+ printf("Failed to retrieve stock data.\n");
+ if(res != CURLE_OK)
+ {
+ printf("Download library error (%d): '%s'\n", res, curl_easy_strerror(res));
+ }
+ return false;
+ }
+
+ uint name_len = 0;
+ for(uint i = 1; i < buf.back; ++i)
+ {
+ if(buf.data[i] == '"')
+ break;
+ ++name_len;
+ }
+
+ const uint name_offs = 1;
+ uint price_offs = name_len + 3;
+ uint price_len = buf.back - price_offs;
+
+ char *name = malloc(name_len + 1);
+ memcpy(name, buf.data + name_offs, name_len);
+ name[name_len] = '\0';
+
+ *name_ret = name;
+
+ /* get price */
+
+ char *pricebuf = malloc(price_len + 1);
+ memcpy(pricebuf, buf.data + price_offs, price_len);
+ pricebuf[price_len] = '\0';
+
+ free(buf.data);
+
+ /* remove the decimal point */
+
+ for(int i = 0; i < price_len; ++i)
+ {
+ if(pricebuf[i] == '.')
+ memmove(pricebuf + i, pricebuf + i + 1, price_len - i);
+ }
+
+ price->cents = strtoull(pricebuf, NULL, 10);
+
+ free(pricebuf);
+
+ return true;
+}
+
+int compare_stocks(const void *a, const void *b)
+{
+ const struct stock_t *a1 = a, *b1 = b;
+ return strcmp(a1->symbol,
+ b1->symbol);
+}
+
+static enum { OTHER = 0, LITTLE = 1, BIG = 2 } endianness;
+
+static void detect_endianness(void)
+{
+ ulong test = 0x12345678;
+ uchar *ptr = (uchar*)&test;
+ if(*ptr == 0x12)
+ endianness = BIG;
+ else if(*ptr == 0x78)
+ endianness = LITTLE;
+ else
+ {
+ printf("FATAL: failed to detect system endianness!\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+uint64_t to_be64(uint64_t n)
+{
+ if(!endianness)
+ {
+ detect_endianness();
+ }
+
+ if(BIG)
+ {
+ n = (n & 0x00000000FFFFFFFF) << 32 | (n & 0xFFFFFFFF00000000) >> 32;
+ n = (n & 0x0000FFFF0000FFFF) << 16 | (n & 0xFFFF0000FFFF0000) >> 16;
+ n = (n & 0x00FF00FF00FF00FF) << 8 | (n & 0xFF00FF00FF00FF00) >> 8;
+ }
+ return n;
+}
+
+uint64_t to_sys64(uint64_t n)
+{
+ if(!endianness)
+ {
+ detect_endianness();
+ }
+
+ if(endianness == BIG)
+ return n;
+ else
+ return to_be64(n);
+}