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