00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "console_internal.h"
00014 #include "network/network.h"
00015 #include "network/network_func.h"
00016 #include "network/network_admin.h"
00017 #include "debug.h"
00018 #include "console_func.h"
00019 #include "settings_type.h"
00020
00021 #include <stdarg.h>
00022
00023 #define ICON_BUFFER 79
00024 #define ICON_HISTORY_SIZE 20
00025 #define ICON_LINE_HEIGHT 12
00026 #define ICON_RIGHT_BORDERWIDTH 10
00027 #define ICON_BOTTOM_BORDERWIDTH 12
00028 #define ICON_MAX_ALIAS_LINES 40
00029 #define ICON_TOKEN_COUNT 20
00030
00031
00032 IConsoleCmd *_iconsole_cmds;
00033 IConsoleAlias *_iconsole_aliases;
00034
00035 FILE *_iconsole_output_file;
00036
00037 void IConsoleInit()
00038 {
00039 _iconsole_output_file = NULL;
00040 #ifdef ENABLE_NETWORK
00041 _redirect_console_to_client = INVALID_CLIENT_ID;
00042 _redirect_console_to_admin = INVALID_ADMIN_ID;
00043 #endif
00044
00045 IConsoleGUIInit();
00046
00047 IConsoleStdLibRegister();
00048 }
00049
00050 static void IConsoleWriteToLogFile(const char *string)
00051 {
00052 if (_iconsole_output_file != NULL) {
00053
00054 const char *header = GetLogPrefix();
00055 if ((strlen(header) != 0 && fwrite(header, strlen(header), 1, _iconsole_output_file) != 1) ||
00056 fwrite(string, strlen(string), 1, _iconsole_output_file) != 1 ||
00057 fwrite("\n", 1, 1, _iconsole_output_file) != 1) {
00058 fclose(_iconsole_output_file);
00059 _iconsole_output_file = NULL;
00060 IConsolePrintF(CC_DEFAULT, "cannot write to log file");
00061 }
00062 }
00063 }
00064
00065 bool CloseConsoleLogIfActive()
00066 {
00067 if (_iconsole_output_file != NULL) {
00068 IConsolePrintF(CC_DEFAULT, "file output complete");
00069 fclose(_iconsole_output_file);
00070 _iconsole_output_file = NULL;
00071 return true;
00072 }
00073
00074 return false;
00075 }
00076
00077 void IConsoleFree()
00078 {
00079 IConsoleGUIFree();
00080 CloseConsoleLogIfActive();
00081 }
00082
00092 void IConsolePrint(ConsoleColour colour_code, const char *string)
00093 {
00094 char *str;
00095 #ifdef ENABLE_NETWORK
00096 if (_redirect_console_to_client != INVALID_CLIENT_ID) {
00097
00098 NetworkServerSendRcon(_redirect_console_to_client, colour_code, string);
00099 return;
00100 }
00101
00102 if (_redirect_console_to_admin != INVALID_ADMIN_ID) {
00103 NetworkServerSendAdminRcon(_redirect_console_to_admin, colour_code, string);
00104 return;
00105 }
00106 #endif
00107
00108
00109
00110 str = strdup(string);
00111 str_strip_colours(str);
00112 str_validate(str, str + strlen(str));
00113
00114 if (_network_dedicated) {
00115 #ifdef ENABLE_NETWORK
00116 NetworkAdminConsole("console", str);
00117 #endif
00118 fprintf(stdout, "%s%s\n", GetLogPrefix(), str);
00119 fflush(stdout);
00120 IConsoleWriteToLogFile(str);
00121 free(str);
00122 return;
00123 }
00124
00125 IConsoleWriteToLogFile(str);
00126 IConsoleGUIPrint(colour_code, str);
00127 }
00128
00134 void CDECL IConsolePrintF(ConsoleColour colour_code, const char *format, ...)
00135 {
00136 va_list va;
00137 char buf[ICON_MAX_STREAMSIZE];
00138
00139 va_start(va, format);
00140 vsnprintf(buf, sizeof(buf), format, va);
00141 va_end(va);
00142
00143 IConsolePrint(colour_code, buf);
00144 }
00145
00154 void IConsoleDebug(const char *dbg, const char *string)
00155 {
00156 if (_settings_client.gui.developer <= 1) return;
00157 IConsolePrintF(CC_DEBUG, "dbg: [%s] %s", dbg, string);
00158 }
00159
00165 void IConsoleWarning(const char *string)
00166 {
00167 if (_settings_client.gui.developer == 0) return;
00168 IConsolePrintF(CC_WARNING, "WARNING: %s", string);
00169 }
00170
00175 void IConsoleError(const char *string)
00176 {
00177 IConsolePrintF(CC_ERROR, "ERROR: %s", string);
00178 }
00179
00187 bool GetArgumentInteger(uint32 *value, const char *arg)
00188 {
00189 char *endptr;
00190
00191 if (strcmp(arg, "on") == 0 || strcmp(arg, "true") == 0) {
00192 *value = 1;
00193 return true;
00194 }
00195 if (strcmp(arg, "off") == 0 || strcmp(arg, "false") == 0) {
00196 *value = 0;
00197 return true;
00198 }
00199
00200 *value = strtoul(arg, &endptr, 0);
00201 return arg != endptr;
00202 }
00203
00209 template<class T>
00210 void IConsoleAddSorted(T **base, T *item_new)
00211 {
00212 if (*base == NULL) {
00213 *base = item_new;
00214 return;
00215 }
00216
00217 T *item_before = NULL;
00218 T *item = *base;
00219
00220 while (item != NULL) {
00221 if (strcmp(item->name, item_new->name) > 0) break;
00222
00223 item_before = item;
00224 item = item->next;
00225 }
00226
00227 if (item_before == NULL) {
00228 *base = item_new;
00229 } else {
00230 item_before->next = item_new;
00231 }
00232
00233 item_new->next = item;
00234 }
00235
00241 char *RemoveUnderscores(char *name)
00242 {
00243 char *q = name;
00244 for (const char *p = name; *p != '\0'; p++) {
00245 if (*p != '_') *q++ = *p;
00246 }
00247 *q = '\0';
00248 return name;
00249 }
00250
00256 void IConsoleCmdRegister(const char *name, IConsoleCmdProc *proc, IConsoleHook *hook)
00257 {
00258 IConsoleCmd *item_new = MallocT<IConsoleCmd>(1);
00259 item_new->name = RemoveUnderscores(strdup(name));
00260 item_new->next = NULL;
00261 item_new->proc = proc;
00262 item_new->hook = hook;
00263
00264 IConsoleAddSorted(&_iconsole_cmds, item_new);
00265 }
00266
00272 IConsoleCmd *IConsoleCmdGet(const char *name)
00273 {
00274 IConsoleCmd *item;
00275
00276 for (item = _iconsole_cmds; item != NULL; item = item->next) {
00277 if (strcmp(item->name, name) == 0) return item;
00278 }
00279 return NULL;
00280 }
00281
00287 void IConsoleAliasRegister(const char *name, const char *cmd)
00288 {
00289 if (IConsoleAliasGet(name) != NULL) {
00290 IConsoleError("an alias with this name already exists; insertion aborted");
00291 return;
00292 }
00293
00294 char *new_alias = RemoveUnderscores(strdup(name));
00295 char *cmd_aliased = strdup(cmd);
00296 IConsoleAlias *item_new = MallocT<IConsoleAlias>(1);
00297
00298 item_new->next = NULL;
00299 item_new->cmdline = cmd_aliased;
00300 item_new->name = new_alias;
00301
00302 IConsoleAddSorted(&_iconsole_aliases, item_new);
00303 }
00304
00310 IConsoleAlias *IConsoleAliasGet(const char *name)
00311 {
00312 IConsoleAlias *item;
00313
00314 for (item = _iconsole_aliases; item != NULL; item = item->next) {
00315 if (strcmp(item->name, name) == 0) return item;
00316 }
00317
00318 return NULL;
00319 }
00320
00322 static inline int IConsoleCopyInParams(char *dst, const char *src, uint bufpos)
00323 {
00324
00325 int len = min(ICON_MAX_STREAMSIZE - bufpos - 1, (uint)strlen(src));
00326 strecpy(dst, src, dst + len);
00327
00328 return len;
00329 }
00330
00338 static void IConsoleAliasExec(const IConsoleAlias *alias, byte tokencount, char *tokens[ICON_TOKEN_COUNT])
00339 {
00340 const char *cmdptr;
00341 char *aliases[ICON_MAX_ALIAS_LINES], aliasstream[ICON_MAX_STREAMSIZE];
00342 uint i;
00343 uint a_index, astream_i;
00344
00345 memset(&aliases, 0, sizeof(aliases));
00346 memset(&aliasstream, 0, sizeof(aliasstream));
00347
00348 DEBUG(console, 6, "Requested command is an alias; parsing...");
00349
00350 aliases[0] = aliasstream;
00351 for (cmdptr = alias->cmdline, a_index = 0, astream_i = 0; *cmdptr != '\0'; cmdptr++) {
00352 if (a_index >= lengthof(aliases) || astream_i >= lengthof(aliasstream)) break;
00353
00354 switch (*cmdptr) {
00355 case '\'':
00356 aliasstream[astream_i++] = '"';
00357 break;
00358
00359 case ';':
00360 aliasstream[astream_i] = '\0';
00361 aliases[++a_index] = &aliasstream[++astream_i];
00362 cmdptr++;
00363 break;
00364
00365 case '%':
00366 cmdptr++;
00367 switch (*cmdptr) {
00368 case '+': {
00369 for (i = 0; i != tokencount; i++) {
00370 aliasstream[astream_i++] = '"';
00371 astream_i += IConsoleCopyInParams(&aliasstream[astream_i], tokens[i], astream_i);
00372 aliasstream[astream_i++] = '"';
00373 aliasstream[astream_i++] = ' ';
00374 }
00375 break;
00376 }
00377
00378 case '!': {
00379 aliasstream[astream_i++] = '"';
00380 for (i = 0; i != tokencount; i++) {
00381 astream_i += IConsoleCopyInParams(&aliasstream[astream_i], tokens[i], astream_i);
00382 aliasstream[astream_i++] = ' ';
00383 }
00384 aliasstream[astream_i++] = '"';
00385 break;
00386 }
00387
00388 default: {
00389 int param = *cmdptr - 'A';
00390
00391 if (param < 0 || param >= tokencount) {
00392 IConsoleError("too many or wrong amount of parameters passed to alias, aborting");
00393 IConsolePrintF(CC_WARNING, "Usage of alias '%s': %s", alias->name, alias->cmdline);
00394 return;
00395 }
00396
00397 aliasstream[astream_i++] = '"';
00398 astream_i += IConsoleCopyInParams(&aliasstream[astream_i], tokens[param], astream_i);
00399 aliasstream[astream_i++] = '"';
00400 break;
00401 }
00402 }
00403 break;
00404
00405 default:
00406 aliasstream[astream_i++] = *cmdptr;
00407 break;
00408 }
00409 }
00410
00411 for (i = 0; i <= a_index; i++) IConsoleCmdExec(aliases[i]);
00412 }
00413
00419 void IConsoleCmdExec(const char *cmdstr)
00420 {
00421 const char *cmdptr;
00422 char *tokens[ICON_TOKEN_COUNT], tokenstream[ICON_MAX_STREAMSIZE];
00423 uint t_index, tstream_i;
00424
00425 bool longtoken = false;
00426 bool foundtoken = false;
00427
00428 if (cmdstr[0] == '#') return;
00429
00430 for (cmdptr = cmdstr; *cmdptr != '\0'; cmdptr++) {
00431 if (!IsValidChar(*cmdptr, CS_ALPHANUMERAL)) {
00432 IConsoleError("command contains malformed characters, aborting");
00433 IConsolePrintF(CC_ERROR, "ERROR: command was: '%s'", cmdstr);
00434 return;
00435 }
00436 }
00437
00438 DEBUG(console, 4, "Executing cmdline: '%s'", cmdstr);
00439
00440 memset(&tokens, 0, sizeof(tokens));
00441 memset(&tokenstream, 0, sizeof(tokenstream));
00442
00443
00444
00445
00446 for (cmdptr = cmdstr, t_index = 0, tstream_i = 0; *cmdptr != '\0'; cmdptr++) {
00447 if (t_index >= lengthof(tokens) || tstream_i >= lengthof(tokenstream)) break;
00448
00449 switch (*cmdptr) {
00450 case ' ':
00451 if (!foundtoken) break;
00452
00453 if (longtoken) {
00454 tokenstream[tstream_i] = *cmdptr;
00455 } else {
00456 tokenstream[tstream_i] = '\0';
00457 foundtoken = false;
00458 }
00459
00460 tstream_i++;
00461 break;
00462 case '"':
00463 longtoken = !longtoken;
00464 if (!foundtoken) {
00465 tokens[t_index++] = &tokenstream[tstream_i];
00466 foundtoken = true;
00467 }
00468 break;
00469 case '\\':
00470 if (cmdptr[1] == '"' && tstream_i + 1 < lengthof(tokenstream)) {
00471 tokenstream[tstream_i++] = *++cmdptr;
00472 break;
00473 }
00474
00475 default:
00476 tokenstream[tstream_i++] = *cmdptr;
00477
00478 if (!foundtoken) {
00479 tokens[t_index++] = &tokenstream[tstream_i - 1];
00480 foundtoken = true;
00481 }
00482 break;
00483 }
00484 }
00485
00486 for (uint i = 0; tokens[i] != NULL; i++) {
00487 DEBUG(console, 8, "Token %d is: '%s'", i, tokens[i]);
00488 }
00489
00490 if (tokens[0] == '\0') return;
00491
00492
00493
00494
00495 RemoveUnderscores(tokens[0]);
00496 IConsoleCmd *cmd = IConsoleCmdGet(tokens[0]);
00497 if (cmd != NULL) {
00498 ConsoleHookResult chr = (cmd->hook == NULL ? CHR_ALLOW : cmd->hook(true));
00499 switch (chr) {
00500 case CHR_ALLOW:
00501 if (!cmd->proc(t_index, tokens)) {
00502 cmd->proc(0, NULL);
00503 }
00504 return;
00505
00506 case CHR_DISALLOW: return;
00507 case CHR_HIDE: break;
00508 }
00509 }
00510
00511 t_index--;
00512 IConsoleAlias *alias = IConsoleAliasGet(tokens[0]);
00513 if (alias != NULL) {
00514 IConsoleAliasExec(alias, t_index, &tokens[1]);
00515 return;
00516 }
00517
00518 IConsoleError("command not found");
00519 }