From b4c20b3cc1f5429650f79a6fd95b5e3d5bc4d4e5 Mon Sep 17 00:00:00 2001 From: Franklin Wei Date: Mon, 11 May 2015 18:40:30 -0400 Subject: lots of stuff, buying mostly works --- src/main.c | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 151 insertions(+), 24 deletions(-) (limited to 'src/main.c') diff --git a/src/main.c b/src/main.c index e2efec6..b153de5 100644 --- a/src/main.c +++ b/src/main.c @@ -2,10 +2,13 @@ #include +#include #include #include #include +/*** utility functions ***/ + void cleanup(void) { curl_global_cleanup(); @@ -18,15 +21,23 @@ struct data_buffer_t { void all_upper(char *str) { - while(*++str = toupper(*str)); + while(*str) + { + *str = toupper(*str); + ++str; + } } void all_lower(char *str) { - while(*++str = tolower(*str)); + while(*str) + { + *str = tolower(*str); + ++str; + } } -size_t curl_callback(char *ptr, size_t size, size_t nmemb, void *userdata) +size_t download_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { struct data_buffer_t *buf = userdata; @@ -36,7 +47,7 @@ size_t curl_callback(char *ptr, size_t size, size_t nmemb, void *userdata) buf->back += size * nmemb; - return CURLE_OK; + return size * nmemb; } bool get_stock_info(char *symbol, struct money_t *price, char **name_ret) @@ -55,16 +66,29 @@ bool get_stock_info(char *symbol, struct money_t *price, char **name_ret) struct data_buffer_t buf; memset(&buf, 0, sizeof(buf)); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buf); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, download_callback); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_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) { @@ -106,47 +130,96 @@ bool get_stock_info(char *symbol, struct money_t *price, char **name_ret) 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); +} + +ullong to_be64(ullong n) +{ + n = (n & 0x00000000FFFFFFFF) << 32 | (n & 0xFFFFFFFF00000000) >> 32; + n = (n & 0x0000FFFF0000FFFF) << 16 | (n & 0xFFFF0000FFFF0000) >> 16; + n = (n & 0x00FF00FF00FF00FF) << 8 | (n & 0xFF00FF00FF00FF00) >> 8; + return n; +} + +/*** driver functions ***/ + void buy_handler(struct player_t *player) { - char sym[16]; + 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); + printf("Failed to get query information for '%s'.\n", sym); + return; } + printf("Stock name: %s\n", name); printf("Price per share: $%d.%02d\n", price.cents / 100, price.cents % 100); printf("Enter the number of shares to be purchased (maximum %u): ", player->cash.cents / price.cents); + ullong count = 0; + scanf("%llu", &count); + ullong cost = price.cents * count; if(cost > player->cash.cents) { - printf("Not enough money!\n"); + printf("You don't have enough money!\n"); return; } printf("This will cost $%d.%02d. Are you sure? ", cost / 100, cost % 100); char response[16]; scanf("%15s", response); - if(response[0] == 'Y' || response[0] == 'y') + 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); + player->portfolio = realloc(player->portfolio, player->portfolio_len * sizeof(struct stock_t)); - player->portfolio[player->portfolio_len - 1].symbol = strdup(sym); - player->portfolio[player->portfolio_len - 1].fullname = strdup(name); + 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 { @@ -160,6 +233,33 @@ void sell_handler(struct player_t *player) 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; + fwrite(stock->symbol, strlen(stock->symbol) + 1, 1, f); + fwrite(stock->fullname, strlen(stock->fullname) + 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) @@ -172,6 +272,16 @@ 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"); + +} + void quit_handler(struct player_t *player) { exit(EXIT_SUCCESS); @@ -192,20 +302,37 @@ int main(int argc, char *argv[]) while(1) { - printf("Your portfolio:\n"); - printf("===============\n"); - for(int i = 0; i < player->portfolio_len; ++i) + printf("\nYour portfolio:\n"); + printf("================================================================================"); + + ullong portfolio_value = 0; + + if(player->portfolio_len == 0) { - struct stock_t *stock = player->portfolio + i; - ullong total_value = stock->count * stock->current_price.cents; - printf("%5s %30s %5d * $%d.%02d = $%d.%d\n", - stock->symbol, stock->fullname, stock->count, stock->current_price.cents / 100, stock->current_price.cents % 100, - total_value / 100, total_value % 100); + printf(" < EMPTY >\n"); } - printf("===============\n"); + else + { + for(int i = 0; i < player->portfolio_len; ++i) + { + struct stock_t *stock = player->portfolio + i; + ullong total_value = stock->count * stock->current_price.cents; + printf("%5s %30s %5d * $%5d.%02d = $%6d.%02d\n", + stock->symbol, stock->fullname, stock->count, stock->current_price.cents / 100, stock->current_price.cents % 100, + total_value / 100, total_value % 100); + + portfolio_value += stock->current_price.cents * stock->count; + } + } + printf("================================================================================\n"); + + printf("Portfolio value: $%d.%02d\n", portfolio_value / 100, portfolio_value % 100); printf("Current cash: $%d.%02d\n", player->cash.cents / 100, player->cash.cents % 100); + ullong total = portfolio_value + player->cash.cents; + printf("Total capital: $%d.%02d\n", total / 100, total % 100); + struct command_t { const char *name; const char *command; @@ -215,8 +342,9 @@ int main(int argc, char *argv[]) const struct command_t commands[] = { { "[B]uy", "buy", buy_handler }, { "[S]ell", "sell", sell_handler }, + { "[U]pdate stock prices", "update", update_handler },d { "[W]rite portfolio", "write", save_handler }, - { "[U]pdate stock prices", "update", update_handler }, + { "[L]oad portfolio", "load", load_handler }, { "[Q]uit", "quit", quit_handler }, }; @@ -230,7 +358,6 @@ int main(int argc, char *argv[]) scanf("%31s", cmdbuf); all_lower(cmdbuf); - /* find the best command */ int best_command = -1; -- cgit v1.1