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 "debug.h"
00017 #include "console_func.h"
00018 #include "settings_type.h"
00019
00020 #include <stdarg.h>
00021
00022 #define ICON_BUFFER 79
00023 #define ICON_HISTORY_SIZE 20
00024 #define ICON_LINE_HEIGHT 12
00025 #define ICON_RIGHT_BORDERWIDTH 10
00026 #define ICON_BOTTOM_BORDERWIDTH 12
00027 #define ICON_MAX_ALIAS_LINES 40
00028 #define ICON_TOKEN_COUNT 20
00029
00030
00031 IConsoleCmd *_iconsole_cmds;
00032 IConsoleAlias *_iconsole_aliases;
00033
00034 FILE *_iconsole_output_file;
00035
00036 void IConsoleInit()
00037 {
00038 _iconsole_output_file = NULL;
00039 #ifdef ENABLE_NETWORK
00040 _redirect_console_to_client = INVALID_CLIENT_ID;
00041 #endif
00042
00043 IConsoleGUIInit();
00044
00045 IConsoleStdLibRegister();
00046 }
00047
00048 static void IConsoleWriteToLogFile(const char *string)
00049 {
00050 if (_iconsole_output_file != NULL) {
00051
00052 const char *header = GetLogPrefix();
00053 if (fwrite(header, strlen(header), 1, _iconsole_output_file) != 1 ||
00054 fwrite(string, strlen(string), 1, _iconsole_output_file) != 1 ||
00055 fwrite("\n", 1, 1, _iconsole_output_file) != 1) {
00056 fclose(_iconsole_output_file);
00057 _iconsole_output_file = NULL;
00058 IConsolePrintF(CC_DEFAULT, "cannot write to log file");
00059 }
00060 }
00061 }
00062
00063 bool CloseConsoleLogIfActive()
00064 {
00065 if (_iconsole_output_file != NULL) {
00066 IConsolePrintF(CC_DEFAULT, "file output complete");
00067 fclose(_iconsole_output_file);
00068 _iconsole_output_file = NULL;
00069 return true;
00070 }
00071
00072 return false;
00073 }
00074
00075 void IConsoleFree()
00076 {
00077 IConsoleGUIFree();
00078 CloseConsoleLogIfActive();
00079 }
00080
00090 void IConsolePrint(ConsoleColour colour_code, const char *string)
00091 {
00092 char *str;
00093 #ifdef ENABLE_NETWORK
00094 if (_redirect_console_to_client != INVALID_CLIENT_ID) {
00095
00096 NetworkServerSendRcon(_redirect_console_to_client, colour_code, string);
00097 return;
00098 }
00099 #endif
00100
00101
00102
00103 str = strdup(string);
00104 str_strip_colours(str);
00105 str_validate(str, str + strlen(str));
00106
00107 if (_network_dedicated) {
00108 fprintf(stdout, "%s%s\n", GetLogPrefix(), str);
00109 fflush(stdout);
00110 IConsoleWriteToLogFile(str);
00111 free(str);
00112 return;
00113 }
00114
00115 IConsoleWriteToLogFile(str);
00116 IConsoleGUIPrint(colour_code, str);
00117 }
00118
00124 void CDECL IConsolePrintF(ConsoleColour colour_code, const char *format, ...)
00125 {
00126 va_list va;
00127 char buf[ICON_MAX_STREAMSIZE];
00128
00129 va_start(va, format);
00130 vsnprintf(buf, sizeof(buf), format, va);
00131 va_end(va);
00132
00133 IConsolePrint(colour_code, buf);
00134 }
00135
00144 void IConsoleDebug(const char *dbg, const char *string)
00145 {
00146 if (_settings_client.gui.developer <= 1) return;
00147 IConsolePrintF(CC_DEBUG, "dbg: [%s] %s", dbg, string);
00148 }
00149
00155 void IConsoleWarning(const char *string)
00156 {
00157 if (_settings_client.gui.developer == 0) return;
00158 IConsolePrintF(CC_WARNING, "WARNING: %s", string);
00159 }
00160
00165 void IConsoleError(const char *string)
00166 {
00167 IConsolePrintF(CC_ERROR, "ERROR: %s", string);
00168 }
00169
00177 bool GetArgumentInteger(uint32 *value, const char *arg)
00178 {
00179 char *endptr;
00180
00181 if (strcmp(arg, "on") == 0 || strcmp(arg, "true") == 0) {
00182 *value = 1;
00183 return true;
00184 }
00185 if (strcmp(arg, "off") == 0 || strcmp(arg, "false") == 0) {
00186 *value = 0;
00187 return true;
00188 }
00189
00190 *value = strtoul(arg, &endptr, 0);
00191 return arg != endptr;
00192 }
00193
00199 #define IConsoleAddSorted(_base, item_new, IConsoleType, type) \
00200 { \
00201 IConsoleType *item, *item_before; \
00202 \
00203 if (_base == NULL) { \
00204 _base = item_new; \
00205 return; \
00206 } \
00207 \
00208 item_before = NULL; \
00209 item = _base; \
00210 \
00211 \
00212 while (item != NULL) { \
00213 int i = strcmp(item->name, item_new->name); \
00214 if (i == 0) { \
00215 IConsoleError(type " with this name already exists; insertion aborted"); \
00216 free(item_new); \
00217 return; \
00218 } \
00219 \
00220 if (i > 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 }
00235
00241 void IConsoleCmdRegister(const char *name, IConsoleCmdProc *proc, IConsoleHook *hook)
00242 {
00243 IConsoleCmd *item_new = MallocT<IConsoleCmd>(1);
00244 item_new->name = strdup(name);
00245 item_new->next = NULL;
00246 item_new->proc = proc;
00247 item_new->hook = hook;
00248
00249 IConsoleAddSorted(_iconsole_cmds, item_new, IConsoleCmd, "a command");
00250 }
00251
00257 IConsoleCmd *IConsoleCmdGet(const char *name)
00258 {
00259 IConsoleCmd *item;
00260
00261 for (item = _iconsole_cmds; item != NULL; item = item->next) {
00262 if (strcmp(item->name, name) == 0) return item;
00263 }
00264 return NULL;
00265 }
00266
00272 void IConsoleAliasRegister(const char *name, const char *cmd)
00273 {
00274 char *new_alias = strdup(name);
00275 char *cmd_aliased = strdup(cmd);
00276 IConsoleAlias *item_new = MallocT<IConsoleAlias>(1);
00277
00278 item_new->next = NULL;
00279 item_new->cmdline = cmd_aliased;
00280 item_new->name = new_alias;
00281
00282 IConsoleAddSorted(_iconsole_aliases, item_new, IConsoleAlias, "an alias");
00283 }
00284
00290 IConsoleAlias *IConsoleAliasGet(const char *name)
00291 {
00292 IConsoleAlias *item;
00293
00294 for (item = _iconsole_aliases; item != NULL; item = item->next) {
00295 if (strcmp(item->name, name) == 0) return item;
00296 }
00297
00298 return NULL;
00299 }
00300
00302 static inline int IConsoleCopyInParams(char *dst, const char *src, uint bufpos)
00303 {
00304
00305 int len = min(ICON_MAX_STREAMSIZE - bufpos - 1, (uint)strlen(src));
00306 strecpy(dst, src, dst + len);
00307
00308 return len;
00309 }
00310
00318 static void IConsoleAliasExec(const IConsoleAlias *alias, byte tokencount, char *tokens[ICON_TOKEN_COUNT])
00319 {
00320 const char *cmdptr;
00321 char *aliases[ICON_MAX_ALIAS_LINES], aliasstream[ICON_MAX_STREAMSIZE];
00322 uint i;
00323 uint a_index, astream_i;
00324
00325 memset(&aliases, 0, sizeof(aliases));
00326 memset(&aliasstream, 0, sizeof(aliasstream));
00327
00328 DEBUG(console, 6, "Requested command is an alias; parsing...");
00329
00330 aliases[0] = aliasstream;
00331 for (cmdptr = alias->cmdline, a_index = 0, astream_i = 0; *cmdptr != '\0'; cmdptr++) {
00332 if (a_index >= lengthof(aliases) || astream_i >= lengthof(aliasstream)) break;
00333
00334 switch (*cmdptr) {
00335 case '\'':
00336 aliasstream[astream_i++] = '"';
00337 break;
00338 case ';':
00339 aliasstream[astream_i] = '\0';
00340 aliases[++a_index] = &aliasstream[++astream_i];
00341 cmdptr++;
00342 break;
00343 case '%':
00344 cmdptr++;
00345 switch (*cmdptr) {
00346 case '+': {
00347 for (i = 0; i != tokencount; i++) {
00348 aliasstream[astream_i++] = '"';
00349 astream_i += IConsoleCopyInParams(&aliasstream[astream_i], tokens[i], astream_i);
00350 aliasstream[astream_i++] = '"';
00351 aliasstream[astream_i++] = ' ';
00352 }
00353 } break;
00354 case '!': {
00355 aliasstream[astream_i++] = '"';
00356 for (i = 0; i != tokencount; i++) {
00357 astream_i += IConsoleCopyInParams(&aliasstream[astream_i], tokens[i], astream_i);
00358 aliasstream[astream_i++] = ' ';
00359 }
00360 aliasstream[astream_i++] = '"';
00361
00362 } break;
00363 default: {
00364 int param = *cmdptr - 'A';
00365
00366 if (param < 0 || param >= tokencount) {
00367 IConsoleError("too many or wrong amount of parameters passed to alias, aborting");
00368 IConsolePrintF(CC_WARNING, "Usage of alias '%s': %s", alias->name, alias->cmdline);
00369 return;
00370 }
00371
00372 aliasstream[astream_i++] = '"';
00373 astream_i += IConsoleCopyInParams(&aliasstream[astream_i], tokens[param], astream_i);
00374 aliasstream[astream_i++] = '"';
00375 } break;
00376 } break;
00377
00378 default:
00379 aliasstream[astream_i++] = *cmdptr;
00380 break;
00381 }
00382 }
00383
00384 for (i = 0; i <= a_index; i++) IConsoleCmdExec(aliases[i]);
00385 }
00386
00392 void IConsoleCmdExec(const char *cmdstr)
00393 {
00394 IConsoleCmd *cmd = NULL;
00395 IConsoleAlias *alias = NULL;
00396
00397 const char *cmdptr;
00398 char *tokens[ICON_TOKEN_COUNT], tokenstream[ICON_MAX_STREAMSIZE];
00399 uint t_index, tstream_i;
00400
00401 bool longtoken = false;
00402 bool foundtoken = false;
00403
00404 if (cmdstr[0] == '#') return;
00405
00406 for (cmdptr = cmdstr; *cmdptr != '\0'; cmdptr++) {
00407 if (!IsValidChar(*cmdptr, CS_ALPHANUMERAL)) {
00408 IConsoleError("command contains malformed characters, aborting");
00409 IConsolePrintF(CC_ERROR, "ERROR: command was: '%s'", cmdstr);
00410 return;
00411 }
00412 }
00413
00414 DEBUG(console, 4, "Executing cmdline: '%s'", cmdstr);
00415
00416 memset(&tokens, 0, sizeof(tokens));
00417 memset(&tokenstream, 0, sizeof(tokenstream));
00418
00419
00420
00421
00422 for (cmdptr = cmdstr, t_index = 0, tstream_i = 0; *cmdptr != '\0'; cmdptr++) {
00423 if (t_index >= lengthof(tokens) || tstream_i >= lengthof(tokenstream)) break;
00424
00425 switch (*cmdptr) {
00426 case ' ':
00427 if (!foundtoken) break;
00428
00429 if (longtoken) {
00430 tokenstream[tstream_i] = *cmdptr;
00431 } else {
00432 tokenstream[tstream_i] = '\0';
00433 foundtoken = false;
00434 }
00435
00436 tstream_i++;
00437 break;
00438 case '"':
00439 longtoken = !longtoken;
00440 break;
00441 case '\\':
00442 if (cmdptr[1] == '"' && tstream_i + 1 < lengthof(tokenstream)) {
00443 tokenstream[tstream_i++] = *++cmdptr;
00444 break;
00445 }
00446
00447 default:
00448 tokenstream[tstream_i++] = *cmdptr;
00449
00450 if (!foundtoken) {
00451 tokens[t_index++] = &tokenstream[tstream_i - 1];
00452 foundtoken = true;
00453 }
00454 break;
00455 }
00456 }
00457
00458 for (uint i = 0; tokens[i] != NULL; i++) {
00459 DEBUG(console, 8, "Token %d is: '%s'", i, tokens[i]);
00460 }
00461
00462 if (tokens[0] == '\0') return;
00463
00464
00465
00466
00467 cmd = IConsoleCmdGet(tokens[0]);
00468 if (cmd != NULL) {
00469 if (cmd->hook == NULL || cmd->hook()) {
00470 if (!cmd->proc(t_index, tokens)) {
00471 cmd->proc(0, NULL);
00472 }
00473 }
00474 return;
00475 }
00476
00477 t_index--;
00478 alias = IConsoleAliasGet(tokens[0]);
00479 if (alias != NULL) {
00480 IConsoleAliasExec(alias, t_index, &tokens[1]);
00481 return;
00482 }
00483
00484 IConsoleError("command not found");
00485 }