From 3b89a135dcde9779bd0537cd136a7c34cfadbe3f Mon Sep 17 00:00:00 2001 From: shennetsind Date: Sun, 17 Mar 2013 01:12:33 -0300 Subject: Re-Introducing Console Input It's back. It's efficient. It's awesome. http://hercules.ws/board/topic/272-re-introducing-console-input/ Signed-off-by: shennetsind --- src/common/console.c | 186 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 src/common/console.c (limited to 'src/common/console.c') diff --git a/src/common/console.c b/src/common/console.c new file mode 100644 index 000000000..ee4570b2a --- /dev/null +++ b/src/common/console.c @@ -0,0 +1,186 @@ +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams + +#include "../common/showmsg.h" +#include "../common/console.h" +#include "../config/core.h" +#include "core.h" + +#ifndef MINICORE + #include "../common/atomic.h" + #include "../common/spinlock.h" + #include "../common/thread.h" + #include "../common/mutex.h" + #include "../common/timer.h" + #include "../common/strlib.h" +#endif + +#include +#include +#ifndef _WIN32 + #include +#else + #include "../common/winapi.h" // Console close event handling +#endif + +#ifdef CONSOLE_INPUT + #ifdef _WIN32 + #include /* _kbhit() */ + #endif +#endif + +/*====================================== + * CORE : Display title + *--------------------------------------*/ +void display_title(void) { + const char* svn = get_svn_revision(); + const char* git = get_git_hash(); + + ShowMessage("\n"); + ShowMessage(""CL_BG_RED" "CL_BT_WHITE" "CL_BG_RED""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_BG_RED" "CL_BT_WHITE" Hercules Development Team presents "CL_BG_RED""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_BG_RED" "CL_BT_WHITE" _ _ _ "CL_BG_RED""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_BG_RED" "CL_BT_WHITE" | | | | | | "CL_BG_RED""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_BG_RED" "CL_BT_WHITE" | |_| | ___ _ __ ___ _ _| | ___ ___ "CL_BG_RED""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_BG_RED" "CL_BT_WHITE" | _ |/ _ \\ '__/ __| | | | |/ _ \\/ __|"CL_BG_RED""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_BG_RED" "CL_BT_WHITE" | | | | __/ | | (__| |_| | | __/\\__ \\"CL_BG_RED""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_BG_RED" "CL_BT_WHITE" \\_| |_/\\___|_| \\___|\\__,_|_|\\___||___/"CL_BG_RED""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_BG_RED" "CL_BT_WHITE" "CL_BG_RED""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_BG_RED" "CL_BT_WHITE" http://hercules.ws/board/ "CL_BG_RED""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_BG_RED" "CL_BT_WHITE" "CL_BG_RED""CL_CLL""CL_NORMAL"\n"); + + if( git[0] != HERC_UNKNOWN_VER ) + ShowInfo("Git Hash: '"CL_WHITE"%s"CL_RESET"'\n", git); + else if( svn[0] != HERC_UNKNOWN_VER ) + ShowInfo("SVN Revision: '"CL_WHITE"%s"CL_RESET"'\n", svn); +} +#ifdef CONSOLE_INPUT +#ifdef _WIN32 +int console_parse_key_pressed(void) { + return _kbhit(); +} +#else /* _WIN32 */ +int console_parse_key_pressed(void) { + struct timeval tv; + fd_set fds; + tv.tv_sec = 0; + tv.tv_usec = 0; + + FD_ZERO(&fds); + FD_SET(STDIN_FILENO, &fds); + + select(STDIN_FILENO+1, &fds, NULL, NULL, &tv); + + return FD_ISSET(STDIN_FILENO, &fds); +} +#endif /* _WIN32 */ + +void console_parse(char* line) { + int c, i = 0, len = MAX_CONSOLE_INPUT - 1;/* we leave room for the \0 :P */ + + while( (c = fgetc(stdin)) != EOF ) { + if( --len == 0 ) + break; + if( (line[i++] = c) == '\n') { + line[i-1] = '\0';/* clear, we skip the new line */ + break;/* new line~! we leave it for the next cycle */ + } + } + + line[i++] = '\0'; +} +void *cThread_main(void *x) { + + while( console->ptstate ) {/* loopx */ + if( console->key_pressed() ) { + char input[MAX_CONSOLE_INPUT]; + + console->parse(input); + if( input[0] != '\0' ) {/* did we get something? */ + EnterSpinLock(&console->ptlock); + + if( cinput.count == CONSOLE_PARSE_SIZE ) { + LeaveSpinLock(&console->ptlock); + continue;/* drop */ + } + + safestrncpy(cinput.queue[cinput.count++],input,MAX_CONSOLE_INPUT); + LeaveSpinLock(&console->ptlock); + } + } + ramutex_lock( console->ptmutex ); + racond_wait( console->ptcond, console->ptmutex, -1 ); + ramutex_unlock( console->ptmutex ); + } + + return NULL; +} +int console_parse_timer(int tid, unsigned int tick, int id, intptr_t data) { + int i; + EnterSpinLock(&console->ptlock); + for(i = 0; i < cinput.count; i++) { + parse_console(cinput.queue[i]); + } + cinput.count = 0; + LeaveSpinLock(&console->ptlock); + racond_signal(console->ptcond); + return 0; +} +void console_parse_final(void) { + InterlockedDecrement(&console->ptstate); + racond_signal(console->ptcond); + + /* wait for thread to close */ + rathread_wait(console->pthread, NULL); + + racond_destroy(console->ptcond); + ramutex_destroy(console->ptmutex); + +} +void console_parse_init(void) { + cinput.count = 0; + + console->ptstate = 1; + + InitializeSpinLock(&console->ptlock); + + console->ptmutex = ramutex_create(); + console->ptcond = racond_create(); + + if( (console->pthread = rathread_create(console->pthread_main, NULL)) == NULL ){ + ShowFatalError("console_parse_init: failed to spawn console_parse thread.\n"); + exit(EXIT_FAILURE); + } + + add_timer_func_list(console->parse_timer, "console_parse_timer"); + add_timer_interval(gettick() + 1000, console->parse_timer, 0, 0, 500);/* start listening in 1s; re-try every 0.5s */ + +} +#endif /* CONSOLE_INPUT */ + +void console_init (void) { + console->display_title(); +#ifdef CONSOLE_INPUT + console->parse_init(); +#endif +} +void console_final(void) { +#ifdef CONSOLE_INPUT + console->parse_final(); +#endif +} +void console_defaults(void) { + console = &console_s; + console->init = console_init; + console->final = console_final; + console->display_title = display_title; +#ifdef CONSOLE_INPUT + console->parse_init = console_parse_init; + console->parse_final = console_parse_final; + console->parse_timer = console_parse_timer; + console->pthread_main = cThread_main; + console->parse = console_parse; + console->key_pressed = console_parse_key_pressed; +#endif +} \ No newline at end of file -- cgit v1.2.3-60-g2f50