Skip to content
Permalink
Browse files

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 <ind@henn.et>
  • Loading branch information...
shennetsind committed Mar 17, 2013
1 parent 5b1fee9 commit 3b89a135dcde9779bd0537cd136a7c34cfadbe3f
@@ -36,13 +36,15 @@ set( COMMON_ALL_HEADERS
set( COMMON_MINI_HEADERS
${COMMON_ALL_HEADERS}
"${COMMON_SOURCE_DIR}/core.h"
"${COMMON_SOURCE_DIR}/console.h"
"${COMMON_SOURCE_DIR}/malloc.h"
"${COMMON_SOURCE_DIR}/showmsg.h"
"${COMMON_SOURCE_DIR}/strlib.h"
${LIBCONFIG_HEADERS} # needed by showmsg.h
CACHE INTERNAL "" )
set( COMMON_MINI_SOURCES
"${COMMON_SOURCE_DIR}/core.c"
"${COMMON_SOURCE_DIR}/console.c"
"${COMMON_SOURCE_DIR}/malloc.c"
"${COMMON_SOURCE_DIR}/showmsg.c"
"${COMMON_SOURCE_DIR}/strlib.c"
@@ -61,6 +63,7 @@ set( COMMON_BASE_HEADERS
${COMMON_ALL_HEADERS}
"${COMMON_SOURCE_DIR}/conf.h"
"${COMMON_SOURCE_DIR}/core.h"
"${COMMON_SOURCE_DIR}/console.h"
"${COMMON_SOURCE_DIR}/db.h"
"${COMMON_SOURCE_DIR}/des.h"
"${COMMON_SOURCE_DIR}/ers.h"
@@ -86,6 +89,7 @@ set( COMMON_BASE_HEADERS
set( COMMON_BASE_SOURCES
"${COMMON_SOURCE_DIR}/conf.c"
"${COMMON_SOURCE_DIR}/core.c"
"${COMMON_SOURCE_DIR}/console.c"
"${COMMON_SOURCE_DIR}/db.c"
"${COMMON_SOURCE_DIR}/des.c"
"${COMMON_SOURCE_DIR}/ers.c"
@@ -3,7 +3,8 @@ COMMON_OBJ = obj_all/core.o obj_all/socket.o obj_all/timer.o obj_all/db.o \
obj_all/nullpo.o obj_all/malloc.o obj_all/showmsg.o obj_all/strlib.o obj_all/utils.o \
obj_all/grfio.o obj_all/mapindex.o obj_all/ers.o obj_all/md5calc.o \
obj_all/minicore.o obj_all/minisocket.o obj_all/minimalloc.o obj_all/random.o obj_all/des.o \
obj_all/conf.o obj_all/thread.o obj_all/mutex.o obj_all/raconf.o obj_all/mempool.o
obj_all/conf.o obj_all/thread.o obj_all/mutex.o obj_all/raconf.o obj_all/mempool.o obj_all/console.o \
obj_all/miniconsole.o

COMMON_H = $(shell ls ../common/*.h)

@@ -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 <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <unistd.h>
#else
#include "../common/winapi.h" // Console close event handling
#endif

#ifdef CONSOLE_INPUT
#ifdef _WIN32
#include <conio.h> /* _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
}
@@ -0,0 +1,48 @@
// Copyright (c) Hercules Dev Team, licensed under GNU GPL.
// See the LICENSE file

#ifndef _CONSOLE_H_
#define _CONSOLE_H_

#include "../common/atomic.h"
#include "../common/thread.h"
#include "../common/mutex.h"
#include "../common/spinlock.h"
#include "../config/core.h"

/**
* Queue Max
* why is there a limit, why not make it dynamic? - I'm playing it safe, I'd rather not play with memory management between threads
**/
#define CONSOLE_PARSE_SIZE 10
struct {
char queue[CONSOLE_PARSE_SIZE][MAX_CONSOLE_INPUT];
unsigned short count;
} cinput;

struct console_interface {
void (*init) (void);
void (*final) (void);
void (*display_title) (void);
#ifdef CONSOLE_INPUT
/* vars */
SPIN_LOCK ptlock;/* parse thread lock */
rAthread pthread;/* parse thread */
volatile int32 ptstate;/* parse thread state */
ramutex ptmutex;/* parse thread mutex */
racond ptcond;/* parse thread cond */
/* */
void (*parse_init) (void);
void (*parse_final) (void);
int (*parse_timer) (int tid, unsigned int tick, int id, intptr_t data);
void *(*pthread_main) (void *x);
void (*parse) (char* line);
int (*key_pressed) (void);
#endif
} console_s;

struct console_interface *console;

void console_defaults(void);

#endif /* _CONSOLE_H_ */

0 comments on commit 3b89a13

Please sign in to comment.
You can’t perform that action at this time.