diff options
| -rw-r--r-- | Makefile | 4 | ||||
| -rw-r--r-- | src/buy.c | 22 | ||||
| -rw-r--r-- | src/globals.h | 2 | ||||
| -rw-r--r-- | src/help.c | 30 | ||||
| -rw-r--r-- | src/history.c | 8 | ||||
| -rw-r--r-- | src/info.c | 16 | ||||
| -rw-r--r-- | src/load.c | 4 | ||||
| -rw-r--r-- | src/main.c | 11 | ||||
| -rw-r--r-- | src/menu.c | 6 | ||||
| -rw-r--r-- | src/save.c | 6 | ||||
| -rw-r--r-- | src/sell.c | 22 | ||||
| -rw-r--r-- | src/util.c | 62 |
12 files changed, 116 insertions, 77 deletions
@@ -7,11 +7,13 @@ GIT_VERSION := $(shell git describe --abbrev=8 --dirty --always --tags) CFLAGS = -Isrc/ -O2 -g -Wall -Wextra -std=gnu99 -fsanitize=address -DVERSION_INFO=\"$(GIT_VERSION)\" +LIBS = -lcurl -lcurses + HEADERS := $(wildcard src/*.h) market-sim: $(OBJ) Makefile $(HEADERS) @echo "LD $@" - @$(CC) $(OBJ) -o $@ $(CFLAGS) -lcurl + @$(CC) $(OBJ) -o $@ $(CFLAGS) $(LIBS) %.o: %.c Makefile $(HEADERS) @echo "CC $<" @@ -2,31 +2,31 @@ void buy_handler(struct player_t *player) { - printf("Enter the ticker symbol of the stock you wish to purchase: "); + output("Enter the ticker symbol of the stock you wish to purchase: "); char *sym = read_ticker(); struct money_t price; - printf("Getting stock information...\n"); + output("Getting stock information...\n"); char *name; if(!get_stock_info(sym, &price, &name)) { - printf("Failed to get query information for '%s'.\n", sym); + output("Failed to get query information for '%s'.\n", sym); free(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); + output("Stock name: %s\n", name); + output("Price per share: $%llu.%02llu\n", price.cents / 100, price.cents % 100); + output("Enter the number of shares to be purchased (maximum %llu): ", player->cash.cents / price.cents); ullong count = read_int(); if(count <= 0) { - printf("Purchase cancelled.\n"); + output("Purchase cancelled.\n"); return; } @@ -34,17 +34,17 @@ void buy_handler(struct player_t *player) if(cost > player->cash.cents) { - printf("Not enough money!\n"); + output("Not enough money!\n"); return; } - printf("This will cost $%llu.%02llu. Are you sure? ", cost / 100, cost % 100); + output("This will cost $%llu.%02llu. Are you sure? ", cost / 100, cost % 100); char *response = read_string(); all_lower(response); if(response[0] == 'y') { - printf("Confirmed.\n"); + output("Confirmed.\n"); struct stock_t *stock = find_stock(player, sym); @@ -82,7 +82,7 @@ void buy_handler(struct player_t *player) } else { - printf("Not confirmed.\n"); + output("Not confirmed.\n"); } free(response); diff --git a/src/globals.h b/src/globals.h index 9735657..b85ecc0 100644 --- a/src/globals.h +++ b/src/globals.h @@ -11,6 +11,7 @@ #include <stdarg.h> #include <curl/curl.h> +#include <ncurses.h> #define ARRAYLEN(x) (sizeof(x) / sizeof(x[0])) @@ -109,6 +110,7 @@ void load_portfolio(struct player_t*, const char*); void print_history(struct stock_t*); void print_usage(int argc, char *argv[]); void print_version(void); +int output(const char*, ...); void buy_handler(struct player_t*); void info_handler(struct player_t*); @@ -4,24 +4,24 @@ void print_usage(int argc, char *argv[]) { assert(argc > 1); - printf("Usage: %s [OPTION] [PORTFOLIO]\n", argv[0]); - printf("Runs a simulated trading session with PORTFOLIO (creating a new one by default).\n\n"); + output("Usage: %s [OPTION] [PORTFOLIO]\n", argv[0]); + output("Runs a simulated trading session with PORTFOLIO (creating a new one by default).\n\n"); - printf("Options:\n"); - printf(" -h, --help\tShow this help and exit\n"); - printf(" -v, --verbose\tEnable verbose operation\n"); - printf(" --version\tOutput version information and exit\n"); + output("Options:\n"); + output(" -h, --help\tShow this help and exit\n"); + output(" -v, --verbose\tEnable verbose operation\n"); + output(" --version\tOutput version information and exit\n"); } void print_version(void) { - printf("market-sim " PROGRAM_VERSION "\n"); - printf("Built with %s.\n", curl_version()); - printf("Build date: %s\n", __DATE__); - printf("Copyright (C) 2015 Franklin Wei.\n\n"); - printf("License GPLv2: GNU GPL version 2 <http://www.gnu.org/licenses/gpl-2.0.html>\n"); - printf("This program is distributed in the hope that it will be useful, but WITHOUT ANY\n"); - printf("WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A\n"); - printf("PARTICULAR PURPOSE.\n"); - printf("See the GNU General Public License version 2 for more details.\n"); + output("market-sim " PROGRAM_VERSION "\n"); + output("Built with %s.\n", curl_version()); + output("Build date: %s\n", __DATE__); + output("Copyright (C) 2015 Franklin Wei.\n\n"); + output("License GPLv2: GNU GPL version 2 <http://www.gnu.org/licenses/gpl-2.0.html>\n"); + output("This program is distributed in the hope that it will be useful, but WITHOUT ANY\n"); + output("WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A\n"); + output("PARTICULAR PURPOSE.\n"); + output("See the GNU General Public License version 2 for more details.\n"); } diff --git a/src/history.c b/src/history.c index bcb63ae..c7aa1be 100644 --- a/src/history.c +++ b/src/history.c @@ -49,21 +49,21 @@ void print_history(struct stock_t *stock) { ullong total = hist->count * hist->price.cents; - printf("[%d-%d-%d %d:%02d:%02d] ", hist->action_time.year + EPOCH_YEAR, hist->action_time.month + 1, hist->action_time.day + 1, + output("[%d-%d-%d %d:%02d:%02d] ", hist->action_time.year + EPOCH_YEAR, hist->action_time.month + 1, hist->action_time.day + 1, hist->action_time.hour, hist->action_time.minute, hist->action_time.second); switch(hist->action) { case BUY: - printf("[BUY] %llu shares for $%llu.%02llu each (+$%llu.%02llu).\n", hist->count, hist->price.cents / 100, hist->price.cents % 100, + output("[BUY] %llu shares for $%llu.%02llu each (+$%llu.%02llu).\n", hist->count, hist->price.cents / 100, hist->price.cents % 100, total / 100, total % 100); break; case SELL: - printf("[SELL] %llu shares for $%llu.%02llu each (-$%llu.%02llu).\n", hist->count, hist->price.cents / 100, hist->price.cents % 100, + output("[SELL] %llu shares for $%llu.%02llu each (-$%llu.%02llu).\n", hist->count, hist->price.cents / 100, hist->price.cents % 100, total / 100, total % 100); break; default: - printf("unknown history enum (%d).\n", hist->action); + output("unknown history enum (%d).\n", hist->action); break; } hist = hist->next; @@ -3,32 +3,32 @@ void info_handler(struct player_t *player) { char *sym; - printf("Enter the ticker symbol of the stock to get information for: "); + output("Enter the ticker symbol of the stock to get information for: "); sym = read_ticker(); struct stock_t *stock = find_stock(player, sym); if(!stock) { - printf("Couldn't find '%s' in portfolio.\n", sym); + output("Couldn't find '%s' in portfolio.\n", sym); free(sym); return; } - printf("Updating price data...\n"); + output("Updating price data...\n"); if(!get_stock_info(sym, &stock->current_price, &stock->fullname)) { - printf("Failed to update prices.\n"); + output("Failed to update prices.\n"); return; } free(sym); - printf("Transaction history for '%s':\n", stock->symbol); - printf("================================================================================\n"); + output("Transaction history for '%s':\n", stock->symbol); + output("================================================================================\n"); print_history(stock); - printf("================================================================================\n"); + output("================================================================================\n"); - printf("Current price: $%llu.%02llu\n", stock->current_price.cents / 100, stock->current_price.cents % 100); + output("Current price: $%llu.%02llu\n", stock->current_price.cents / 100, stock->current_price.cents % 100); } @@ -82,7 +82,7 @@ size_t ck_read(char *buf, size_t sz, size_t nmemb, FILE* f) void load_portfolio(struct player_t *player, const char *filename) { - printf("Loading portfolio...\n"); + output("Loading portfolio...\n"); if(player->need_to_free_portfolio) free(player->portfolio); @@ -174,7 +174,7 @@ void load_portfolio(struct player_t *player, const char *filename) void load_handler(struct player_t *player) { - printf("Enter the file to load portfolio from: "); + output("Enter the file to load portfolio from: "); char *filename = read_string(); load_portfolio(player, filename); @@ -10,10 +10,19 @@ void quit_handler(struct player_t *player) int main(int argc, char *argv[]) { - atexit(cleanup); curl_global_init(CURL_GLOBAL_DEFAULT); + atexit(cleanup); + + initscr(); + echo(); + nocbreak(); + nl(); + scrollok(stdscr, true); + + atexit(endwin); + struct player_t *player = malloc(sizeof(struct player_t)); memset(player, 0, sizeof(struct player_t)); @@ -4,10 +4,10 @@ void do_menu(struct player_t *player, const struct command_t *commands, uint len { for(uint i = 0; i < len; ++i) { - printf("%d. %s\n", i + 1, commands[i].name); + output("%d. %s\n", i + 1, commands[i].name); } - printf("%s", prompt); + output("%s", prompt); char *cmdbuf = read_string(); all_lower(cmdbuf); @@ -64,7 +64,7 @@ exec_cmd: if(best_command >= 0) { commands[best_command].handler(player); - printf("\n"); + output("\n"); } free(cmdbuf); @@ -65,11 +65,11 @@ size_t ck_write(const char *buf, size_t sz, size_t nmemb, FILE *f) void save_handler(struct player_t *player) { - printf("Enter the file to save your portfolio in: "); + output("Enter the file to save your portfolio in: "); char *filename = read_string(); - printf("Writing data...\n"); + output("Writing data...\n"); FILE *f = fopen(filename, "wb"); free(filename); @@ -115,5 +115,5 @@ void save_handler(struct player_t *player) fclose(f); - printf("Done saving.\n"); + output("Done saving.\n"); } @@ -2,10 +2,10 @@ void sell_handler(struct player_t *player) { - printf("Enter the ticker symbol of the stock you wish to sell: "); + output("Enter the ticker symbol of the stock you wish to sell: "); char *sym = read_ticker(); - printf("Getting stock information...\n"); + output("Getting stock information...\n"); struct stock_t *stock = NULL; @@ -13,38 +13,38 @@ void sell_handler(struct player_t *player) if(!stock) { - printf("Couldn't find '%s' in portfolio.\n", sym); + output("Couldn't find '%s' in portfolio.\n", sym); free(sym); return; } free(sym); - printf("Updating prices...\n"); + output("Updating prices...\n"); get_stock_info(stock->symbol, &stock->current_price, &stock->fullname); - printf("You currently own %llu share(s) of '%s' (%s) valued at $%llu.%02llu each.\n", + output("You currently own %llu share(s) 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); - printf("How many shares do you wish to sell? "); + output("How many shares do you wish to sell? "); ullong sell_count = read_int(); if(!sell_count) { - printf("Sale cancelled.\n"); + output("Sale cancelled.\n"); return; } if(stock->count < sell_count) { - printf("You don't own enough shares!\n"); + output("You don't own enough shares!\n"); return; } ullong sell_total = stock->current_price.cents * sell_count; - printf("This will sell %llu share(s) for $%llu.%02llu total.\nProceed? ", sell_count, sell_total / 100, sell_total % 100); + output("This will sell %llu share(s) for $%llu.%02llu total.\nProceed? ", sell_count, sell_total / 100, sell_total % 100); char *response = read_string(); @@ -67,11 +67,11 @@ void sell_handler(struct player_t *player) add_hist(stock, SELL, sell_count); - printf("%llu share(s) sold for $%llu.%02llu total.\n", sell_count, sell_total / 100, sell_total % 100); + output("%llu share(s) sold for $%llu.%02llu total.\n", sell_count, sell_total / 100, sell_total % 100); } else { - printf("Not confirmed.\n"); + output("Not confirmed.\n"); } free(response); @@ -67,7 +67,7 @@ bool get_stock_info(char *symbol, struct money_t *price, char **name_ret) if(res != CURLE_OK || buf.data[0] != '"') { - printf("Failed querying information for '%s'.\n", symbol); + output("Failed querying information for '%s'.\n", symbol); return false; } @@ -182,14 +182,14 @@ struct stock_t *find_stock(struct player_t *player, char *sym) void print_handler(struct player_t *player) { - printf("Your portfolio:\n"); - printf("================================================================================\n"); + output("Your portfolio:\n"); + output("================================================================================\n"); ullong portfolio_value = 0; if(player->portfolio_len == 0) { - printf(" < EMPTY >\n"); + output(" < EMPTY >\n"); } else { @@ -199,7 +199,7 @@ void print_handler(struct player_t *player) if(stock->count) { ullong total_value = stock->count * stock->current_price.cents; - printf("%6s %40s %5llu * $%5llu.%02llu = $%6llu.%02llu\n", + output("%6s %40s %5llu * $%5llu.%02llu = $%6llu.%02llu\n", stock->symbol, stock->fullname, stock->count, stock->current_price.cents / 100, stock->current_price.cents % 100, total_value / 100, total_value % 100); @@ -207,24 +207,36 @@ void print_handler(struct player_t *player) } } } - printf("================================================================================\n"); + output("================================================================================\n"); - printf("Portfolio value: $%llu.%02llu\n", portfolio_value / 100, portfolio_value % 100); + output("Portfolio value: $%llu.%02llu\n", portfolio_value / 100, portfolio_value % 100); - printf("Cash balance: $%llu.%02llu\n", player->cash.cents / 100, player->cash.cents % 100); + output("Cash balance: $%llu.%02llu\n", player->cash.cents / 100, player->cash.cents % 100); ullong total = portfolio_value + player->cash.cents; - printf("Total capital: $%llu.%02llu\n", total / 100, total % 100); + output("Total capital: $%llu.%02llu\n", total / 100, total % 100); } char *read_string(void) { - char *ret = NULL; - size_t len = 0; - len = getline(&ret, &len, stdin); - if(len) - ret[len - 1] = '\0'; + char *ret = malloc(1); + size_t len = 1; + + ret[0] = '\0'; + + char c; + do { + c = getch(); + if(c != '\b' && c != '\n') + { + ++len; + ret = realloc(ret, len); + ret[len - 1] = '\0'; + ret[len - 2] = c; + } + } while(c != '\n'); + return ret; } @@ -248,13 +260,13 @@ ullong read_int(void) void update_handler(struct player_t *player) { - printf("Updating stock prices...\n"); + output("Updating stock prices...\n"); for(uint i = 0; i < player->portfolio_len; ++i) { struct stock_t *stock = player->portfolio + i; if(stock->count > 0) { - printf("%s...\n", stock->symbol); + output("%s...\n", stock->symbol); get_stock_info(stock->symbol, &stock->current_price, &stock->fullname); } } @@ -304,7 +316,7 @@ uint parse_args(struct player_t *player, int argc, char *argv[]) } else { - printf("FATAL: multiple portfolio files specified.\n"); + output("FATAL: multiple portfolio files specified.\n"); ret |= ARG_FAILURE; break; } @@ -330,7 +342,21 @@ void fail(const char *fmt, ...) vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); - fprintf(stderr, "FATAL: %s\n", buf); + output("FATAL: %s\n", buf); exit(EXIT_FAILURE); } + +int output(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + + int ret = vwprintw(stdscr, fmt, ap); + + refresh(); + + va_end(ap); + + return ret; +} |