00001
00002
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "gui.h"
00008 #include "textbuf_gui.h"
00009 #include "window_gui.h"
00010 #include "variables.h"
00011 #include <stdarg.h>
00012 #include <string.h>
00013 #include "console.h"
00014 #include "network/network.h"
00015 #include "network/network_data.h"
00016 #include "network/network_server.h"
00017 #include "core/alloc_func.hpp"
00018 #include "window_func.h"
00019 #include "string_func.h"
00020 #include "gfx_func.h"
00021
00022 #include "table/strings.h"
00023
00024 #define ICON_BUFFER 79
00025 #define ICON_HISTORY_SIZE 20
00026 #define ICON_LINE_HEIGHT 12
00027 #define ICON_RIGHT_BORDERWIDTH 10
00028 #define ICON_BOTTOM_BORDERWIDTH 12
00029 #define ICON_MAX_ALIAS_LINES 40
00030 #define ICON_TOKEN_COUNT 20
00031
00032
00033 IConsoleCmd *_iconsole_cmds;
00034 IConsoleVar *_iconsole_vars;
00035 IConsoleAlias *_iconsole_aliases;
00036
00037
00038 byte _icolour_def;
00039 byte _icolour_err;
00040 byte _icolour_warn;
00041 byte _icolour_dbg;
00042 byte _icolour_cmd;
00043 IConsoleModes _iconsole_mode;
00044
00045
00046 static char *_iconsole_buffer[ICON_BUFFER + 1];
00047 static uint16 _iconsole_cbuffer[ICON_BUFFER + 1];
00048 static Textbuf _iconsole_cmdline;
00049
00050
00051 byte _stdlib_developer = 1;
00052 bool _stdlib_con_developer = false;
00053 FILE *_iconsole_output_file;
00054
00055
00056 static char *_iconsole_history[ICON_HISTORY_SIZE];
00057 static byte _iconsole_historypos;
00058
00059
00060
00061
00062
00063 static void IConsoleClearCommand()
00064 {
00065 memset(_iconsole_cmdline.buf, 0, ICON_CMDLN_SIZE);
00066 _iconsole_cmdline.length = 0;
00067 _iconsole_cmdline.width = 0;
00068 _iconsole_cmdline.caretpos = 0;
00069 _iconsole_cmdline.caretxoffs = 0;
00070 SetWindowDirty(FindWindowById(WC_CONSOLE, 0));
00071 }
00072
00073 static inline void IConsoleResetHistoryPos() {_iconsole_historypos = ICON_HISTORY_SIZE - 1;}
00074
00075
00076 static void IConsoleHistoryAdd(const char *cmd);
00077 static void IConsoleHistoryNavigate(int direction);
00078
00079
00080 static void IConsoleWndProc(Window *w, WindowEvent *e)
00081 {
00082 static byte iconsole_scroll = ICON_BUFFER;
00083
00084 switch (e->event) {
00085 case WE_PAINT: {
00086 int i = iconsole_scroll;
00087 int max = (w->height / ICON_LINE_HEIGHT) - 1;
00088 int delta = 0;
00089 GfxFillRect(w->left, w->top, w->width, w->height - 1, 0);
00090 while ((i > 0) && (i > iconsole_scroll - max) && (_iconsole_buffer[i] != NULL)) {
00091 DoDrawString(_iconsole_buffer[i], 5,
00092 w->height - (iconsole_scroll + 2 - i) * ICON_LINE_HEIGHT, _iconsole_cbuffer[i]);
00093 i--;
00094 }
00095
00096 delta = w->width - 10 - _iconsole_cmdline.width - ICON_RIGHT_BORDERWIDTH;
00097 if (delta > 0) {
00098 DoDrawString("]", 5, w->height - ICON_LINE_HEIGHT, _icolour_cmd);
00099 delta = 0;
00100 }
00101
00102 DoDrawString(_iconsole_cmdline.buf, 10 + delta, w->height - ICON_LINE_HEIGHT, _icolour_cmd);
00103
00104 if (_iconsole_cmdline.caret)
00105 DoDrawString("_", 10 + delta + _iconsole_cmdline.caretxoffs, w->height - ICON_LINE_HEIGHT, TC_WHITE);
00106 break;
00107 }
00108 case WE_MOUSELOOP:
00109 if (HandleCaret(&_iconsole_cmdline))
00110 SetWindowDirty(w);
00111 break;
00112 case WE_DESTROY:
00113 _iconsole_mode = ICONSOLE_CLOSED;
00114 break;
00115 case WE_KEYPRESS:
00116 e->we.keypress.cont = false;
00117 switch (e->we.keypress.keycode) {
00118 case WKC_UP:
00119 IConsoleHistoryNavigate(+1);
00120 SetWindowDirty(w);
00121 break;
00122 case WKC_DOWN:
00123 IConsoleHistoryNavigate(-1);
00124 SetWindowDirty(w);
00125 break;
00126 case WKC_SHIFT | WKC_PAGEUP:
00127 if (iconsole_scroll - (w->height / ICON_LINE_HEIGHT) - 1 < 0) {
00128 iconsole_scroll = 0;
00129 } else {
00130 iconsole_scroll -= (w->height / ICON_LINE_HEIGHT) - 1;
00131 }
00132 SetWindowDirty(w);
00133 break;
00134 case WKC_SHIFT | WKC_PAGEDOWN:
00135 if (iconsole_scroll + (w->height / ICON_LINE_HEIGHT) - 1 > ICON_BUFFER) {
00136 iconsole_scroll = ICON_BUFFER;
00137 } else {
00138 iconsole_scroll += (w->height / ICON_LINE_HEIGHT) - 1;
00139 }
00140 SetWindowDirty(w);
00141 break;
00142 case WKC_SHIFT | WKC_UP:
00143 if (iconsole_scroll <= 0) {
00144 iconsole_scroll = 0;
00145 } else {
00146 --iconsole_scroll;
00147 }
00148 SetWindowDirty(w);
00149 break;
00150 case WKC_SHIFT | WKC_DOWN:
00151 if (iconsole_scroll >= ICON_BUFFER) {
00152 iconsole_scroll = ICON_BUFFER;
00153 } else {
00154 ++iconsole_scroll;
00155 }
00156 SetWindowDirty(w);
00157 break;
00158 case WKC_BACKQUOTE:
00159 IConsoleSwitch();
00160 break;
00161 case WKC_RETURN: case WKC_NUM_ENTER:
00162 IConsolePrintF(_icolour_cmd, "] %s", _iconsole_cmdline.buf);
00163 IConsoleHistoryAdd(_iconsole_cmdline.buf);
00164
00165 IConsoleCmdExec(_iconsole_cmdline.buf);
00166 IConsoleClearCommand();
00167 break;
00168 case WKC_CTRL | WKC_RETURN:
00169 _iconsole_mode = (_iconsole_mode == ICONSOLE_FULL) ? ICONSOLE_OPENED : ICONSOLE_FULL;
00170 IConsoleResize(w);
00171 MarkWholeScreenDirty();
00172 break;
00173 case (WKC_CTRL | 'V'):
00174 if (InsertTextBufferClipboard(&_iconsole_cmdline)) {
00175 IConsoleResetHistoryPos();
00176 SetWindowDirty(w);
00177 }
00178 break;
00179 case (WKC_CTRL | 'L'):
00180 IConsoleCmdExec("clear");
00181 break;
00182 case (WKC_CTRL | 'U'):
00183 DeleteTextBufferAll(&_iconsole_cmdline);
00184 SetWindowDirty(w);
00185 break;
00186 case WKC_BACKSPACE: case WKC_DELETE:
00187 if (DeleteTextBufferChar(&_iconsole_cmdline, e->we.keypress.keycode)) {
00188 IConsoleResetHistoryPos();
00189 SetWindowDirty(w);
00190 }
00191 break;
00192 case WKC_LEFT: case WKC_RIGHT: case WKC_END: case WKC_HOME:
00193 if (MoveTextBufferPos(&_iconsole_cmdline, e->we.keypress.keycode)) {
00194 IConsoleResetHistoryPos();
00195 SetWindowDirty(w);
00196 }
00197 break;
00198 default:
00199 if (IsValidChar(e->we.keypress.key, CS_ALPHANUMERAL)) {
00200 iconsole_scroll = ICON_BUFFER;
00201 InsertTextBufferChar(&_iconsole_cmdline, e->we.keypress.key);
00202 IConsoleResetHistoryPos();
00203 SetWindowDirty(w);
00204 } else {
00205 e->we.keypress.cont = true;
00206 }
00207 break;
00208 }
00209 }
00210 }
00211
00212 static const Widget _iconsole_window_widgets[] = {
00213 {WIDGETS_END}
00214 };
00215
00216 static const WindowDesc _iconsole_window_desc = {
00217 0, 0, 2, 2, 2, 2,
00218 WC_CONSOLE, WC_NONE,
00219 WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
00220 _iconsole_window_widgets,
00221 IConsoleWndProc,
00222 };
00223
00224 void IConsoleInit()
00225 {
00226 extern const char _openttd_revision[];
00227 _iconsole_output_file = NULL;
00228 _icolour_def = 1;
00229 _icolour_err = 3;
00230 _icolour_warn = 13;
00231 _icolour_dbg = 5;
00232 _icolour_cmd = TC_GOLD;
00233 _iconsole_historypos = ICON_HISTORY_SIZE - 1;
00234 _iconsole_mode = ICONSOLE_CLOSED;
00235
00236 #ifdef ENABLE_NETWORK
00237 _redirect_console_to_client = 0;
00238 #endif
00239
00240 memset(_iconsole_history, 0, sizeof(_iconsole_history));
00241 memset(_iconsole_buffer, 0, sizeof(_iconsole_buffer));
00242 memset(_iconsole_cbuffer, 0, sizeof(_iconsole_cbuffer));
00243 _iconsole_cmdline.buf = CallocT<char>(ICON_CMDLN_SIZE);
00244 _iconsole_cmdline.maxlength = ICON_CMDLN_SIZE;
00245
00246 IConsolePrintF(13, "OpenTTD Game Console Revision 7 - %s", _openttd_revision);
00247 IConsolePrint(12, "------------------------------------");
00248 IConsolePrint(12, "use \"help\" for more information");
00249 IConsolePrint(12, "");
00250 IConsoleStdLibRegister();
00251 IConsoleClearCommand();
00252 IConsoleHistoryAdd("");
00253 }
00254
00255 void IConsoleClearBuffer()
00256 {
00257 uint i;
00258 for (i = 0; i <= ICON_BUFFER; i++) {
00259 free(_iconsole_buffer[i]);
00260 _iconsole_buffer[i] = NULL;
00261 }
00262 }
00263
00264 static void IConsoleClear()
00265 {
00266 free(_iconsole_cmdline.buf);
00267 IConsoleClearBuffer();
00268 }
00269
00270 static void IConsoleWriteToLogFile(const char *string)
00271 {
00272 if (_iconsole_output_file != NULL) {
00273
00274 fwrite(string, strlen(string), 1, _iconsole_output_file);
00275 fwrite("\n", 1, 1, _iconsole_output_file);
00276 }
00277 }
00278
00279 bool CloseConsoleLogIfActive()
00280 {
00281 if (_iconsole_output_file != NULL) {
00282 IConsolePrintF(_icolour_def, "file output complete");
00283 fclose(_iconsole_output_file);
00284 _iconsole_output_file = NULL;
00285 return true;
00286 }
00287
00288 return false;
00289 }
00290
00291 void IConsoleFree()
00292 {
00293 IConsoleClear();
00294 CloseConsoleLogIfActive();
00295 }
00296
00297 void IConsoleResize(Window *w)
00298 {
00299 switch (_iconsole_mode) {
00300 case ICONSOLE_OPENED:
00301 w->height = _screen.height / 3;
00302 w->width = _screen.width;
00303 break;
00304 case ICONSOLE_FULL:
00305 w->height = _screen.height - ICON_BOTTOM_BORDERWIDTH;
00306 w->width = _screen.width;
00307 break;
00308 default: return;
00309 }
00310
00311 MarkWholeScreenDirty();
00312 }
00313
00314 void IConsoleSwitch()
00315 {
00316 switch (_iconsole_mode) {
00317 case ICONSOLE_CLOSED: {
00318 Window *w = AllocateWindowDesc(&_iconsole_window_desc);
00319 w->height = _screen.height / 3;
00320 w->width = _screen.width;
00321 _iconsole_mode = ICONSOLE_OPENED;
00322 SetBit(_no_scroll, SCROLL_CON);
00323 } break;
00324 case ICONSOLE_OPENED: case ICONSOLE_FULL:
00325 DeleteWindowById(WC_CONSOLE, 0);
00326 _iconsole_mode = ICONSOLE_CLOSED;
00327 ClrBit(_no_scroll, SCROLL_CON);
00328 break;
00329 }
00330
00331 MarkWholeScreenDirty();
00332 }
00333
00334 void IConsoleClose() {if (_iconsole_mode == ICONSOLE_OPENED) IConsoleSwitch();}
00335 void IConsoleOpen() {if (_iconsole_mode == ICONSOLE_CLOSED) IConsoleSwitch();}
00336
00342 static void IConsoleHistoryAdd(const char *cmd)
00343 {
00344 free(_iconsole_history[ICON_HISTORY_SIZE - 1]);
00345
00346 memmove(&_iconsole_history[1], &_iconsole_history[0], sizeof(_iconsole_history[0]) * (ICON_HISTORY_SIZE - 1));
00347 _iconsole_history[0] = strdup(cmd);
00348 IConsoleResetHistoryPos();
00349 }
00350
00355 static void IConsoleHistoryNavigate(int direction)
00356 {
00357 int i = _iconsole_historypos + direction;
00358
00359
00360 if (i < 0) i = ICON_HISTORY_SIZE - 1;
00361 if (i >= ICON_HISTORY_SIZE) i = 0;
00362
00363 if (direction > 0)
00364 if (_iconsole_history[i] == NULL) i = 0;
00365
00366 if (direction < 0) {
00367 while (i > 0 && _iconsole_history[i] == NULL) i--;
00368 }
00369
00370 _iconsole_historypos = i;
00371 IConsoleClearCommand();
00372
00373 assert(_iconsole_history[i] != NULL && IsInsideMM(i, 0, ICON_HISTORY_SIZE));
00374 ttd_strlcpy(_iconsole_cmdline.buf, _iconsole_history[i], _iconsole_cmdline.maxlength);
00375 UpdateTextBufferSize(&_iconsole_cmdline);
00376 }
00377
00387 void IConsolePrint(uint16 color_code, const char *string)
00388 {
00389 char *str;
00390 #ifdef ENABLE_NETWORK
00391 if (_redirect_console_to_client != 0) {
00392
00393 SEND_COMMAND(PACKET_SERVER_RCON)(NetworkFindClientStateFromIndex(_redirect_console_to_client), color_code, string);
00394 return;
00395 }
00396 #endif
00397
00398
00399
00400 str = strdup(string);
00401 str_strip_colours(str);
00402 str_validate(str);
00403
00404 if (_network_dedicated) {
00405 fprintf(stdout, "%s\n", str);
00406 fflush(stdout);
00407 IConsoleWriteToLogFile(str);
00408 free(str);
00409 return;
00410 }
00411
00412
00413
00414 free(_iconsole_buffer[0]);
00415 memmove(&_iconsole_buffer[0], &_iconsole_buffer[1], sizeof(_iconsole_buffer[0]) * ICON_BUFFER);
00416 _iconsole_buffer[ICON_BUFFER] = str;
00417
00418 memmove(&_iconsole_cbuffer[0], &_iconsole_cbuffer[1], sizeof(_iconsole_cbuffer[0]) * ICON_BUFFER);
00419 _iconsole_cbuffer[ICON_BUFFER] = color_code;
00420
00421 IConsoleWriteToLogFile(_iconsole_buffer[ICON_BUFFER]);
00422
00423 SetWindowDirty(FindWindowById(WC_CONSOLE, 0));
00424 }
00425
00431 void CDECL IConsolePrintF(uint16 color_code, const char *s, ...)
00432 {
00433 va_list va;
00434 char buf[ICON_MAX_STREAMSIZE];
00435
00436 va_start(va, s);
00437 vsnprintf(buf, sizeof(buf), s, va);
00438 va_end(va);
00439
00440 IConsolePrint(color_code, buf);
00441 }
00442
00451 void IConsoleDebug(const char *dbg, const char *string)
00452 {
00453 if (_stdlib_developer > 1)
00454 IConsolePrintF(_icolour_dbg, "dbg: [%s] %s", dbg, string);
00455 }
00456
00462 void IConsoleWarning(const char *string)
00463 {
00464 if (_stdlib_developer > 0)
00465 IConsolePrintF(_icolour_warn, "WARNING: %s", string);
00466 }
00467
00472 void IConsoleError(const char *string)
00473 {
00474 IConsolePrintF(_icolour_err, "ERROR: %s", string);
00475 }
00476
00484 bool GetArgumentInteger(uint32 *value, const char *arg)
00485 {
00486 char *endptr;
00487
00488 if (strcmp(arg, "on") == 0 || strcmp(arg, "true") == 0) {
00489 *value = 1;
00490 return true;
00491 }
00492 if (strcmp(arg, "off") == 0 || strcmp(arg, "false") == 0) {
00493 *value = 0;
00494 return true;
00495 }
00496
00497 *value = strtoul(arg, &endptr, 0);
00498 return arg != endptr;
00499 }
00500
00501
00502
00503
00504
00511 static void IConsoleHookAdd(IConsoleHooks *hooks, IConsoleHookTypes type, IConsoleHook *proc)
00512 {
00513 if (hooks == NULL || proc == NULL) return;
00514
00515 switch (type) {
00516 case ICONSOLE_HOOK_ACCESS:
00517 hooks->access = proc;
00518 break;
00519 case ICONSOLE_HOOK_PRE_ACTION:
00520 hooks->pre = proc;
00521 break;
00522 case ICONSOLE_HOOK_POST_ACTION:
00523 hooks->post = proc;
00524 break;
00525 default: NOT_REACHED();
00526 }
00527 }
00528
00537 static bool IConsoleHookHandle(const IConsoleHooks *hooks, IConsoleHookTypes type)
00538 {
00539 IConsoleHook *proc = NULL;
00540 if (hooks == NULL) return false;
00541
00542 switch (type) {
00543 case ICONSOLE_HOOK_ACCESS:
00544 proc = hooks->access;
00545 break;
00546 case ICONSOLE_HOOK_PRE_ACTION:
00547 proc = hooks->pre;
00548 break;
00549 case ICONSOLE_HOOK_POST_ACTION:
00550 proc = hooks->post;
00551 break;
00552 default: NOT_REACHED();
00553 }
00554
00555 return (proc == NULL) ? true : proc();
00556 }
00557
00564 void IConsoleCmdHookAdd(const char *name, IConsoleHookTypes type, IConsoleHook *proc)
00565 {
00566 IConsoleCmd *cmd = IConsoleCmdGet(name);
00567 if (cmd == NULL) return;
00568 IConsoleHookAdd(&cmd->hook, type, proc);
00569 }
00570
00577 void IConsoleVarHookAdd(const char *name, IConsoleHookTypes type, IConsoleHook *proc)
00578 {
00579 IConsoleVar *var = IConsoleVarGet(name);
00580 if (var == NULL) return;
00581 IConsoleHookAdd(&var->hook, type, proc);
00582 }
00583
00589 #define IConsoleAddSorted(_base, item_new, IConsoleType, type) \
00590 { \
00591 IConsoleType *item, *item_before; \
00592 \
00593 if (_base == NULL) { \
00594 _base = item_new; \
00595 return; \
00596 } \
00597 \
00598 item_before = NULL; \
00599 item = _base; \
00600 \
00601 \
00602 while (item != NULL) { \
00603 int i = strcmp(item->name, item_new->name); \
00604 if (i == 0) { \
00605 IConsoleError(type " with this name already exists; insertion aborted"); \
00606 free(item_new); \
00607 return; \
00608 } \
00609 \
00610 if (i > 0) break; \
00611 \
00612 item_before = item; \
00613 item = item->next; \
00614 } \
00615 \
00616 if (item_before == NULL) { \
00617 _base = item_new; \
00618 } else { \
00619 item_before->next = item_new; \
00620 } \
00621 \
00622 item_new->next = item; \
00623 \
00624 }
00625
00631 void IConsoleCmdRegister(const char *name, IConsoleCmdProc *proc)
00632 {
00633 char *new_cmd = strdup(name);
00634 IConsoleCmd *item_new = MallocT<IConsoleCmd>(1);
00635
00636 item_new->next = NULL;
00637 item_new->proc = proc;
00638 item_new->name = new_cmd;
00639
00640 item_new->hook.access = NULL;
00641 item_new->hook.pre = NULL;
00642 item_new->hook.post = NULL;
00643
00644 IConsoleAddSorted(_iconsole_cmds, item_new, IConsoleCmd, "a command");
00645 }
00646
00652 IConsoleCmd *IConsoleCmdGet(const char *name)
00653 {
00654 IConsoleCmd *item;
00655
00656 for (item = _iconsole_cmds; item != NULL; item = item->next) {
00657 if (strcmp(item->name, name) == 0) return item;
00658 }
00659 return NULL;
00660 }
00661
00667 void IConsoleAliasRegister(const char *name, const char *cmd)
00668 {
00669 char *new_alias = strdup(name);
00670 char *cmd_aliased = strdup(cmd);
00671 IConsoleAlias *item_new = MallocT<IConsoleAlias>(1);
00672
00673 item_new->next = NULL;
00674 item_new->cmdline = cmd_aliased;
00675 item_new->name = new_alias;
00676
00677 IConsoleAddSorted(_iconsole_aliases, item_new, IConsoleAlias, "an alias");
00678 }
00679
00685 IConsoleAlias *IConsoleAliasGet(const char *name)
00686 {
00687 IConsoleAlias* item;
00688
00689 for (item = _iconsole_aliases; item != NULL; item = item->next) {
00690 if (strcmp(item->name, name) == 0) return item;
00691 }
00692
00693 return NULL;
00694 }
00695
00697 static inline int IConsoleCopyInParams(char *dst, const char *src, uint bufpos)
00698 {
00699 int len = min(ICON_MAX_STREAMSIZE - bufpos, (uint)strlen(src));
00700 strecpy(dst, src, dst + len - 1);
00701
00702 return len;
00703 }
00704
00712 static void IConsoleAliasExec(const IConsoleAlias *alias, byte tokencount, char *tokens[ICON_TOKEN_COUNT])
00713 {
00714 const char *cmdptr;
00715 char *aliases[ICON_MAX_ALIAS_LINES], aliasstream[ICON_MAX_STREAMSIZE];
00716 uint i;
00717 uint a_index, astream_i;
00718
00719 memset(&aliases, 0, sizeof(aliases));
00720 memset(&aliasstream, 0, sizeof(aliasstream));
00721
00722 if (_stdlib_con_developer)
00723 IConsolePrintF(_icolour_dbg, "condbg: requested command is an alias; parsing...");
00724
00725 aliases[0] = aliasstream;
00726 for (cmdptr = alias->cmdline, a_index = 0, astream_i = 0; *cmdptr != '\0'; cmdptr++) {
00727 if (a_index >= lengthof(aliases) || astream_i >= lengthof(aliasstream)) break;
00728
00729 switch (*cmdptr) {
00730 case '\'':
00731 aliasstream[astream_i++] = '"';
00732 break;
00733 case ';':
00734 aliasstream[astream_i] = '\0';
00735 aliases[++a_index] = &aliasstream[++astream_i];
00736 cmdptr++;
00737 break;
00738 case '%':
00739 cmdptr++;
00740 switch (*cmdptr) {
00741 case '+': {
00742 for (i = 0; i != tokencount; i++) {
00743 aliasstream[astream_i++] = '"';
00744 astream_i += IConsoleCopyInParams(&aliasstream[astream_i], tokens[i], astream_i);
00745 aliasstream[astream_i++] = '"';
00746 aliasstream[astream_i++] = ' ';
00747 }
00748 } break;
00749 case '!': {
00750 aliasstream[astream_i++] = '"';
00751 for (i = 0; i != tokencount; i++) {
00752 astream_i += IConsoleCopyInParams(&aliasstream[astream_i], tokens[i], astream_i);
00753 aliasstream[astream_i++] = ' ';
00754 }
00755 aliasstream[astream_i++] = '"';
00756
00757 } break;
00758 default: {
00759 int param = *cmdptr - 'A';
00760
00761 if (param < 0 || param >= tokencount) {
00762 IConsoleError("too many or wrong amount of parameters passed to alias, aborting");
00763 IConsolePrintF(_icolour_warn, "Usage of alias '%s': %s", alias->name, alias->cmdline);
00764 return;
00765 }
00766
00767 aliasstream[astream_i++] = '"';
00768 astream_i += IConsoleCopyInParams(&aliasstream[astream_i], tokens[param], astream_i);
00769 aliasstream[astream_i++] = '"';
00770 } break;
00771 } break;
00772
00773 default:
00774 aliasstream[astream_i++] = *cmdptr;
00775 break;
00776 }
00777 }
00778
00779 for (i = 0; i <= a_index; i++) IConsoleCmdExec(aliases[i]);
00780 }
00781
00791 void IConsoleVarStringRegister(const char *name, void *addr, uint32 size, const char *help)
00792 {
00793 IConsoleVar *var;
00794 IConsoleVarRegister(name, addr, ICONSOLE_VAR_STRING, help);
00795 var = IConsoleVarGet(name);
00796 var->size = size;
00797 }
00798
00806 void IConsoleVarRegister(const char *name, void *addr, IConsoleVarTypes type, const char *help)
00807 {
00808 char *new_cmd = strdup(name);
00809 IConsoleVar *item_new = MallocT<IConsoleVar>(1);
00810
00811 item_new->help = (help != NULL) ? strdup(help) : NULL;
00812
00813 item_new->next = NULL;
00814 item_new->name = new_cmd;
00815 item_new->addr = addr;
00816 item_new->proc = NULL;
00817 item_new->type = type;
00818
00819 item_new->hook.access = NULL;
00820 item_new->hook.pre = NULL;
00821 item_new->hook.post = NULL;
00822
00823 IConsoleAddSorted(_iconsole_vars, item_new, IConsoleVar, "a variable");
00824 }
00825
00831 IConsoleVar *IConsoleVarGet(const char *name)
00832 {
00833 IConsoleVar *item;
00834 for (item = _iconsole_vars; item != NULL; item = item->next) {
00835 if (strcmp(item->name, name) == 0) return item;
00836 }
00837
00838 return NULL;
00839 }
00840
00846 static void IConsoleVarSetValue(const IConsoleVar *var, uint32 value)
00847 {
00848 IConsoleHookHandle(&var->hook, ICONSOLE_HOOK_PRE_ACTION);
00849 switch (var->type) {
00850 case ICONSOLE_VAR_BOOLEAN:
00851 *(bool*)var->addr = (value != 0);
00852 break;
00853 case ICONSOLE_VAR_BYTE:
00854 *(byte*)var->addr = (byte)value;
00855 break;
00856 case ICONSOLE_VAR_UINT16:
00857 *(uint16*)var->addr = (uint16)value;
00858 break;
00859 case ICONSOLE_VAR_INT16:
00860 *(int16*)var->addr = (int16)value;
00861 break;
00862 case ICONSOLE_VAR_UINT32:
00863 *(uint32*)var->addr = (uint32)value;
00864 break;
00865 case ICONSOLE_VAR_INT32:
00866 *(int32*)var->addr = (int32)value;
00867 break;
00868 default: NOT_REACHED();
00869 }
00870
00871 IConsoleHookHandle(&var->hook, ICONSOLE_HOOK_POST_ACTION);
00872 IConsoleVarPrintSetValue(var);
00873 }
00874
00881 static void IConsoleVarSetStringvalue(const IConsoleVar *var, const char *value)
00882 {
00883 if (var->type != ICONSOLE_VAR_STRING || var->addr == NULL) return;
00884
00885 IConsoleHookHandle(&var->hook, ICONSOLE_HOOK_PRE_ACTION);
00886 ttd_strlcpy((char*)var->addr, value, var->size);
00887 IConsoleHookHandle(&var->hook, ICONSOLE_HOOK_POST_ACTION);
00888 IConsoleVarPrintSetValue(var);
00889 return;
00890 }
00891
00897 static uint32 IConsoleVarGetValue(const IConsoleVar *var)
00898 {
00899 uint32 result = 0;
00900
00901 switch (var->type) {
00902 case ICONSOLE_VAR_BOOLEAN:
00903 result = *(bool*)var->addr;
00904 break;
00905 case ICONSOLE_VAR_BYTE:
00906 result = *(byte*)var->addr;
00907 break;
00908 case ICONSOLE_VAR_UINT16:
00909 result = *(uint16*)var->addr;
00910 break;
00911 case ICONSOLE_VAR_INT16:
00912 result = *(int16*)var->addr;
00913 break;
00914 case ICONSOLE_VAR_UINT32:
00915 result = *(uint32*)var->addr;
00916 break;
00917 case ICONSOLE_VAR_INT32:
00918 result = *(int32*)var->addr;
00919 break;
00920 default: NOT_REACHED();
00921 }
00922 return result;
00923 }
00924
00929 static char *IConsoleVarGetStringValue(const IConsoleVar *var)
00930 {
00931 static char tempres[50];
00932 char *value = tempres;
00933
00934 switch (var->type) {
00935 case ICONSOLE_VAR_BOOLEAN:
00936 snprintf(tempres, sizeof(tempres), "%s", (*(bool*)var->addr) ? "on" : "off");
00937 break;
00938 case ICONSOLE_VAR_BYTE:
00939 snprintf(tempres, sizeof(tempres), "%u", *(byte*)var->addr);
00940 break;
00941 case ICONSOLE_VAR_UINT16:
00942 snprintf(tempres, sizeof(tempres), "%u", *(uint16*)var->addr);
00943 break;
00944 case ICONSOLE_VAR_UINT32:
00945 snprintf(tempres, sizeof(tempres), "%u", *(uint32*)var->addr);
00946 break;
00947 case ICONSOLE_VAR_INT16:
00948 snprintf(tempres, sizeof(tempres), "%i", *(int16*)var->addr);
00949 break;
00950 case ICONSOLE_VAR_INT32:
00951 snprintf(tempres, sizeof(tempres), "%i", *(int32*)var->addr);
00952 break;
00953 case ICONSOLE_VAR_STRING:
00954 value = (char*)var->addr;
00955 break;
00956 default: NOT_REACHED();
00957 }
00958
00959 return value;
00960 }
00961
00965 void IConsoleVarPrintGetValue(const IConsoleVar *var)
00966 {
00967 char *value;
00968
00969
00970 if (var->proc != NULL) {
00971 var->proc(0, NULL);
00972 return;
00973 }
00974
00975 value = IConsoleVarGetStringValue(var);
00976 IConsolePrintF(_icolour_warn, "Current value for '%s' is: %s", var->name, value);
00977 }
00978
00983 void IConsoleVarPrintSetValue(const IConsoleVar *var)
00984 {
00985 char *value = IConsoleVarGetStringValue(var);
00986 IConsolePrintF(_icolour_warn, "'%s' changed to: %s", var->name, value);
00987 }
00988
00996 void IConsoleVarExec(const IConsoleVar *var, byte tokencount, char *token[ICON_TOKEN_COUNT])
00997 {
00998 const char *tokenptr = token[0];
00999 byte t_index = tokencount;
01000 uint32 value;
01001
01002 if (_stdlib_con_developer)
01003 IConsolePrintF(_icolour_dbg, "condbg: requested command is a variable");
01004
01005 if (tokencount == 0) {
01006 IConsoleVarPrintGetValue(var);
01007 return;
01008 }
01009
01010
01011 if (strcmp(tokenptr, "=") == 0) tokencount--;
01012
01013 if (tokencount == 1) {
01014
01015 if (var->proc != NULL) {
01016 var->proc(tokencount, &token[t_index - tokencount]);
01017 return;
01018 }
01019
01020
01021 if (var->type == ICONSOLE_VAR_STRING) {
01022 IConsoleVarSetStringvalue(var, token[t_index - tokencount]);
01023 return;
01024 } else if (GetArgumentInteger(&value, token[t_index - tokencount])) {
01025 IConsoleVarSetValue(var, value);
01026 return;
01027 }
01028
01029
01030 if (strcmp(tokenptr, "++") == 0 && var->type != ICONSOLE_VAR_STRING) {
01031 IConsoleVarSetValue(var, IConsoleVarGetValue(var) + 1);
01032 return;
01033 }
01034
01035 if (strcmp(tokenptr, "--") == 0 && var->type != ICONSOLE_VAR_STRING) {
01036 IConsoleVarSetValue(var, IConsoleVarGetValue(var) - 1);
01037 return;
01038 }
01039 }
01040
01041 IConsoleError("invalid variable assignment");
01042 }
01043
01050 void IConsoleVarProcAdd(const char *name, IConsoleCmdProc *proc)
01051 {
01052 IConsoleVar *var = IConsoleVarGet(name);
01053 if (var == NULL) return;
01054 var->proc = proc;
01055 }
01056
01062 void IConsoleCmdExec(const char *cmdstr)
01063 {
01064 IConsoleCmd *cmd = NULL;
01065 IConsoleAlias *alias = NULL;
01066 IConsoleVar *var = NULL;
01067
01068 const char *cmdptr;
01069 char *tokens[ICON_TOKEN_COUNT], tokenstream[ICON_MAX_STREAMSIZE];
01070 uint t_index, tstream_i;
01071
01072 bool longtoken = false;
01073 bool foundtoken = false;
01074
01075 if (cmdstr[0] == '#') return;
01076
01077 for (cmdptr = cmdstr; *cmdptr != '\0'; cmdptr++) {
01078 if (!IsValidChar(*cmdptr, CS_ALPHANUMERAL)) {
01079 IConsoleError("command contains malformed characters, aborting");
01080 IConsolePrintF(_icolour_err, "ERROR: command was: '%s'", cmdstr);
01081 return;
01082 }
01083 }
01084
01085 if (_stdlib_con_developer)
01086 IConsolePrintF(_icolour_dbg, "condbg: executing cmdline: '%s'", cmdstr);
01087
01088 memset(&tokens, 0, sizeof(tokens));
01089 memset(&tokenstream, 0, sizeof(tokenstream));
01090
01091
01092
01093
01094 for (cmdptr = cmdstr, t_index = 0, tstream_i = 0; *cmdptr != '\0'; cmdptr++) {
01095 if (t_index >= lengthof(tokens) || tstream_i >= lengthof(tokenstream)) break;
01096
01097 switch (*cmdptr) {
01098 case ' ':
01099 if (!foundtoken) break;
01100
01101 if (longtoken) {
01102 tokenstream[tstream_i] = *cmdptr;
01103 } else {
01104 tokenstream[tstream_i] = '\0';
01105 foundtoken = false;
01106 }
01107
01108 tstream_i++;
01109 break;
01110 case '"':
01111 longtoken = !longtoken;
01112 break;
01113 case '\\':
01114 if (cmdptr[1] == '"' && tstream_i + 1 < lengthof(tokenstream)) {
01115 tokenstream[tstream_i++] = *++cmdptr;
01116 break;
01117 }
01118
01119 default:
01120 tokenstream[tstream_i++] = *cmdptr;
01121
01122 if (!foundtoken) {
01123 tokens[t_index++] = &tokenstream[tstream_i - 1];
01124 foundtoken = true;
01125 }
01126 break;
01127 }
01128 }
01129
01130 if (_stdlib_con_developer) {
01131 uint i;
01132
01133 for (i = 0; tokens[i] != NULL; i++) {
01134 IConsolePrintF(_icolour_dbg, "condbg: token %d is: '%s'", i, tokens[i]);
01135 }
01136 }
01137
01138 if (tokens[0] == '\0') return;
01139
01140
01141
01142
01143 cmd = IConsoleCmdGet(tokens[0]);
01144 if (cmd != NULL) {
01145 if (IConsoleHookHandle(&cmd->hook, ICONSOLE_HOOK_ACCESS)) {
01146 IConsoleHookHandle(&cmd->hook, ICONSOLE_HOOK_PRE_ACTION);
01147 if (cmd->proc(t_index, tokens)) {
01148 IConsoleHookHandle(&cmd->hook, ICONSOLE_HOOK_POST_ACTION);
01149 } else {
01150 cmd->proc(0, NULL);
01151 }
01152 }
01153 return;
01154 }
01155
01156 t_index--;
01157 alias = IConsoleAliasGet(tokens[0]);
01158 if (alias != NULL) {
01159 IConsoleAliasExec(alias, t_index, &tokens[1]);
01160 return;
01161 }
01162
01163 var = IConsoleVarGet(tokens[0]);
01164 if (var != NULL) {
01165 if (IConsoleHookHandle(&var->hook, ICONSOLE_HOOK_ACCESS)) {
01166 IConsoleVarExec(var, t_index, &tokens[1]);
01167 }
01168 return;
01169 }
01170
01171 IConsoleError("command or variable not found");
01172 }