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