#include #include #include #include #include "termbox_render.h" #include "oct_termbox_sprite.h" #include "oct_networking.h" #include "oct_log.h" #define TB_IMPL #include "termbox.h" #define OCT_MAX_FILENAME_SIZE 1024 #define OCT_VERSION "0.0" #define OCT_URL "https://git.thejerks.club/j4nk/open-card-table" int oct_type; lua_State *L = NULL; struct { char port[6]; // max 65535 so 6 bytes needed // Might come in handy later to keep filename // e.g. if I ever want to allow downloading a script from peer char lua_file[OCT_MAX_FILENAME_SIZE]; int needs_termbox; int needs_networking; } config; void usage(); void version(); int process_args(int argc, char* argv[]); int initialize_everything(char* lua_file); int deinitialize_everything(); int finish = 0; void handle_sigint() {finish = 1;}; int main(int argc, char* argv[]) { if (!process_args(argc, argv)) { return EXIT_FAILURE; } // initialize SIGINT handler struct sigaction sa = {0}; sa.sa_handler = handle_sigint; sigaction(SIGINT, &sa, NULL); struct tb_event ev; if (config.needs_termbox) { while (!finish) { tb_clear(); tb_peek_event(&ev, 10); if (ev.key == TB_KEY_ESC) { finish = 1; } oct_network_recv_msg(); lua_getglobal(L, "oct_loop"); lua_pushinteger(L, ev.key); lua_pushinteger(L, ev.ch); lua_call(L, 2, 0); for (uint32_t i=0; i < oct_tb_sprite_list.new_index; i++) { oct_render_termbox_sprite(oct_tb_sprite_list.sprite_list[i]); } tb_present(); oct_network_send_msg(); } } else { while (!finish) { oct_network_recv_msg(); lua_getglobal(L, "oct_loop"); lua_pushinteger(L, 0); lua_pushinteger(L, 0); if (lua_pcall(L, 2, 0, 0) != LUA_OK) { OCT_LOG_ERROR("%s", luaL_checkstring(L, -1)); finish = 1; } oct_network_send_msg(); } } deinitialize_everything(); return EXIT_SUCCESS; } int process_args(int argc, char* argv[]) { if (argc == 1) { // Didn't specify a file // Can't use oct_log as logging is not init fprintf(stderr, "Error: No lua file given\n\n"); usage(); return 0; } // Set config.port to default strncpy(config.port, OCT_DEFAULT_PORT, 6); int log_level = OCT_LOG_LEVEL_ERROR; char log_file[OCT_MAX_FILENAME_SIZE]; int log_file_spec = 0; int valid_last_argument = 0; for (int i = 1; i < argc; i++) { // argv's are guaranteed to be zero-terminated, so can use // strcmp instead of strncmp if (strcmp(argv[i], "-p") == 0) { if (i+1 < argc) { strncpy(config.port, argv[i+1], 6); i++; } else { fprintf(stderr, "Error: need to specify a port after -p\n"); return 0; } } else if (strcmp(argv[i], "-h") == 0) { usage(); return 0; } else if (strcmp(argv[i], "-v") == 0) { version(); return 0; } else if (strcmp(argv[i], "-ll") == 0) { if (i+1 < argc) { char* endptr = NULL; log_level = strtoul(argv[i+1], &endptr, 10); if (log_level == 0 && endptr == argv[i+1]) { printf("Error: invalid log level\n"); return 0; } i++; } else { fprintf(stderr, "Error: need to specify a log level after -ll\n"); return 0; } } else if (strcmp(argv[i], "-lf") == 0) { if (i+1 < argc) { strncpy(log_file, argv[i+1], OCT_MAX_FILENAME_SIZE); log_file_spec = 1; i++; } else { fprintf(stderr, "Error: need to specify a log file after -lf\n"); return 0; } } else { // This is the lua file to run if (i == argc-1) { valid_last_argument = 1; break; } // Invalid argument else { fprintf(stderr, "Error: invalid argument %s\n", argv[i]); return 0; } } } if (!valid_last_argument) { return 0; } oct_log_init(log_file_spec ? log_file : NULL, log_level); strncpy(config.lua_file, argv[argc-1], OCT_MAX_FILENAME_SIZE); OCT_LOG_INFO("Running lua file: %s", config.lua_file); return initialize_everything(config.lua_file); } int initialize_everything(char* lua_file) { // Check if file exists if (access(lua_file, F_OK) != 0) { // oct_log is init by this time, but don't want PITA bug in case this changes fprintf(stderr, "Error: Could not open file: %s\n", lua_file); deinitialize_everything(); return 0; } if (!oct_tb_sprite_list_initialize()) { return 0; } OCT_LOG_INFO("Initialized the sprite list"); L = luaL_newstate(); if (L == NULL) { OCT_LOG_ERROR("Can't initialize Lua\n"); return 0; } OCT_LOG_INFO("Initialized lua state"); luaL_openlibs(L); oct_tb_initialize_lua(L); oct_log_init_lua(L); if (luaL_dofile(L, lua_file)) { OCT_LOG_ERROR("%s", luaL_checkstring(L, -1)); deinitialize_everything(); return 0; } OCT_LOG_INFO("Begin running oct_init()"); lua_getglobal(L, "oct_init"); if (lua_pcall(L, 0, 2, 0) != LUA_OK) { OCT_LOG_ERROR("%s", luaL_checkstring(L, -1)); deinitialize_everything(); return 0; } config.needs_networking = lua_tointeger(L, -2); config.needs_termbox = lua_tointeger(L, -1); OCT_LOG_INFO("Finish running oct_init()"); OCT_LOG_INFO("Lua script %s termbox", config.needs_termbox ? "requires" : "does not require"); if (!config.needs_termbox) { oct_tb_change_oct_tb_sprite_new(L); } OCT_LOG_INFO("Lua script %s networking", config.needs_networking ? "requires" : "does not require"); if (config.needs_networking) { if (!oct_network_node_init(config.port, L)) { OCT_LOG_ERROR("Could not establish a socket on port %s\n", config.port); deinitialize_everything(); return 0; } // initialize the address book oct_network_ab_init(); } if (config.needs_termbox) { tb_init(); } return 1; } int deinitialize_everything() { OCT_LOG_INFO("Deinitializing everything"); tb_shutdown(); if (L) lua_close(L); oct_tb_sprite_list_deinitialize(); oct_network_ab_deinit(); //oct_network_node_deinit(); oct_log_deinit(); return 1; } void usage() { fprintf(stderr, "Open Card Table, version %s\n", OCT_VERSION); fprintf(stderr, "%s\n", OCT_URL); fprintf(stderr, "\n"); fprintf(stderr, "Usage: ./open_card_table [OPTIONS] FILE\n"); fprintf(stderr, "\n"); fprintf(stderr, " -p\t\tPort on which to listen\n"); fprintf(stderr, " -v\t\tPrint version and exit\n"); fprintf(stderr, " -h\t\tPrint this message and exit\n"); fprintf(stderr, " -ll\t\t Set log level: 0=err, 1=warn, 2=info, 3=debug\n"); fprintf(stderr, " -lf\t\t Specify log output file\n"); fprintf(stderr, "\n"); } void version() { fprintf(stderr, "%s\n", OCT_VERSION); }