console.c
changeset 1726 0f014227480a
parent 1725 e391da994698
child 1739 4c8fb3905cbd
equal deleted inserted replaced
1725:e391da994698 1726:0f014227480a
    14 #include "network.h"
    14 #include "network.h"
    15 #include "network_data.h"
    15 #include "network_data.h"
    16 #include "network_server.h"
    16 #include "network_server.h"
    17 
    17 
    18 #define ICON_BUFFER 79
    18 #define ICON_BUFFER 79
    19 #define ICON_HISTORY_SIZE 20
    19 #define ICON_CMDBUF_SIZE 20
    20 #define ICON_CMDLN_SIZE 255
    20 #define ICON_CMDLN_SIZE 255
    21 #define ICON_LINE_HEIGHT 12
    21 #define ICON_LINE_HEIGHT 12
    22 #define ICON_RIGHT_BORDERWIDTH 10
    22 #define ICON_RIGHT_BORDERWIDTH 10
    23 #define ICON_BOTTOM_BORDERWIDTH 12
    23 #define ICON_BOTTOM_BORDERWIDTH 12
    24 #define ICON_MAX_ALIAS_LINES 40
    24 #define ICON_MAX_ALIAS_LINES 40
    25 #define ICON_TOKEN_COUNT 20
       
    26 
    25 
    27 // ** main console ** //
    26 // ** main console ** //
    28 static Window *_iconsole_win; // Pointer to console window
    27 static Window *_iconsole_win; // Pointer to console window
    29 static bool _iconsole_inited;
    28 static bool _iconsole_inited;
    30 static char* _iconsole_buffer[ICON_BUFFER + 1];
    29 static char* _iconsole_buffer[ICON_BUFFER + 1];
    36 byte _stdlib_developer = 1;
    35 byte _stdlib_developer = 1;
    37 bool _stdlib_con_developer = false;
    36 bool _stdlib_con_developer = false;
    38 FILE* _iconsole_output_file;
    37 FILE* _iconsole_output_file;
    39 
    38 
    40 // ** main console cmd buffer
    39 // ** main console cmd buffer
    41 static char *_iconsole_history[ICON_HISTORY_SIZE];
    40 static char* _iconsole_cmdbuffer[ICON_CMDBUF_SIZE];
    42 static byte _iconsole_historypos;
    41 static byte _iconsole_cmdbufferpos;
    43 
    42 
    44 /* *************** */
    43 /* *************** */
    45 /*  end of header  */
    44 /*  end of header  */
    46 /* *************** */
    45 /* *************** */
    47 
    46 
    53 	_iconsole_cmdline.caretpos = 0;
    52 	_iconsole_cmdline.caretpos = 0;
    54 	_iconsole_cmdline.caretxoffs = 0;
    53 	_iconsole_cmdline.caretxoffs = 0;
    55 	SetWindowDirty(_iconsole_win);
    54 	SetWindowDirty(_iconsole_win);
    56 }
    55 }
    57 
    56 
    58 static inline void IConsoleResetHistoryPos(void) {_iconsole_historypos = ICON_HISTORY_SIZE - 1;}
       
    59 
       
    60 // ** console window ** //
    57 // ** console window ** //
    61 static void IConsoleWndProc(Window* w, WindowEvent* e)
    58 static void IConsoleWndProc(Window* w, WindowEvent* e)
    62 {
    59 {
    63 	switch (e->event) {
    60 	switch(e->event) {
    64 		case WE_PAINT: {
    61 		case WE_PAINT: {
    65 			int i = _iconsole_scroll;
    62 			int i = _iconsole_scroll;
    66 			int max = (w->height / ICON_LINE_HEIGHT) - 1;
    63 			int max = (w->height / ICON_LINE_HEIGHT) - 1;
    67 			int delta = 0;
    64 			int delta = 0;
    68 			GfxFillRect(w->left, w->top, w->width, w->height - 1, 0);
    65 			GfxFillRect(w->left, w->top, w->width, w->height - 1, 0);
    94 			break;
    91 			break;
    95 		case WE_KEYPRESS:
    92 		case WE_KEYPRESS:
    96 			e->keypress.cont = false;
    93 			e->keypress.cont = false;
    97 			switch (e->keypress.keycode) {
    94 			switch (e->keypress.keycode) {
    98 				case WKC_UP:
    95 				case WKC_UP:
    99 					IConsoleHistoryNavigate(+1);
    96 					IConsoleCmdBufferNavigate(+1);
   100 					SetWindowDirty(w);
    97 					SetWindowDirty(w);
   101 					break;
    98 					break;
   102 				case WKC_DOWN:
    99 				case WKC_DOWN:
   103 					IConsoleHistoryNavigate(-1);
   100 					IConsoleCmdBufferNavigate(-1);
   104 					SetWindowDirty(w);
   101 					SetWindowDirty(w);
   105 					break;
   102 					break;
   106 				case WKC_SHIFT | WKC_PAGEUP:
   103 				case WKC_SHIFT | WKC_PAGEUP:
   107 					if (_iconsole_scroll - (w->height / ICON_LINE_HEIGHT) - 1 < 0)
   104 					if (_iconsole_scroll - (w->height / ICON_LINE_HEIGHT) - 1 < 0)
   108 						_iconsole_scroll = 0;
   105 						_iconsole_scroll = 0;
   134 				case WKC_BACKQUOTE:
   131 				case WKC_BACKQUOTE:
   135 					IConsoleSwitch();
   132 					IConsoleSwitch();
   136 					break;
   133 					break;
   137 				case WKC_RETURN: case WKC_NUM_ENTER:
   134 				case WKC_RETURN: case WKC_NUM_ENTER:
   138 					IConsolePrintF(_iconsole_color_commands, "] %s", _iconsole_cmdline.buf);
   135 					IConsolePrintF(_iconsole_color_commands, "] %s", _iconsole_cmdline.buf);
   139 					IConsoleHistoryAdd(_iconsole_cmdline.buf);
   136 					_iconsole_cmdbufferpos = ICON_CMDBUF_SIZE - 1;
       
   137 					IConsoleCmdBufferAdd(_iconsole_cmdline.buf);
   140 
   138 
   141 					IConsoleCmdExec(_iconsole_cmdline.buf);
   139 					IConsoleCmdExec(_iconsole_cmdline.buf);
   142 					IConsoleClearCommand();
   140 					IConsoleClearCommand();
   143 					break;
   141 					break;
   144 				case WKC_CTRL | WKC_RETURN:
   142 				case WKC_CTRL | WKC_RETURN:
   145 					_iconsole_mode = (_iconsole_mode == ICONSOLE_FULL) ? ICONSOLE_OPENED : ICONSOLE_FULL;
   143 					_iconsole_mode = (_iconsole_mode == ICONSOLE_FULL) ? ICONSOLE_OPENED : ICONSOLE_FULL;
   146 					IConsoleResize();
   144 					IConsoleResize();
   147 					MarkWholeScreenDirty();
   145 					MarkWholeScreenDirty();
   148 					break;
   146 					break;
   149 				case (WKC_CTRL | 'V'):
   147 				case (WKC_CTRL | 'V'):
   150 					if (InsertTextBufferClipboard(&_iconsole_cmdline)) {
   148 					if (InsertTextBufferClipboard(&_iconsole_cmdline))
   151 						IConsoleResetHistoryPos();
       
   152 						SetWindowDirty(w);
   149 						SetWindowDirty(w);
   153 					}
       
   154 					break;
   150 					break;
   155 				case WKC_BACKSPACE: case WKC_DELETE:
   151 				case WKC_BACKSPACE: case WKC_DELETE:
   156 					if (DeleteTextBufferChar(&_iconsole_cmdline, e->keypress.keycode)) {
   152 					if (DeleteTextBufferChar(&_iconsole_cmdline, e->keypress.keycode))
   157 						IConsoleResetHistoryPos();
       
   158 						SetWindowDirty(w);
   153 						SetWindowDirty(w);
   159 					}
   154 					_iconsole_cmdbufferpos = ICON_CMDBUF_SIZE - 1;
   160 					break;
   155 					break;
   161 				case WKC_LEFT: case WKC_RIGHT: case WKC_END: case WKC_HOME:
   156 				case WKC_LEFT: case WKC_RIGHT: case WKC_END: case WKC_HOME:
   162 					if (MoveTextBufferPos(&_iconsole_cmdline, e->keypress.keycode)) {
   157 					if (MoveTextBufferPos(&_iconsole_cmdline, e->keypress.keycode))
   163 						IConsoleResetHistoryPos();
       
   164 						SetWindowDirty(w);
   158 						SetWindowDirty(w);
   165 					}
       
   166 					break;
   159 					break;
   167 				default:
   160 				default:
   168 					if (IsValidAsciiChar(e->keypress.ascii)) {
   161 					if (IsValidAsciiChar(e->keypress.ascii)) {
   169 						_iconsole_scroll = ICON_BUFFER;
   162 						_iconsole_scroll = ICON_BUFFER;
   170 						InsertTextBufferChar(&_iconsole_cmdline, e->keypress.ascii);
   163 						InsertTextBufferChar(&_iconsole_cmdline, e->keypress.ascii);
   171 						IConsoleResetHistoryPos();
   164 						_iconsole_cmdbufferpos = ICON_CMDBUF_SIZE - 1;
   172 						SetWindowDirty(w);
   165 						SetWindowDirty(w);
   173 					} else
   166 					} else
   174 						e->keypress.cont = true;
   167 						e->keypress.cont = true;
   175 			break;
   168 			break;
   176 		}
   169 		}
   198 	_iconsole_color_error = 3;
   191 	_iconsole_color_error = 3;
   199 	_iconsole_color_warning = 13;
   192 	_iconsole_color_warning = 13;
   200 	_iconsole_color_debug = 5;
   193 	_iconsole_color_debug = 5;
   201 	_iconsole_color_commands = 2;
   194 	_iconsole_color_commands = 2;
   202 	_iconsole_scroll = ICON_BUFFER;
   195 	_iconsole_scroll = ICON_BUFFER;
   203 	_iconsole_historypos = ICON_HISTORY_SIZE - 1;
   196 	_iconsole_cmdbufferpos = ICON_CMDBUF_SIZE - 1;
   204 	_iconsole_inited = true;
   197 	_iconsole_inited = true;
   205 	_iconsole_mode = ICONSOLE_CLOSED;
   198 	_iconsole_mode = ICONSOLE_CLOSED;
   206 	_iconsole_win = NULL;
   199 	_iconsole_win = NULL;
   207 
   200 
   208 #ifdef ENABLE_NETWORK /* Initialize network only variables */
   201 #ifdef ENABLE_NETWORK /* Initialize network only variables */
   209 	_redirect_console_to_client = 0;
   202 	_redirect_console_to_client = 0;
   210 #endif
   203 #endif
   211 
   204 
   212 	memset(_iconsole_history, 0, sizeof(_iconsole_history));
   205 	memset(_iconsole_cmdbuffer, 0, sizeof(_iconsole_cmdbuffer));
   213 	memset(_iconsole_buffer, 0, sizeof(_iconsole_buffer));
   206 	memset(_iconsole_buffer, 0, sizeof(_iconsole_buffer));
   214 	memset(_iconsole_cbuffer, 0, sizeof(_iconsole_cbuffer));
   207 	memset(_iconsole_cbuffer, 0, sizeof(_iconsole_cbuffer));
   215 	_iconsole_cmdline.buf = calloc(ICON_CMDLN_SIZE, sizeof(*_iconsole_cmdline.buf)); // create buffer and zero it
   208 	_iconsole_cmdline.buf = calloc(ICON_CMDLN_SIZE, sizeof(*_iconsole_cmdline.buf)); // create buffer and zero it
   216 	_iconsole_cmdline.maxlength = ICON_CMDLN_SIZE - 1;
   209 	_iconsole_cmdline.maxlength = ICON_CMDLN_SIZE - 1;
   217 
   210 
   218 	IConsoleStdLibRegister();
   211 	IConsoleStdLibRegister();
   219 	IConsolePrintF(13, "OpenTTD Game Console Revision 7 - %s", _openttd_revision);
   212 	IConsolePrintF(13, "OpenTTD Game Console Revision 6 - %s", _openttd_revision);
   220 	IConsolePrint(12,  "------------------------------------");
   213 	IConsolePrint(12, "---------------------------------");
   221 	IConsolePrint(12,  "use \"help\" for more info");
   214 	IConsolePrint(12, "use \"help\" for more info");
   222 	IConsolePrint(12,  "");
   215 	IConsolePrint(12, "");
   223 	IConsoleClearCommand();
   216 	IConsoleClearCommand();
   224 	IConsoleHistoryAdd("");
   217 	IConsoleCmdBufferAdd("");
   225 }
   218 }
   226 
   219 
   227 void IConsoleClear(void)
   220 void IConsoleClear(void)
   228 {
   221 {
   229 	uint i;
   222 	uint i;
   261 	CloseConsoleLogIfActive();
   254 	CloseConsoleLogIfActive();
   262 }
   255 }
   263 
   256 
   264 void IConsoleResize(void)
   257 void IConsoleResize(void)
   265 {
   258 {
       
   259 
   266 	_iconsole_win = FindWindowById(WC_CONSOLE, 0);
   260 	_iconsole_win = FindWindowById(WC_CONSOLE, 0);
   267 
   261 
   268 	switch (_iconsole_mode) {
   262 	switch (_iconsole_mode) {
   269 		case ICONSOLE_OPENED:
   263 		case ICONSOLE_OPENED:
   270 			_iconsole_win->height = _screen.height / 3;
   264 			_iconsole_win->height = _screen.height / 3;
   273 		case ICONSOLE_FULL:
   267 		case ICONSOLE_FULL:
   274 			_iconsole_win->height = _screen.height - ICON_BOTTOM_BORDERWIDTH;
   268 			_iconsole_win->height = _screen.height - ICON_BOTTOM_BORDERWIDTH;
   275 			_iconsole_win->width = _screen.width;
   269 			_iconsole_win->width = _screen.width;
   276 			break;
   270 			break;
   277 		default:
   271 		default:
   278 			NOT_REACHED();
   272 			break;
   279 	}
   273 	}
   280 
   274 
   281 	MarkWholeScreenDirty();
   275 	MarkWholeScreenDirty();
   282 }
   276 }
   283 
   277 
   287 		case ICONSOLE_CLOSED:
   281 		case ICONSOLE_CLOSED:
   288 			_iconsole_win = AllocateWindowDesc(&_iconsole_window_desc);
   282 			_iconsole_win = AllocateWindowDesc(&_iconsole_window_desc);
   289 			_iconsole_win->height = _screen.height / 3;
   283 			_iconsole_win->height = _screen.height / 3;
   290 			_iconsole_win->width = _screen.width;
   284 			_iconsole_win->width = _screen.width;
   291 			_iconsole_mode = ICONSOLE_OPENED;
   285 			_iconsole_mode = ICONSOLE_OPENED;
   292 			SETBIT(_no_scroll, SCROLL_CON); // override cursor arrows; the gamefield will not scroll
   286 			SETBIT(_no_scroll, SCROLL_CON);
   293 			break;
   287 			break;
   294 		case ICONSOLE_OPENED: case ICONSOLE_FULL:
   288 		case ICONSOLE_OPENED: case ICONSOLE_FULL:
   295 			DeleteWindowById(WC_CONSOLE, 0);
   289 			DeleteWindowById(WC_CONSOLE, 0);
   296 			_iconsole_win = NULL;
   290 			_iconsole_win = NULL;
   297 			_iconsole_mode = ICONSOLE_CLOSED;
   291 			_iconsole_mode = ICONSOLE_CLOSED;
   310 void IConsoleOpen(void)
   304 void IConsoleOpen(void)
   311 {
   305 {
   312 	if (_iconsole_mode == ICONSOLE_CLOSED) IConsoleSwitch();
   306 	if (_iconsole_mode == ICONSOLE_CLOSED) IConsoleSwitch();
   313 }
   307 }
   314 
   308 
   315 /**
   309 void IConsoleCmdBufferAdd(const char* cmd)
   316  * Add the entered line into the history so you can look it back
   310 {
   317  * scroll, etc. Put it to the beginning as it is the latest text
   311 	int i;
   318  * @param cmd Text to be entered into the 'history'
   312 	if (_iconsole_cmdbufferpos != (ICON_CMDBUF_SIZE - 1)) return;
   319  */
   313 	free(_iconsole_cmdbuffer[ICON_CMDBUF_SIZE - 2]);
   320 void IConsoleHistoryAdd(const char *cmd)
   314 	for (i = (ICON_CMDBUF_SIZE - 2); i > 0; i--) _iconsole_cmdbuffer[i] = _iconsole_cmdbuffer[i - 1];
   321 {
   315 	_iconsole_cmdbuffer[0] = strdup(cmd);
   322 	free(_iconsole_history[ICON_HISTORY_SIZE - 1]);
   316 }
   323 
   317 
   324 	memmove(&_iconsole_history[1], &_iconsole_history[0], sizeof(_iconsole_history[0]) * (ICON_HISTORY_SIZE - 1));
   318 void IConsoleCmdBufferNavigate(signed char direction)
   325 	_iconsole_history[0] = strdup(cmd);
   319 {
   326 	IConsoleResetHistoryPos();
   320 	int i;
   327 }
   321 	i = _iconsole_cmdbufferpos + direction;
   328 
   322 	if (i < 0) i = ICON_CMDBUF_SIZE - 1;
   329 /**
   323 	if (i >= ICON_CMDBUF_SIZE) i = 0;
   330  * Navigate Up/Down in the history of typed commands
       
   331  * @param direction Go further back in history (+1), go to recently typed commands (-1)
       
   332  */
       
   333 void IConsoleHistoryNavigate(signed char direction)
       
   334 {
       
   335 	int i = _iconsole_historypos + direction;
       
   336 
       
   337 	// watch out for overflows, just wrap around
       
   338 	if (i < 0) i = ICON_HISTORY_SIZE - 1;
       
   339 	if (i >= ICON_HISTORY_SIZE) i = 0;
       
   340 
       
   341 	if (direction > 0)
   324 	if (direction > 0)
   342 		if (_iconsole_history[i] == NULL) i = 0;
   325 		while (_iconsole_cmdbuffer[i] == NULL) {
   343 
   326 			i++;
   344 	if (direction < 0) {
   327 			if (i >= ICON_CMDBUF_SIZE) i = 0;
   345 		while (i > 0 && _iconsole_history[i] == NULL) i--;
   328 		}
   346 	}
   329 	if (direction < 0)
   347 
   330 		while (_iconsole_cmdbuffer[i] == NULL) {
   348 	_iconsole_historypos = i;
   331 			--i;
       
   332 			if (i < 0) i = ICON_CMDBUF_SIZE - 1;
       
   333 		}
       
   334 	_iconsole_cmdbufferpos = i;
   349 	IConsoleClearCommand();
   335 	IConsoleClearCommand();
   350 	// copy history to 'command prompt / bash'
   336 	ttd_strlcpy(_iconsole_cmdline.buf, _iconsole_cmdbuffer[i], _iconsole_cmdline.maxlength);
   351 	assert(_iconsole_history[i] != NULL && IS_INT_INSIDE(i, 0, ICON_HISTORY_SIZE));
       
   352 	ttd_strlcpy(_iconsole_cmdline.buf, _iconsole_history[i], _iconsole_cmdline.maxlength);
       
   353 	UpdateTextBufferSize(&_iconsole_cmdline);
   337 	UpdateTextBufferSize(&_iconsole_cmdline);
   354 }
   338 }
   355 
   339 
   356 /**
   340 /**
   357  * Handle the printing of text entered into the console or redirected there
   341  * Handle the printing of text entered into the console or redirected there
   398 	IConsoleWriteToLogFile(string);
   382 	IConsoleWriteToLogFile(string);
   399 
   383 
   400 	if (_iconsole_win != NULL) SetWindowDirty(_iconsole_win);
   384 	if (_iconsole_win != NULL) SetWindowDirty(_iconsole_win);
   401 }
   385 }
   402 
   386 
   403 /**
   387 
   404  * Handle the printing of text entered into the console or redirected there
       
   405  * by any other means. Uses printf() style format, for more information look
       
   406  * at @IConsolePrint()
       
   407  */
       
   408 void CDECL IConsolePrintF(uint16 color_code, const char* s, ...)
   388 void CDECL IConsolePrintF(uint16 color_code, const char* s, ...)
   409 {
   389 {
   410 	va_list va;
   390 	va_list va;
   411 	char buf[ICON_MAX_STREAMSIZE];
   391 	char buf[1024];
       
   392 	int len;
   412 
   393 
   413 	va_start(va, s);
   394 	va_start(va, s);
   414 	vsnprintf(buf, sizeof(buf), s, va);
   395 	len = vsnprintf(buf, sizeof(buf), s, va);
   415 	va_end(va);
   396 	va_end(va);
   416 
   397 
   417 	IConsolePrint(color_code, buf);
   398 	IConsolePrint(color_code, buf);
   418 }
   399 }
   419 
   400 
   420 /**
       
   421  * It is possible to print debugging information to the console,
       
   422  * which is achieved by using this function. Can only be used by
       
   423  * @debug() in debug.c. You need at least a level 2 (developer) for debugging
       
   424  * messages to show up
       
   425  */
       
   426 void IConsoleDebug(const char* string)
   401 void IConsoleDebug(const char* string)
   427 {
   402 {
   428 	if (_stdlib_developer > 1)
   403 	if (_stdlib_developer > 1)
   429 		IConsolePrintF(_iconsole_color_debug, "dbg: %s", string);
   404 		IConsolePrintF(_iconsole_color_debug, "dbg: %s", string);
   430 }
   405 }
   431 
   406 
   432 /**
   407 void IConsoleError(const char* string)
   433  * It is possible to print warnings to the console. These are mostly
   408 {
   434  * errors or mishaps, but non-fatal. You need at least a level 1 (developer) for
   409 	if (_stdlib_developer > 0)
   435  * debugging messages to show up
   410 		IConsolePrintF(_iconsole_color_error, "ERROR: %s", string);
   436  */
   411 }
       
   412 
   437 void IConsoleWarning(const char* string)
   413 void IConsoleWarning(const char* string)
   438 {
   414 {
   439 	if (_stdlib_developer > 0)
   415 	if (_stdlib_developer > 0)
   440 		IConsolePrintF(_iconsole_color_warning, "WARNING: %s", string);
   416 		IConsolePrintF(_iconsole_color_warning, "WARNING: %s", string);
   441 }
   417 }
   442 
   418 
   443 /**
   419 void IConsoleCmdRegister(const char* name, _iconsole_cmd_addr addr)
   444  * It is possible to print error information to the console. This can include
   420 {
   445  * game errors, or errors in general you would want the user to notice
   421 	char* _new;
   446  */
   422 	_iconsole_cmd* item;
   447 void IConsoleError(const char* string)
   423 	_iconsole_cmd* item_new;
   448 {
   424 	_iconsole_cmd* item_before;
   449 	IConsolePrintF(_iconsole_color_error, "ERROR: %s", string);
   425 
   450 }
   426 	_new = strdup(name);
   451 
   427 
   452 /**
   428 	item_new = malloc(sizeof(_iconsole_cmd));
   453  * Register a new command to be used in the console
       
   454  * @param name name of the command that will be used
       
   455  * @param addr function that will be called upon execution of command
       
   456  */
       
   457 void IConsoleCmdRegister(const char *name, IConsoleCmdAddr addr)
       
   458 {
       
   459 	IConsoleCmd *item, *item_before;
       
   460 	char *new_cmd = strdup(name);
       
   461 	IConsoleCmd *item_new = malloc(sizeof(IConsoleCmd));
       
   462 
   429 
   463 	item_new->_next = NULL;
   430 	item_new->_next = NULL;
   464 	item_new->addr = addr;
   431 	item_new->addr = addr;
   465 	item_new->name = new_cmd;
   432 	item_new->name = _new;
   466 
   433 
   467 	item_new->hook_access = NULL;
   434 	item_new->hook_access = NULL;
   468 	item_new->hook_after_exec = NULL;
   435 	item_new->hook_after_exec = NULL;
   469 	item_new->hook_before_exec = NULL;
   436 	item_new->hook_before_exec = NULL;
   470 
   437 
   471 	// first command
       
   472 	if (_iconsole_cmds == NULL) {
       
   473 		_iconsole_cmds = item_new;
       
   474 		return;
       
   475 	}
       
   476 
       
   477 	item_before = NULL;
   438 	item_before = NULL;
   478 	item = _iconsole_cmds;
   439 	item = _iconsole_cmds;
   479 
   440 
   480 	/* BEGIN - Alphabetically insert the commands into the linked list */
   441 	if (item == NULL) {
       
   442 		_iconsole_cmds = item_new;
       
   443 	} else {
       
   444 		while ((item->_next != NULL) && (strcmp(item->name,item_new->name)<=0)) {
       
   445 			item_before = item;
       
   446 			item = item->_next;
       
   447 			}
       
   448 // insertion sort
       
   449 		if (item_before==NULL) {
       
   450 			if (strcmp(item->name,item_new->name)<=0) {
       
   451 				// appending
       
   452 				item ->_next = item_new;
       
   453 			} else {
       
   454 				// inserting as startitem
       
   455 				_iconsole_cmds = item_new;
       
   456 				item_new ->_next = item;
       
   457 			}
       
   458 		} else {
       
   459 			if (strcmp(item->name,item_new->name)<=0) {
       
   460 				// appending
       
   461 				item ->_next = item_new;
       
   462 			} else {
       
   463 				// inserting
       
   464 				item_new ->_next = item_before->_next;
       
   465 				item_before ->_next = item_new;
       
   466 			}
       
   467 		}
       
   468 // insertion sort end
       
   469 	}
       
   470 
       
   471 }
       
   472 
       
   473 _iconsole_cmd* IConsoleCmdGet(const char* name)
       
   474 {
       
   475 	_iconsole_cmd* item;
       
   476 
       
   477 	item = _iconsole_cmds;
   481 	while (item != NULL) {
   478 	while (item != NULL) {
   482 		int i = strcmp(item->name, item_new->name);
   479 		if (strcmp(item->name, name) == 0) return item;
   483 		if (i == 0) {
       
   484 			IConsoleError("a command with this name already exists; insertion aborted");
       
   485 			free(item_new);
       
   486 			return;
       
   487 		}
       
   488 
       
   489 		if (i > 0) break; // insert at this position
       
   490 
       
   491 		item_before = item;
       
   492 		item = item->_next;
   480 		item = item->_next;
   493 	}
   481 	}
   494 
       
   495 	if (item_before == NULL) {
       
   496 		_iconsole_cmds = item_new;
       
   497 	} else
       
   498 		item_before->_next = item_new;
       
   499 
       
   500 	item_new->_next = item;
       
   501 	/* END - Alphabetical insert */
       
   502 }
       
   503 
       
   504 /**
       
   505  * Find the command pointed to by its string
       
   506  * @param name command to be found
       
   507  * @return return Cmdstruct of the found command, or NULL on failure
       
   508  */
       
   509 IConsoleCmd *IConsoleCmdGet(const char *name)
       
   510 {
       
   511 	IConsoleCmd *item;
       
   512 
       
   513 	for (item = _iconsole_cmds; item != NULL; item = item->_next) {
       
   514 		if (strcmp(item->name, name) == 0) return item;
       
   515 	}
       
   516 	return NULL;
   482 	return NULL;
   517 }
   483 }
   518 
   484 
   519 /**
   485 void IConsoleAliasRegister(const char* name, const char* cmdline)
   520  * Register a an alias for an already existing command in the console
   486 {
   521  * @param name name of the alias that will be used
   487 	char* _new;
   522  * @param cmd name of the command that 'name' will be alias of
   488 	char* _newcmd;
   523  */
   489 	_iconsole_alias* item;
   524 void IConsoleAliasRegister(const char *name, const char *cmd)
   490 	_iconsole_alias* item_new;
   525 {
   491 	_iconsole_alias* item_before;
   526 	IConsoleAlias *item, *item_before;
   492 
   527 	char *new_alias = strdup(name);
   493 	_new = strdup(name);
   528 	char *cmd_aliased = strdup(cmd);
   494 	_newcmd = strdup(cmdline);
   529 	IConsoleAlias *item_new = malloc(sizeof(IConsoleAlias));
   495 
       
   496 	item_new = malloc(sizeof(_iconsole_alias));
   530 
   497 
   531 	item_new->_next = NULL;
   498 	item_new->_next = NULL;
   532 	item_new->cmdline = cmd_aliased;
   499 	item_new->cmdline = _newcmd;
   533 	item_new->name = new_alias;
   500 	item_new->name = _new;
   534 
   501 
   535 	item_before = NULL;
   502 	item_before = NULL;
   536 	item = _iconsole_aliases;
   503 	item = _iconsole_aliases;
   537 
   504 
   538 	// first command
   505 	if (item == NULL) {
   539 	if (_iconsole_aliases == NULL) {
       
   540 		_iconsole_aliases = item_new;
   506 		_iconsole_aliases = item_new;
   541 		return;
   507 	} else {
   542 	}
   508 		while ((item->_next != NULL) && (strcmp(item->name,item_new->name)<=0)) {
   543 
   509 			item_before = item;
   544 	item_before = NULL;
   510 			item = item->_next;
       
   511 			}
       
   512 // insertion sort
       
   513 		if (item_before==NULL) {
       
   514 			if (strcmp(item->name,item_new->name)<=0) {
       
   515 				// appending
       
   516 				item ->_next = item_new;
       
   517 			} else {
       
   518 				// inserting as startitem
       
   519 				_iconsole_aliases = item_new;
       
   520 				item_new ->_next = item;
       
   521 			}
       
   522 		} else {
       
   523 			if (strcmp(item->name,item_new->name)<=0) {
       
   524 				// appending
       
   525 				item ->_next = item_new;
       
   526 			} else {
       
   527 				// inserting
       
   528 				item_new ->_next = item_before->_next;
       
   529 				item_before ->_next = item_new;
       
   530 			}
       
   531 		}
       
   532 // insertion sort end
       
   533 	}
       
   534 
       
   535 }
       
   536 
       
   537 _iconsole_alias* IConsoleAliasGet(const char* name)
       
   538 {
       
   539 	_iconsole_alias* item;
       
   540 
   545 	item = _iconsole_aliases;
   541 	item = _iconsole_aliases;
   546 
       
   547 	/* BEGIN - Alphabetically insert the commands into the linked list */
       
   548 	while (item != NULL) {
   542 	while (item != NULL) {
   549 		int i = strcmp(item->name, item_new->name);
   543 		if (strcmp(item->name, name) == 0) return item;
   550 		if (i == 0) {
       
   551 			IConsoleError("an alias with this name already exists; insertion aborted");
       
   552 			free(item_new);
       
   553 			return;
       
   554 		}
       
   555 
       
   556 		if (i > 0) break; // insert at this position
       
   557 
       
   558 		item_before = item;
       
   559 		item = item->_next;
   544 		item = item->_next;
   560 	}
   545 	}
   561 
       
   562 	if (item_before == NULL) {
       
   563 		_iconsole_aliases = item_new;
       
   564 	} else
       
   565 		item_before->_next = item_new;
       
   566 
       
   567 	item_new->_next = item;
       
   568 	/* END - Alphabetical insert */
       
   569 }
       
   570 
       
   571 /**
       
   572  * Find the alias pointed to by its string
       
   573  * @param name alias to be found
       
   574  * @return return Aliasstruct of the found alias, or NULL on failure
       
   575  */
       
   576 IConsoleAlias *IConsoleAliasGet(const char *name)
       
   577 {
       
   578 	IConsoleAlias* item;
       
   579 
       
   580 	for (item = _iconsole_aliases; item != NULL; item = item->_next) {
       
   581 		if (strcmp(item->name, name) == 0) return item;
       
   582 	}
       
   583 
       
   584 	return NULL;
   546 	return NULL;
   585 }
   547 }
   586 
   548 
   587 static inline int IConsoleCopyInParams(char *dst, const char *src, uint bufpos)
   549 static void IConsoleAliasExec(const char* cmdline, char* tokens[20], byte tokentypes[20])
   588 {
   550 {
   589 	int len = min(ICON_MAX_STREAMSIZE - bufpos, strlen(src));
   551 	char* lines[ICON_MAX_ALIAS_LINES];
   590 	strncpy(dst, src, len);
   552 	char* linestream;
   591 
   553 	char* linestream_s;
   592 	return len;
       
   593 }
       
   594 
       
   595 /**
       
   596  * An alias is just another name for a command, or for more commands
       
   597  * Execute it as well.
       
   598  * @param cmdstr is the alias of the command
       
   599  * @param tokens are the parameters given to the original command (0 is the first param)
       
   600  * @param tokencount the number of parameters passed
       
   601  */
       
   602 static void IConsoleAliasExec(const char *cmdstr, char *tokens[ICON_TOKEN_COUNT], int tokencount)
       
   603 {
       
   604 	const char *cmdptr;
       
   605 	char *aliases[ICON_MAX_ALIAS_LINES], aliasstream[ICON_MAX_STREAMSIZE];
       
   606 	int i;
       
   607 	uint a_index, astream_i;
       
   608 
       
   609 	memset(&aliases, 0, sizeof(aliases));
       
   610 	memset(&aliasstream, 0, sizeof(aliasstream));
       
   611 
       
   612 	aliases[0] = aliasstream;
       
   613 	for (cmdptr = cmdstr, a_index = 0, astream_i = 0; *cmdptr != '\0'; *cmdptr++) {
       
   614 		if (a_index >= lengthof(aliases) || astream_i >= lengthof(aliasstream)) break;
       
   615 
       
   616 		switch (*cmdptr) {
       
   617 		case '\'': /* ' will double for : */
       
   618 			aliasstream[astream_i++] = '"';
       
   619 			break;
       
   620 		case ';': /* Cmd seperator, start new line */
       
   621 			aliasstream[astream_i] = '\0';
       
   622 			aliases[++a_index] = &aliasstream[++astream_i];
       
   623 			*cmdptr++;
       
   624 			break;
       
   625 		case '%': /* One specific parameter: %A = [param 1] %B = [param 2] ... */
       
   626 			*cmdptr++;
       
   627 			switch (*cmdptr) {
       
   628 			case '+': { /* All parameters seperated: "[param 1]" "[param 2]" */
       
   629 				for (i = 0; i != tokencount; i++) {
       
   630 					aliasstream[astream_i++] = '"';
       
   631 					astream_i += IConsoleCopyInParams(&aliasstream[astream_i], tokens[i], astream_i);
       
   632 					aliasstream[astream_i++] = '"';
       
   633 					aliasstream[astream_i++] = ' ';
       
   634 				}
       
   635 			} break;
       
   636 			case '!': { /* Merge the parameters to one: "[param 1] [param 2] [param 3...]" */
       
   637 				aliasstream[astream_i++] = '"';
       
   638 				for (i = 0; i != tokencount; i++) {
       
   639 					astream_i += IConsoleCopyInParams(&aliasstream[astream_i], tokens[i], astream_i);
       
   640 					aliasstream[astream_i++] = ' ';
       
   641 				}
       
   642 				aliasstream[astream_i++] = '"';
       
   643 
       
   644 			} break;
       
   645 				default: {
       
   646 				int param = *cmdptr - 'A';
       
   647 
       
   648 				if (param < 0 || param >= tokencount) {
       
   649 					IConsoleError("too many or wrong amount of parameters passed to alias, aborting");
       
   650 					return;
       
   651 				}
       
   652 
       
   653 				aliasstream[astream_i++] = '"';
       
   654 				astream_i += IConsoleCopyInParams(&aliasstream[astream_i], tokens[param], astream_i);
       
   655 				aliasstream[astream_i++] = '"';
       
   656 			} break;
       
   657 			} break;
       
   658 
       
   659 		default:
       
   660 			aliasstream[astream_i++] = *cmdptr;
       
   661 			break;
       
   662 		}
       
   663 	}
       
   664 
       
   665 	for (i = 0; i <= (int)a_index; i++) IConsoleCmdExec(aliases[i]);
       
   666 }
       
   667 
       
   668 #if 0
       
   669 static void IConsoleAliasExec(const char* cmdline, char* tokens[TOKEN_COUNT], byte tokentypes[TOKEN_COUNT])
       
   670 {
       
   671 	char *lines[ICON_MAX_ALIAS_LINES];
       
   672 	char *linestream, *linestream_s;
       
   673 
   554 
   674 	int c;
   555 	int c;
   675 	int i;
   556 	int i;
   676 	int l;
   557 	int l;
   677 	int x;
   558 	int x;
   678 	byte t;
   559 	byte t;
   679 
   560 
   680 	memset(lines, 0, ICON_MAX_ALIAS_LINES); // clear buffer
   561 	//** clearing buffer **//
   681 
   562 
   682 	linestream_s = linestream = malloc(1024 * ICON_MAX_ALIAS_LINES);
   563 	for (i = 0; i < 40; i++) {
   683 	memset(linestream, 0, 1024 * ICON_MAX_ALIAS_LINES);
   564 		lines[0] = NULL;
       
   565 	}
       
   566 	linestream_s = linestream = malloc(1024*ICON_MAX_ALIAS_LINES);
       
   567 	memset(linestream, 0, 1024*ICON_MAX_ALIAS_LINES);
   684 
   568 
   685 	//** parsing **//
   569 	//** parsing **//
   686 
   570 
   687 	l = strlen(cmdline);
   571 	l = strlen(cmdline);
   688 	i = 0;
   572 	i = 0;
   783 		c++;
   667 		c++;
   784 		linestream++;
   668 		linestream++;
   785 		*linestream = '\0';
   669 		*linestream = '\0';
   786 	}
   670 	}
   787 
   671 
   788 	for (i = 0; i < c; i++)	IConsoleCmdExec(lines[i]);
   672 	for (i=0; i<c; i++)	{
       
   673 		IConsoleCmdExec(lines[i]);
       
   674 	}
   789 
   675 
   790 	free(linestream_s);
   676 	free(linestream_s);
   791 }
   677 }
   792 #endif
       
   793 
       
   794 static void IConsoleVarExec(char *token[ICON_TOKEN_COUNT]) {}
       
   795 
   678 
   796 void IConsoleVarInsert(_iconsole_var* item_new, const char* name)
   679 void IConsoleVarInsert(_iconsole_var* item_new, const char* name)
   797 {
   680 {
   798 	_iconsole_var* item;
   681 	_iconsole_var* item;
   799 	_iconsole_var* item_before;
   682 	_iconsole_var* item_before;
   892 }
   775 }
   893 
   776 
   894 _iconsole_var* IConsoleVarGet(const char* name)
   777 _iconsole_var* IConsoleVarGet(const char* name)
   895 {
   778 {
   896 	_iconsole_var* item;
   779 	_iconsole_var* item;
   897 	for (item = _iconsole_vars; item != NULL; item = item->_next) {
   780 	for (item = _iconsole_vars; item != NULL; item = item->_next)
   898 		if (strcmp(item->name, name) == 0) return item;
   781 		if (strcmp(item->name, name) == 0) return item;
   899 	}
       
   900 
       
   901 	return NULL;
   782 	return NULL;
   902 }
   783 }
   903 
   784 
   904 _iconsole_var* IConsoleVarAlloc(_iconsole_var_types type)
   785 _iconsole_var* IConsoleVarAlloc(_iconsole_var_types type)
   905 {
   786 {
  1102 	return proc == NULL ? true : proc(hook_var);
   983 	return proc == NULL ? true : proc(hook_var);
  1103 }
   984 }
  1104 
   985 
  1105 void IConsoleCmdHook(const char* name, _iconsole_hook_types type, iconsole_cmd_hook proc)
   986 void IConsoleCmdHook(const char* name, _iconsole_hook_types type, iconsole_cmd_hook proc)
  1106 {
   987 {
  1107 	IConsoleCmd* hook_cmd = IConsoleCmdGet(name);
   988 	_iconsole_cmd* hook_cmd = IConsoleCmdGet(name);
  1108 	if (hook_cmd == NULL) return;
   989 	if (hook_cmd == NULL) return;
  1109 	switch (type) {
   990 	switch (type) {
  1110 		case ICONSOLE_HOOK_AFTER_EXEC:
   991 		case ICONSOLE_HOOK_AFTER_EXEC:
  1111 			hook_cmd->hook_after_exec = proc;
   992 			hook_cmd->hook_after_exec = proc;
  1112 			break;
   993 			break;
  1121 			assert(0);
  1002 			assert(0);
  1122 			break;
  1003 			break;
  1123 	}
  1004 	}
  1124 }
  1005 }
  1125 
  1006 
  1126 bool IConsoleCmdHookHandle(IConsoleCmd* hook_cmd, _iconsole_hook_types type)
  1007 bool IConsoleCmdHookHandle(_iconsole_cmd* hook_cmd, _iconsole_hook_types type)
  1127 {
  1008 {
  1128 	iconsole_cmd_hook proc = NULL;
  1009 	iconsole_cmd_hook proc = NULL;
  1129 	switch (type) {
  1010 	switch (type) {
  1130 		case ICONSOLE_HOOK_AFTER_EXEC:
  1011 		case ICONSOLE_HOOK_AFTER_EXEC:
  1131 			proc = hook_cmd->hook_after_exec;
  1012 			proc = hook_cmd->hook_after_exec;
  1142 			break;
  1023 			break;
  1143 	}
  1024 	}
  1144 	return proc == NULL ? true : proc(hook_cmd);
  1025 	return proc == NULL ? true : proc(hook_cmd);
  1145 }
  1026 }
  1146 
  1027 
  1147 /**
       
  1148  * Execute a given command passed to us. First chop it up into
       
  1149  * individual tokens, then execute it if possible
       
  1150  * @param cmdstr string to be parsed and executed
       
  1151  */
       
  1152 void IConsoleCmdExec(const char *cmdstr)
       
  1153 {
       
  1154 	IConsoleCmd   *cmd    = NULL;
       
  1155 	IConsoleAlias *alias  = NULL;
       
  1156 	_iconsole_var *var    = NULL;
       
  1157 
       
  1158 	const char *cmdptr;
       
  1159 	char *tokens[ICON_TOKEN_COUNT], tokenstream[ICON_MAX_STREAMSIZE];
       
  1160 	uint t_index, tstream_i;
       
  1161 
       
  1162 	bool longtoken = false;
       
  1163 
       
  1164 	for (cmdptr = cmdstr; *cmdptr != '\0'; *cmdptr++) {
       
  1165 		if (!IsValidAsciiChar(*cmdptr)) {
       
  1166 			IConsoleError("command contains malformed characters, aborting");
       
  1167 			return;
       
  1168 		}
       
  1169 	}
       
  1170 
       
  1171 	if (_stdlib_con_developer)
       
  1172 		IConsolePrintF(_iconsole_color_debug, "condbg: executing cmdline: %s", cmdstr);
       
  1173 
       
  1174 	memset(&tokens, 0, sizeof(tokens));
       
  1175 	memset(&tokenstream, 0, sizeof(tokenstream));
       
  1176 
       
  1177 	/* 1. Split up commandline into tokens, seperated by spaces, commands
       
  1178 	 * enclosed in "" are taken as one token. We can only go as far as the amount
       
  1179 	 * of characters in our stream or the max amount of tokens we can handle */
       
  1180 	tokens[0] = tokenstream;
       
  1181 	for (cmdptr = cmdstr, t_index = 0, tstream_i = 0; *cmdptr != '\0'; *cmdptr++) {
       
  1182 		if (t_index >= lengthof(tokens) || tstream_i >= lengthof(tokenstream)) break;
       
  1183 
       
  1184 		switch (*cmdptr) {
       
  1185 		case ' ': /* Token seperator */
       
  1186 			if (!longtoken) {
       
  1187 				tokenstream[tstream_i] = '\0';
       
  1188 				tokens[++t_index] = &tokenstream[tstream_i + 1];
       
  1189 			} else
       
  1190 				tokenstream[tstream_i] = *cmdptr;
       
  1191 
       
  1192 			tstream_i++;
       
  1193 			break;
       
  1194 		case '"': /* Tokens enclosed in "" are one token */
       
  1195 			longtoken = !longtoken;
       
  1196 			break;
       
  1197 		default: /* Normal character */
       
  1198 			tokenstream[tstream_i++] = *cmdptr;
       
  1199 			break;
       
  1200 		}
       
  1201 	}
       
  1202 
       
  1203 	t_index++; // index was 0
       
  1204 
       
  1205 	/* 2. Determine type of command (cmd, alias or variable) and execute
       
  1206 	 * First try commands, then aliases, and finally variables
       
  1207 	 */
       
  1208 	 cmd = IConsoleCmdGet(tokens[0]);
       
  1209 	 if (cmd != NULL) {
       
  1210 		if (IConsoleCmdHookHandle(cmd, ICONSOLE_HOOK_ACCESS)) {
       
  1211 			IConsoleCmdHookHandle(cmd, ICONSOLE_HOOK_BEFORE_EXEC);
       
  1212 			cmd->addr(t_index, tokens, NULL);
       
  1213 			IConsoleCmdHookHandle(cmd, ICONSOLE_HOOK_AFTER_EXEC);
       
  1214 		}
       
  1215 	 	return;
       
  1216 	 }
       
  1217 
       
  1218 	 alias = IConsoleAliasGet(tokens[0]);
       
  1219 	 if (alias != NULL) {
       
  1220 	 	IConsoleAliasExec(alias->cmdline, &tokens[1], t_index - 1);
       
  1221 	 	return;
       
  1222 	 }
       
  1223 
       
  1224 	 var = IConsoleVarGet(tokens[0]);
       
  1225 	 if (var != NULL) {
       
  1226 	 	IConsoleVarExec(tokens);
       
  1227 	 	return;
       
  1228 	 }
       
  1229 
       
  1230 	 IConsoleError("command or variable not found");
       
  1231 }
       
  1232 
       
  1233 #if 0
       
  1234 void IConsoleCmdExec(const char* cmdstr)
  1028 void IConsoleCmdExec(const char* cmdstr)
  1235 {
  1029 {
  1236 	IConsoleCmdAddr function;
  1030 	_iconsole_cmd_addr function;
  1237 	char* tokens[20];
  1031 	char* tokens[20];
  1238 	byte  tokentypes[20];
  1032 	byte  tokentypes[20];
  1239 	char* tokenstream;
  1033 	char* tokenstream;
  1240 	char* tokenstream_s;
  1034 	char* tokenstream_s;
  1241 	byte  execution_mode;
  1035 	byte  execution_mode;
  1242 	_iconsole_var* var     = NULL;
  1036 	_iconsole_var* var     = NULL;
  1243 	_iconsole_var* result  = NULL;
  1037 	_iconsole_var* result  = NULL;
  1244 	IConsoleCmd* cmd     = NULL;
  1038 	_iconsole_cmd* cmd     = NULL;
  1245 	IConsoleAlias* alias = NULL;
  1039 	_iconsole_alias* alias = NULL;
  1246 
  1040 
  1247 	bool longtoken;
  1041 	bool longtoken;
  1248 	bool valid_token;
  1042 	bool valid_token;
  1249 	bool skip_lt_change;
  1043 	bool skip_lt_change;
  1250 
  1044 
  1251 	uint c;
  1045 	uint c;
  1252 	uint i;
  1046 	uint i;
  1253 	uint l;
  1047 	uint l;
  1254 
  1048 
  1255 	for (; strchr("\n\r \t", *cmdstr) != NULL; cmdstr++) {
  1049 	for (; strchr("\n\r \t", *cmdstr) != NULL; ++cmdstr) {
  1256 		switch (*cmdstr) {
  1050 		switch (*cmdstr) {
  1257 			case '\0': case '#': return;
  1051 			case '\0':
  1258 			default: break;
  1052 			case '#':
       
  1053 				return;
       
  1054 
       
  1055 			default:
       
  1056 				break;
  1259 		}
  1057 		}
  1260 	}
  1058 	}
  1261 
  1059 
  1262 	if (_stdlib_con_developer)
  1060 	if (_stdlib_con_developer)
  1263 		IConsolePrintF(_iconsole_color_debug, "CONDEBUG: execution_cmdline: %s", cmdstr);
  1061 		IConsolePrintF(_iconsole_color_debug, "CONDEBUG: execution_cmdline: %s", cmdstr);
  1684 	}
  1482 	}
  1685 
  1483 
  1686 	//** freeing the tokenstream **//
  1484 	//** freeing the tokenstream **//
  1687 	free(tokenstream_s);
  1485 	free(tokenstream_s);
  1688 }
  1486 }
  1689 #endif