X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=console.c;h=12df5d1adb31790f2b096855797522be6a2f6a6e;hb=4b164eed56b6a99c6abde650578d7a30c0e51bf1;hp=feb70bacfbdc1474ef315c0b0baa01fc966711b9;hpb=2cbfd57208b7e0050bf532456dedae601670af88;p=xonotic%2Fdarkplaces.git diff --git a/console.c b/console.c index feb70bac..12df5d1a 100644 --- a/console.c +++ b/console.c @@ -28,38 +28,17 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. float con_cursorspeed = 4; -#define CON_TEXTSIZE 131072 -#define CON_MAXLINES 4096 +#define CON_TEXTSIZE 1048576 +#define CON_MAXLINES 16384 // lines up from bottom to display int con_backscroll; -// console buffer -char con_text[CON_TEXTSIZE]; +conbuffer_t con; -#define CON_MASK_HIDENOTIFY 128 -#define CON_MASK_CHAT 1 - -typedef struct -{ - char *start; - int len; - - double addtime; - int mask; - - int height; // recalculated line height when needed (-1 to unset) -} -con_lineinfo; -con_lineinfo con_lines[CON_MAXLINES]; - -int con_lines_first; // cyclic buffer -int con_lines_count; -#define CON_LINES_IDX(i) ((con_lines_first + (i)) % CON_MAXLINES) -#define CON_LINES_LAST CON_LINES_IDX(con_lines_count - 1) -#define CON_LINES(i) con_lines[CON_LINES_IDX(i)] -#define CON_LINES_PRED(i) (((i) + CON_MAXLINES - 1) % CON_MAXLINES) -#define CON_LINES_SUCC(i) (((i) + 1) % CON_MAXLINES) +#define CON_LINES(i) CONBUFFER_LINES(&con, i) +#define CON_LINES_LAST CONBUFFER_LINES_LAST(&con) +#define CON_LINES_COUNT CONBUFFER_LINES_COUNT(&con) cvar_t con_notifytime = {CVAR_SAVE, "con_notifytime","3", "how long notify lines last, in seconds"}; cvar_t con_notify = {CVAR_SAVE, "con_notify","4", "how many notify lines to show"}; @@ -96,9 +75,9 @@ cvar_t con_nickcompletion_flags = {CVAR_SAVE, "con_nickcompletion_flags", "11", #define NICKS_ALPHANUMERICS_ONLY 8 #define NICKS_NO_SPACES 16 -cvar_t con_completion_playdemo = {CVAR_SAVE, "con_completion_playdemo", "*.dem"}; -cvar_t con_completion_timedemo = {CVAR_SAVE, "con_completion_timedemo", "*.dem"}; -cvar_t con_completion_exec = {CVAR_SAVE, "con_completion_exec", "*.cfg"}; +cvar_t con_completion_playdemo = {CVAR_SAVE, "con_completion_playdemo", "*.dem", "completion pattern for the playdemo command"}; +cvar_t con_completion_timedemo = {CVAR_SAVE, "con_completion_timedemo", "*.dem", "completion pattern for the timedemo command"}; +cvar_t con_completion_exec = {CVAR_SAVE, "con_completion_exec", "*.cfg", "completion pattern for the exec command"}; int con_linewidth; int con_vislines; @@ -111,6 +90,216 @@ lhnetaddress_t *rcon_redirect_dest = NULL; int rcon_redirect_bufferpos = 0; char rcon_redirect_buffer[1400]; +// generic functions for console buffers + +void ConBuffer_Init(conbuffer_t *buf, int textsize, int maxlines, mempool_t *mempool) +{ + buf->textsize = textsize; + buf->text = (char *) Mem_Alloc(mempool, textsize); + buf->maxlines = maxlines; + buf->lines = (con_lineinfo_t *) Mem_Alloc(mempool, maxlines * sizeof(*buf->lines)); + buf->lines_first = 0; + buf->lines_count = 0; +} + +/* +================ +ConBuffer_Clear +================ +*/ +void ConBuffer_Clear (conbuffer_t *buf) +{ + buf->lines_count = 0; +} + +/* +================ +ConBuffer_Shutdown +================ +*/ +void ConBuffer_Shutdown(conbuffer_t *buf) +{ + Mem_Free(buf->text); + Mem_Free(buf->lines); + buf->text = NULL; + buf->lines = NULL; +} + +/* +================ +ConBuffer_FixTimes + +Notifies the console code about the current time +(and shifts back times of other entries when the time +went backwards) +================ +*/ +void ConBuffer_FixTimes(conbuffer_t *buf) +{ + int i; + if(buf->lines_count >= 1) + { + double diff = cl.time - CONBUFFER_LINES_LAST(buf).addtime; + if(diff < 0) + { + for(i = 0; i < buf->lines_count; ++i) + CONBUFFER_LINES(buf, i).addtime += diff; + } + } +} + +/* +================ +ConBuffer_DeleteLine + +Deletes the first line from the console history. +================ +*/ +void ConBuffer_DeleteLine(conbuffer_t *buf) +{ + if(buf->lines_count == 0) + return; + --buf->lines_count; + buf->lines_first = (buf->lines_first + 1) % buf->maxlines; +} + +/* +================ +ConBuffer_DeleteLastLine + +Deletes the last line from the console history. +================ +*/ +void ConBuffer_DeleteLastLine(conbuffer_t *buf) +{ + if(buf->lines_count == 0) + return; + --buf->lines_count; +} + +/* +================ +ConBuffer_BytesLeft + +Checks if there is space for a line of the given length, and if yes, returns a +pointer to the start of such a space, and NULL otherwise. +================ +*/ +static char *ConBuffer_BytesLeft(conbuffer_t *buf, int len) +{ + if(len > buf->textsize) + return NULL; + if(buf->lines_count == 0) + return buf->text; + else + { + char *firstline_start = buf->lines[buf->lines_first].start; + char *lastline_onepastend = CONBUFFER_LINES_LAST(buf).start + CONBUFFER_LINES_LAST(buf).len; + // the buffer is cyclic, so we first have two cases... + if(firstline_start < lastline_onepastend) // buffer is contiguous + { + // put at end? + if(len <= buf->text + buf->textsize - lastline_onepastend) + return lastline_onepastend; + // put at beginning? + else if(len <= firstline_start - buf->text) + return buf->text; + else + return NULL; + } + else // buffer has a contiguous hole + { + if(len <= firstline_start - lastline_onepastend) + return lastline_onepastend; + else + return NULL; + } + } +} + +/* +================ +ConBuffer_AddLine + +Appends a given string as a new line to the console. +================ +*/ +void ConBuffer_AddLine(conbuffer_t *buf, const char *line, int len, int mask) +{ + char *putpos; + con_lineinfo_t *p; + + ConBuffer_FixTimes(buf); + + if(len >= buf->textsize) + { + // line too large? + // only display end of line. + line += len - buf->textsize + 1; + len = buf->textsize - 1; + } + while(!(putpos = ConBuffer_BytesLeft(buf, len + 1)) || buf->lines_count >= buf->maxlines) + ConBuffer_DeleteLine(buf); + memcpy(putpos, line, len); + putpos[len] = 0; + ++buf->lines_count; + + //fprintf(stderr, "Now have %d lines (%d -> %d).\n", buf->lines_count, buf->lines_first, CON_LINES_LAST); + + p = &CONBUFFER_LINES_LAST(buf); + p->start = putpos; + p->len = len; + p->addtime = cl.time; + p->mask = mask; + p->height = -1; // calculate when needed +} + +int ConBuffer_FindPrevLine(conbuffer_t *buf, int mask_must, int mask_mustnot, int start) +{ + int i; + if(start == -1) + start = buf->lines_count; + for(i = start - 1; i >= 0; --i) + { + con_lineinfo_t *l = &CONBUFFER_LINES(buf, i); + + if((l->mask & mask_must) != mask_must) + continue; + if(l->mask & mask_mustnot) + continue; + + return i; + } + + return -1; +} + +int Con_FindNextLine(conbuffer_t *buf, int mask_must, int mask_mustnot, int start) +{ + int i; + for(i = start + 1; i < buf->lines_count; ++i) + { + con_lineinfo_t *l = &CONBUFFER_LINES(buf, i); + + if((l->mask & mask_must) != mask_must) + continue; + if(l->mask & mask_mustnot) + continue; + + return i; + } + + return -1; +} + +const char *ConBuffer_GetLine(conbuffer_t *buf, int i) +{ + static char copybuf[MAX_INPUTLINE]; + con_lineinfo_t *l = &CONBUFFER_LINES(buf, i); + size_t sz = l->len+1 > sizeof(copybuf) ? sizeof(copybuf) : l->len+1; + strlcpy(copybuf, l->start, sz); + return copybuf; +} /* ============================================================================== @@ -120,11 +309,13 @@ LOGGING ============================================================================== */ +/// \name Logging +//@{ cvar_t log_file = {0, "log_file","", "filename to log messages to"}; cvar_t log_dest_udp = {0, "log_dest_udp","", "UDP address to log messages to (in QW rcon compatible format); multiple destinations can be separated by spaces; DO NOT SPECIFY DNS NAMES HERE"}; char log_dest_buffer[1400]; // UDP packet size_t log_dest_buffer_pos; -qboolean log_dest_buffer_appending; +unsigned int log_dest_buffer_appending; char crt_log_file [MAX_OSPATH] = ""; qfile_t* logfile = NULL; @@ -133,7 +324,7 @@ size_t logq_ind = 0; size_t logq_size = 0; void Log_ConPrint (const char *msg); - +//@} /* ==================== Log_DestBuffer_Init @@ -397,28 +588,15 @@ void Con_ToggleConsole_f (void) Con_ClearNotify(); } -/* -================ -Con_Clear_f -================ -*/ -void Con_Clear_f (void) -{ - con_lines_count = 0; -} - - /* ================ Con_ClearNotify - -Clear all notify lines. ================ */ void Con_ClearNotify (void) { int i; - for(i = 0; i < con_lines_count; ++i) + for(i = 0; i < CON_LINES_COUNT; ++i) CON_LINES(i).mask |= CON_MASK_HIDENOTIFY; } @@ -431,7 +609,9 @@ Con_MessageMode_f void Con_MessageMode_f (void) { key_dest = key_message; - chat_team = false; + chat_mode = 0; // "say" + chat_bufferlen = 0; + chat_buffer[0] = 0; } @@ -443,15 +623,30 @@ Con_MessageMode2_f void Con_MessageMode2_f (void) { key_dest = key_message; - chat_team = true; + chat_mode = 1; // "say_team" + chat_bufferlen = 0; + chat_buffer[0] = 0; } +/* +================ +Con_CommandMode_f +================ +*/ +void Con_CommandMode_f (void) +{ + key_dest = key_message; + if(Cmd_Argc() > 1) + { + dpsnprintf(chat_buffer, sizeof(chat_buffer), "%s ", Cmd_Args()); + chat_bufferlen = strlen(chat_buffer); + } + chat_mode = -1; // command +} /* ================ Con_CheckResize - -If the line width has changed, reformat the buffer. ================ */ void Con_CheckResize (void) @@ -463,14 +658,15 @@ void Con_CheckResize (void) if(f != con_textsize.value) Cvar_SetValueQuick(&con_textsize, f); width = (int)floor(vid_conwidth.value / con_textsize.value); - width = bound(1, width, CON_TEXTSIZE/4); + width = bound(1, width, con.textsize/4); + // FIXME uses con in a non abstracted way if (width == con_linewidth) return; con_linewidth = width; - for(i = 0; i < con_lines_count; ++i) + for(i = 0; i < CON_LINES_COUNT; ++i) CON_LINES(i).height = -1; // recalculate when next needed Con_ClearNotify(); @@ -507,7 +703,7 @@ void Con_ConDump_f (void) Con_Printf("condump: unable to write file \"%s\"\n", Cmd_Argv(1)); return; } - for(i = 0; i < con_lines_count; ++i) + for(i = 0; i < CON_LINES_COUNT; ++i) { FS_Write(file, CON_LINES(i).start, CON_LINES(i).len); FS_Write(file, "\n", 1); @@ -515,6 +711,11 @@ void Con_ConDump_f (void) FS_Close(file); } +void Con_Clear_f () +{ + ConBuffer_Clear(&con); +} + /* ================ Con_Init @@ -523,8 +724,7 @@ Con_Init void Con_Init (void) { con_linewidth = 80; - con_lines_first = 0; - con_lines_count = 0; + ConBuffer_Init(&con, CON_TEXTSIZE, CON_MAXLINES, zonemempool); // Allocate a log queue, this will be freed after configs are parsed logq_size = MAX_INPUTLINE; @@ -566,6 +766,7 @@ void Con_Init (void) Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f, "opens or closes the console"); Cmd_AddCommand ("messagemode", Con_MessageMode_f, "input a chat message to say to everyone"); Cmd_AddCommand ("messagemode2", Con_MessageMode2_f, "input a chat message to say to only your team"); + Cmd_AddCommand ("commandmode", Con_CommandMode_f, "input a console command"); Cmd_AddCommand ("clear", Con_Clear_f, "clear console history"); Cmd_AddCommand ("maps", Con_Maps_f, "list information about available maps"); Cmd_AddCommand ("condump", Con_ConDump_f, "output console history to a file (see also log_file)"); @@ -574,134 +775,9 @@ void Con_Init (void) Con_DPrint("Console initialized.\n"); } - -/* -================ -Con_DeleteLine - -Deletes the first line from the console history. -================ -*/ -void Con_DeleteLine() +void Con_Shutdown (void) { - if(con_lines_count == 0) - return; - --con_lines_count; - con_lines_first = CON_LINES_IDX(1); -} - -/* -================ -Con_DeleteLastLine - -Deletes the last line from the console history. -================ -*/ -void Con_DeleteLastLine() -{ - if(con_lines_count == 0) - return; - --con_lines_count; -} - -/* -================ -Con_BytesLeft - -Checks if there is space for a line of the given length, and if yes, returns a -pointer to the start of such a space, and NULL otherwise. -================ -*/ -char *Con_BytesLeft(int len) -{ - if(len > CON_TEXTSIZE) - return NULL; - if(con_lines_count == 0) - return con_text; - else - { - char *firstline_start = con_lines[con_lines_first].start; - char *lastline_onepastend = con_lines[CON_LINES_LAST].start + con_lines[CON_LINES_LAST].len; - // the buffer is cyclic, so we first have two cases... - if(firstline_start < lastline_onepastend) // buffer is contiguous - { - // put at end? - if(len <= con_text + CON_TEXTSIZE - lastline_onepastend) - return lastline_onepastend; - // put at beginning? - else if(len <= firstline_start - con_text) - return con_text; - else - return NULL; - } - else // buffer has a contiguous hole - { - if(len <= firstline_start - lastline_onepastend) - return lastline_onepastend; - else - return NULL; - } - } -} - -/* -================ -Con_FixTimes - -Notifies the console code about the current time -(and shifts back times of other entries when the time -went backwards) -================ -*/ -void Con_FixTimes() -{ - int i; - if(con_lines_count >= 1) - { - double diff = cl.time - (con_lines + CON_LINES_LAST)->addtime; - if(diff < 0) - { - for(i = 0; i < con_lines_count; ++i) - CON_LINES(i).addtime += diff; - } - } -} - -/* -================ -Con_AddLine - -Appends a given string as a new line to the console. -================ -*/ -void Con_AddLine(const char *line, int len, int mask) -{ - char *putpos; - con_lineinfo *p; - - Con_FixTimes(); - - if(len >= CON_TEXTSIZE) - { - // line too large? - // only display end of line. - line += len - CON_TEXTSIZE + 1; - len = CON_TEXTSIZE - 1; - } - while(!(putpos = Con_BytesLeft(len + 1)) || con_lines_count >= CON_MAXLINES) - Con_DeleteLine(); - memcpy(putpos, line, len); - putpos[len] = 0; - ++con_lines_count; - - //fprintf(stderr, "Now have %d lines (%d -> %d).\n", con_lines_count, con_lines_first, CON_LINES_LAST); - - p = con_lines + CON_LINES_LAST; - p->start = putpos; - p->len = len; - p->addtime = cl.time; - p->mask = mask; - p->height = -1; // calculate when needed + ConBuffer_Shutdown(&con); } /* @@ -723,11 +799,14 @@ void Con_PrintToHistory(const char *txt, int mask) static char buf[CON_TEXTSIZE]; static int bufpos = 0; + if(!con.text) // FIXME uses a non-abstracted property of con + return; + for(; *txt; ++txt) { if(cr_pending) { - Con_DeleteLastLine(); + ConBuffer_DeleteLastLine(&con); cr_pending = 0; } switch(*txt) @@ -735,19 +814,19 @@ void Con_PrintToHistory(const char *txt, int mask) case 0: break; case '\r': - Con_AddLine(buf, bufpos, mask); + ConBuffer_AddLine(&con, buf, bufpos, mask); bufpos = 0; cr_pending = 1; break; case '\n': - Con_AddLine(buf, bufpos, mask); + ConBuffer_AddLine(&con, buf, bufpos, mask); bufpos = 0; break; default: buf[bufpos++] = *txt; - if(bufpos >= CON_TEXTSIZE - 1) + if(bufpos >= con.textsize - 1) // FIXME uses a non-abstracted property of con { - Con_AddLine(buf, bufpos, mask); + ConBuffer_AddLine(&con, buf, bufpos, mask); bufpos = 0; } break; @@ -755,7 +834,7 @@ void Con_PrintToHistory(const char *txt, int mask) } } -/* The translation table between the graphical font and plain ASCII --KB */ +/*! The translation table between the graphical font and plain ASCII --KB */ static char qfont_table[256] = { '\0', '#', '#', '#', '#', '.', '#', '#', '#', 9, 10, '#', ' ', 13, '.', '.', @@ -824,11 +903,10 @@ void Con_Rcon_Redirect_Abort() /* ================ Con_Rcon_AddChar - -Adds a character to the rcon buffer ================ */ -void Con_Rcon_AddChar(char c) +/// Adds a character to the rcon buffer. +void Con_Rcon_AddChar(int c) { if(log_dest_buffer_appending) return; @@ -857,11 +935,72 @@ void Con_Rcon_AddChar(char c) --log_dest_buffer_appending; } +/** + * Convert an RGB color to its nearest quake color. + * I'll cheat on this a bit by translating the colors to HSV first, + * S and V decide if it's black or white, otherwise, H will decide the + * actual color. + * @param _r Red (0-255) + * @param _g Green (0-255) + * @param _b Blue (0-255) + * @return A quake color character. + */ +static char Sys_Con_NearestColor(const unsigned char _r, const unsigned char _g, const unsigned char _b) +{ + float r = ((float)_r)/255.0; + float g = ((float)_g)/255.0; + float b = ((float)_b)/255.0; + float min = min(r, min(g, b)); + float max = max(r, max(g, b)); + + int h; ///< Hue angle [0,360] + float s; ///< Saturation [0,1] + float v = max; ///< In HSV v == max [0,1] + + if(max == min) + s = 0; + else + s = 1.0 - (min/max); + + // Saturation threshold. We now say 0.2 is the minimum value for a color! + if(s < 0.2) + { + // If the value is less than half, return a black color code. + // Otherwise return a white one. + if(v < 0.5) + return '0'; + return '7'; + } + + // Let's get the hue angle to define some colors: + if(max == min) + h = 0; + else if(max == r) + h = (int)(60.0 * (g-b)/(max-min))%360; + else if(max == g) + h = (int)(60.0 * (b-r)/(max-min) + 120); + else // if(max == b) redundant check + h = (int)(60.0 * (r-g)/(max-min) + 240); + + if(h < 36) // *red* to orange + return '1'; + else if(h < 80) // orange over *yellow* to evilish-bright-green + return '3'; + else if(h < 150) // evilish-bright-green over *green* to ugly bright blue + return '2'; + else if(h < 200) // ugly bright blue over *bright blue* to darkish blue + return '5'; + else if(h < 270) // darkish blue over *dark blue* to cool purple + return '4'; + else if(h < 330) // cool purple over *purple* to ugly swiny red + return '6'; + else // ugly red to red closes the circly + return '1'; +} + /* ================ Con_Print - -Prints to all appropriate console targets, and adds timestamps ================ */ extern cvar_t timestamps; @@ -951,12 +1090,32 @@ void Con_Print(const char *msg) int lastcolor = 0; const char *in; char *out; + int color; for(in = line, out = printline; *in; ++in) { switch(*in) { case STRING_COLOR_TAG: - switch(in[1]) + if( in[1] == STRING_COLOR_RGB_TAG_CHAR && isxdigit(in[2]) && isxdigit(in[3]) && isxdigit(in[4]) ) + { + char r = tolower(in[2]); + char g = tolower(in[3]); + char b = tolower(in[4]); + // it's a hex digit already, so the else part needs no check --blub + if(isdigit(r)) r -= '0'; + else r -= 87; + if(isdigit(g)) g -= '0'; + else g -= 87; + if(isdigit(b)) b -= '0'; + else b -= 87; + + color = Sys_Con_NearestColor(r * 17, g * 17, b * 17); + in += 3; // 3 only, the switch down there does the fourth + } + else + color = in[1]; + + switch(color) { case STRING_COLOR_TAG: ++in; @@ -1056,6 +1215,16 @@ void Con_Print(const char *msg) case STRING_COLOR_TAG: switch(in[1]) { + case STRING_COLOR_RGB_TAG_CHAR: + if ( isxdigit(in[2]) && isxdigit(in[3]) && isxdigit(in[4]) ) + { + in+=4; + break; + } + *out++ = STRING_COLOR_TAG; + *out++ = STRING_COLOR_RGB_TAG_CHAR; + ++in; + break; case STRING_COLOR_TAG: ++in; *out++ = STRING_COLOR_TAG; @@ -1096,8 +1265,6 @@ void Con_Print(const char *msg) /* ================ Con_Printf - -Prints to all appropriate console targets ================ */ void Con_Printf(const char *fmt, ...) @@ -1115,8 +1282,6 @@ void Con_Printf(const char *fmt, ...) /* ================ Con_DPrint - -A Con_Print that only shows up if the "developer" cvar is set ================ */ void Con_DPrint(const char *msg) @@ -1129,8 +1294,6 @@ void Con_DPrint(const char *msg) /* ================ Con_DPrintf - -A Con_Printf that only shows up if the "developer" cvar is set ================ */ void Con_DPrintf(const char *fmt, ...) @@ -1176,7 +1339,7 @@ void Con_DrawInput (void) if (!key_consoleactive) return; // don't draw anything - strlcpy(editlinecopy, key_lines[edit_line], sizeof(editlinecopy)); + strlcpy(editlinecopy, key_line, sizeof(editlinecopy)); text = editlinecopy; // Advanced Console Editing by Radix radix@planetquake.com @@ -1204,7 +1367,7 @@ void Con_DrawInput (void) DrawQ_String_Font(x, con_vislines - con_textsize.value*2, text, 0, con_textsize.value, con_textsize.value, 1.0, 1.0, 1.0, 1.0, 0, NULL, false, FONT_CONSOLE ); // remove cursor -// key_lines[edit_line][key_linepos] = 0; +// key_line[key_linepos] = 0; } typedef struct @@ -1263,9 +1426,9 @@ int Con_DisplayLineFunc(void *passthrough, const char *line, size_t length, floa (void) 0; else { - int x = ti->x + (ti->width - width) * ti->alignment; + int x = (int) (ti->x + (ti->width - width) * ti->alignment); if(isContinuation && *ti->continuationString) - x += DrawQ_String_Font(x, ti->y, ti->continuationString, strlen(ti->continuationString), ti->fontsize, ti->fontsize, 1.0, 1.0, 1.0, 1.0, 0, NULL, false, ti->font); + x += (int) DrawQ_String_Font(x, ti->y, ti->continuationString, strlen(ti->continuationString), ti->fontsize, ti->fontsize, 1.0, 1.0, 1.0, 1.0, 0, NULL, false, ti->font); if(length > 0) DrawQ_String_Font(x, ti->y, line, length, ti->fontsize, ti->fontsize, 1.0, 1.0, 1.0, 1.0, 0, &(ti->colorindex), false, ti->font); } @@ -1274,7 +1437,6 @@ int Con_DisplayLineFunc(void *passthrough, const char *line, size_t length, floa return 1; } - int Con_DrawNotifyRect(int mask_must, int mask_mustnot, float maxage, float x, float y, float width, float height, float fontsize, float alignment_x, float alignment_y, const char *continuationString) { int i; @@ -1298,13 +1460,13 @@ int Con_DrawNotifyRect(int mask_must, int mask_mustnot, float maxage, float x, f l = 0; Con_WordWidthFunc(&ti, NULL, &l, -1); l = strlen(continuationString); - continuationWidth = Con_WordWidthFunc(&ti, continuationString, &l, -1); + continuationWidth = (int) Con_WordWidthFunc(&ti, continuationString, &l, -1); // first find the first line to draw by backwards iterating and word wrapping to find their length... - startidx = con_lines_count; - for(i = con_lines_count - 1; i >= 0; --i) + startidx = CON_LINES_COUNT; + for(i = CON_LINES_COUNT - 1; i >= 0; --i) { - con_lineinfo *l = &CON_LINES(i); + con_lineinfo_t *l = &CON_LINES(i); int mylines; if((l->mask & mask_must) != mask_must) @@ -1333,9 +1495,9 @@ int Con_DrawNotifyRect(int mask_must, int mask_mustnot, float maxage, float x, f ti.y = y + alignment_y * (height - lines * fontsize) - nskip * fontsize; // then actually draw - for(i = startidx; i < con_lines_count; ++i) + for(i = startidx; i < CON_LINES_COUNT; ++i) { - con_lineinfo *l = &CON_LINES(i); + con_lineinfo_t *l = &CON_LINES(i); if((l->mask & mask_must) != mask_must) continue; @@ -1366,7 +1528,7 @@ void Con_DrawNotify (void) int numChatlines; int chatpos; - Con_FixTimes(); + ConBuffer_FixTimes(&con); numChatlines = con_chat.integer; chatpos = con_chatpos.integer; @@ -1414,13 +1576,13 @@ void Con_DrawNotify (void) chatstart = 0; // shut off gcc warning } - v = notifystart + con_notifysize.value * Con_DrawNotifyRect(0, CON_MASK_HIDENOTIFY | (numChatlines ? CON_MASK_CHAT : 0), con_notifytime.value, 0, notifystart, vid_conwidth.value, con_notify.value * con_notifysize.value, con_notifysize.value, align, 0.0, ""); + v = notifystart + con_notifysize.value * Con_DrawNotifyRect(0, CON_MASK_INPUT | CON_MASK_HIDENOTIFY | (numChatlines ? CON_MASK_CHAT : 0), con_notifytime.value, 0, notifystart, vid_conwidth.value, con_notify.value * con_notifysize.value, con_notifysize.value, align, 0.0, ""); // chat? if(numChatlines) { v = chatstart + numChatlines * con_chatsize.value; - Con_DrawNotifyRect(CON_MASK_CHAT, 0, con_chattime.value, 0, chatstart, vid_conwidth.value * con_chatwidth.value, v - chatstart, con_chatsize.value, 0.0, 1.0, "^3\014\014\014 "); // 015 is ·> character in conchars.tga + Con_DrawNotifyRect(CON_MASK_CHAT, CON_MASK_INPUT, con_chattime.value, 0, chatstart, vid_conwidth.value * con_chatwidth.value, v - chatstart, con_chatsize.value, 0.0, 1.0, "^3\014\014\014 "); // 015 is ·> character in conchars.tga } if (key_dest == key_message) @@ -1428,7 +1590,9 @@ void Con_DrawNotify (void) int colorindex = -1; // LordHavoc: speedup, and other improvements - if (chat_team) + if (chat_mode < 0) + dpsnprintf(temptext, sizeof(temptext), "]%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1)); + else if(chat_mode) dpsnprintf(temptext, sizeof(temptext), "say_team:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1)); else dpsnprintf(temptext, sizeof(temptext), "say:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1)); @@ -1453,10 +1617,15 @@ int Con_MeasureConsoleLine(int lineno) { float width = vid_conwidth.value; con_text_info_t ti; + con_lineinfo_t *li = &CON_LINES(lineno); + + //if(con.lines[lineno].mask & CON_MASK_LOADEDHISTORY) + // return 0; + ti.fontsize = con_textsize.value; ti.font = FONT_CONSOLE; - return COM_Wordwrap(con_lines[lineno].start, con_lines[lineno].len, 0, width, Con_WordWidthFunc, &ti, Con_CountLineFunc, NULL); + return COM_Wordwrap(li->start, li->len, 0, width, Con_WordWidthFunc, &ti, Con_CountLineFunc, NULL); } /* @@ -1468,10 +1637,11 @@ Returns the height of a given console line; calculates it if necessary. */ int Con_LineHeight(int i) { - int h = con_lines[i].height; + con_lineinfo_t *li = &CON_LINES(i); + int h = li->height; if(h != -1) return h; - return con_lines[i].height = Con_MeasureConsoleLine(i); + return li->height = Con_MeasureConsoleLine(i); } /* @@ -1486,8 +1656,12 @@ returned. int Con_DrawConsoleLine(float y, int lineno, float ymin, float ymax) { float width = vid_conwidth.value; - con_text_info_t ti; + con_lineinfo_t *li = &CON_LINES(lineno); + + //if(con.lines[lineno].mask & CON_MASK_LOADEDHISTORY) + // return 0; + ti.continuationString = ""; ti.alignment = 0; ti.fontsize = con_textsize.value; @@ -1498,7 +1672,7 @@ int Con_DrawConsoleLine(float y, int lineno, float ymin, float ymax) ti.ymax = ymax; ti.width = width; - return COM_Wordwrap(con_lines[lineno].start, con_lines[lineno].len, 0, width, Con_WordWidthFunc, &ti, Con_DisplayLineFunc, &ti); + return COM_Wordwrap(li->start, li->len, 0, width, Con_WordWidthFunc, &ti, Con_DisplayLineFunc, &ti); } /* @@ -1512,15 +1686,14 @@ con_backscroll. void Con_LastVisibleLine(int *last, int *limitlast) { int lines_seen = 0; - int ic; + int i; if(con_backscroll < 0) con_backscroll = 0; // now count until we saw con_backscroll actual lines - for(ic = 0; ic < con_lines_count; ++ic) + for(i = CON_LINES_COUNT - 1; i >= 0; --i) { - int i = CON_LINES_IDX(con_lines_count - 1 - ic); int h = Con_LineHeight(i); // line is the last visible line? @@ -1537,7 +1710,8 @@ void Con_LastVisibleLine(int *last, int *limitlast) // if we get here, no line was on screen - scroll so that one line is // visible then. con_backscroll = lines_seen - 1; - *last = con_lines_first; + *last = con.lines_first; + // FIXME uses con in a non abstracted way *limitlast = 1; } @@ -1564,25 +1738,26 @@ void Con_DrawConsole (int lines) DrawQ_String_Font(vid_conwidth.integer - DrawQ_TextWidth_Font(engineversion, 0, false, FONT_CONSOLE) * con_textsize.value, lines - con_textsize.value, engineversion, 0, con_textsize.value, con_textsize.value, 1, 0, 0, 1, 0, NULL, true, FONT_CONSOLE); // draw the text - if(con_lines_count > 0) + if(CON_LINES_COUNT > 0) { float ymax = con_vislines - 2 * con_textsize.value; Con_LastVisibleLine(&last, &limitlast); y = ymax - con_textsize.value; if(limitlast) - y += (con_lines[last].height - limitlast) * con_textsize.value; + y += (CON_LINES(last).height - limitlast) * con_textsize.value; + // FIXME uses con in a non abstracted way i = last; for(;;) { y -= Con_DrawConsoleLine(y, i, 0, ymax) * con_textsize.value; - if(i == con_lines_first) + if(i == 0) break; // top of console buffer if(y < 0) break; // top of console window limitlast = 0; - i = CON_LINES_PRED(i); + --i; } } @@ -1693,8 +1868,8 @@ qboolean GetMapList (const char *s, char *completedname, int completednamebuffer if (com_token[0] == '}') break; // skip leading whitespace - for (k = 0;com_token[k] && com_token[k] <= ' ';k++); - for (l = 0;l < (int)sizeof(keyname) - 1 && com_token[k+l] && com_token[k+l] > ' ';l++) + for (k = 0;com_token[k] && ISWHITESPACE(com_token[k]);k++); + for (l = 0;l < (int)sizeof(keyname) - 1 && com_token[k+l] && !ISWHITESPACE(com_token[k+l]);l++) keyname[l] = com_token[k+l]; keyname[l] = 0; if (!COM_ParseToken_Simple(&data, false, false)) @@ -1786,11 +1961,10 @@ void Con_DisplayList(const char **list) Con_Print("\n\n"); } -/* Nicks_CompleteCountPossible - - Count the number of possible nicks to complete - */ -//qboolean COM_StringDecolorize(const char *in, size_t size_in, char *out, size_t size_out, qboolean escape_carets); +/* + SanitizeString strips color tags from the string in + and writes the result on string out +*/ void SanitizeString(char *in, char *out) { while(*in) @@ -1803,18 +1977,33 @@ void SanitizeString(char *in, char *out) out[0] = STRING_COLOR_TAG; out[1] = 0; return; - } else if(*in >= '0' && *in <= '9') + } + else if (*in >= '0' && *in <= '9') // ^[0-9] found { ++in; - if(!*in) // end + if(!*in) { *out = 0; return; - } else if (*in == STRING_COLOR_TAG) + } else if (*in == STRING_COLOR_TAG) // ^[0-9]^ found, don't print ^[0-9] continue; - } else if (*in != STRING_COLOR_TAG) { - --in; } + else if (*in == STRING_COLOR_RGB_TAG_CHAR) // ^x found + { + if ( isxdigit(in[1]) && isxdigit(in[2]) && isxdigit(in[3]) ) + { + in+=4; + if (!*in) + { + *out = 0; + return; + } else if (*in == STRING_COLOR_TAG) // ^xrgb^ found, don't print ^xrgb + continue; + } + else in--; + } + else if (*in != STRING_COLOR_TAG) + --in; } *out = qfont_table[*(unsigned char*)in]; ++in; @@ -1903,6 +2092,11 @@ int Nicks_strncasecmp(char *a, char *b, unsigned int a_len) return 0; } + +/* Nicks_CompleteCountPossible + + Count the number of possible nicks to complete + */ int Nicks_CompleteCountPossible(char *line, int pos, char *s, qboolean isCon) { char name[128]; @@ -1926,7 +2120,7 @@ int Nicks_CompleteCountPossible(char *line, int pos, char *s, qboolean isCon) continue; SanitizeString(cl.scores[p].name, name); - //Con_Printf("Sanitized: %s^7 -> %s", cl.scores[p].name, name); + //Con_Printf(" ^2Sanitized: ^7%s -> %s", cl.scores[p].name, name); if(!name[0]) continue; @@ -1935,7 +2129,7 @@ int Nicks_CompleteCountPossible(char *line, int pos, char *s, qboolean isCon) match = -1; spos = pos - 1; // no need for a minimum of characters :) - while(spos >= 0 && (spos - pos) < length) // search-string-length < name length + while(spos >= 0) { if(spos > 0 && line[spos-1] != ' ' && line[spos-1] != ';' && line[spos-1] != '\"' && line[spos-1] != '\'') { @@ -2158,11 +2352,16 @@ const char **Nicks_CompleteBuildList(int count) return buf; } +/* + Nicks_AddLastColor + Restores the previous used color, after the autocompleted name. +*/ int Nicks_AddLastColor(char *buffer, int pos) { qboolean quote_added = false; int match; - char color = '7'; + int color = STRING_COLOR_DEFAULT + '0'; + char r = 0, g = 0, b = 0; if(con_nickcompletion_flags.integer & NICKS_ADD_QUOTE && buffer[Nicks_matchpos-1] == '\"') { @@ -2177,16 +2376,44 @@ int Nicks_AddLastColor(char *buffer, int pos) // find last color for(match = Nicks_matchpos-1; match >= 0; --match) { - if(buffer[match] == STRING_COLOR_TAG && buffer[match+1] >= '0' && buffer[match+1] <= '9') + if(buffer[match] == STRING_COLOR_TAG) { - color = buffer[match+1]; - break; + if( isdigit(buffer[match+1]) ) + { + color = buffer[match+1]; + break; + } + else if(buffer[match+1] == STRING_COLOR_RGB_TAG_CHAR) + { + if ( isxdigit(buffer[match+2]) && isxdigit(buffer[match+3]) && isxdigit(buffer[match+4]) ) + { + r = buffer[match+2]; + g = buffer[match+3]; + b = buffer[match+4]; + color = -1; + break; + } + } } } - if(!quote_added && buffer[pos-2] == STRING_COLOR_TAG && buffer[pos-1] >= '0' && buffer[pos-1] <= '9') // when thes use &4 - pos -= 2; + if(!quote_added) + { + if( pos >= 2 && buffer[pos-2] == STRING_COLOR_TAG && isdigit(buffer[pos-1]) ) // when thes use &4 + pos -= 2; + else if( pos >= 5 && buffer[pos-5] == STRING_COLOR_TAG && buffer[pos-4] == STRING_COLOR_RGB_TAG_CHAR + && isxdigit(buffer[pos-3]) && isxdigit(buffer[pos-2]) && isxdigit(buffer[pos-1]) ) + pos -= 5; + } buffer[pos++] = STRING_COLOR_TAG; - buffer[pos++] = color; + if (color == -1) + { + buffer[pos++] = STRING_COLOR_RGB_TAG_CHAR; + buffer[pos++] = r; + buffer[pos++] = g; + buffer[pos++] = b; + } + else + buffer[pos++] = color; } return pos; } @@ -2205,7 +2432,7 @@ int Nicks_CompleteChatLine(char *buffer, size_t size, unsigned int pos) msg = Nicks_list[0]; len = min(size - Nicks_matchpos - 3, strlen(msg)); memcpy(&buffer[Nicks_matchpos], msg, len); - if( len < (size - 4) ) // space for color and space and \0 + if( len < (size - 7) ) // space for color (^[0-9] or ^xrgb) and space and \0 len = Nicks_AddLastColor(buffer, Nicks_matchpos+len); buffer[len++] = ' '; buffer[len] = 0; @@ -2214,7 +2441,7 @@ int Nicks_CompleteChatLine(char *buffer, size_t size, unsigned int pos) { int len; char *msg; - Con_Printf("\n%i possible nick%s\n", n, (n > 1) ? "s: " : ":"); + Con_Printf("\n%i possible nicks:\n", n); Cmd_CompleteNicksPrint(n); Nicks_CutMatches(n); @@ -2255,20 +2482,20 @@ void Con_CompleteCommandLine (void) pos = key_linepos; while(--pos) { - k = key_lines[edit_line][pos]; + k = key_line[pos]; if(k == '\"' || k == ';' || k == ' ' || k == '\'') break; } pos++; - s = key_lines[edit_line] + pos; - strlcpy(s2, key_lines[edit_line] + key_linepos, sizeof(s2)); //save chars after cursor - key_lines[edit_line][key_linepos] = 0; //hide them + s = key_line + pos; + strlcpy(s2, key_line + key_linepos, sizeof(s2)); //save chars after cursor + key_line[key_linepos] = 0; //hide them - space = strchr(key_lines[edit_line] + 1, ' '); - if(space && pos == (space - key_lines[edit_line]) + 1) + space = strchr(key_line + 1, ' '); + if(space && pos == (space - key_line) + 1) { - strlcpy(command, key_lines[edit_line] + 1, min(sizeof(command), (unsigned int)(space - key_lines[edit_line]))); + strlcpy(command, key_line + 1, min(sizeof(command), (unsigned int)(space - key_line))); patterns = Cvar_VariableString(va("con_completion_%s", command)); // TODO maybe use a better place for this? if(patterns && !*patterns) @@ -2285,12 +2512,12 @@ void Con_CompleteCommandLine (void) // and now do the actual work *s = 0; - strlcat(key_lines[edit_line], t, MAX_INPUTLINE); - strlcat(key_lines[edit_line], s2, MAX_INPUTLINE); //add back chars after cursor + strlcat(key_line, t, MAX_INPUTLINE); + strlcat(key_line, s2, MAX_INPUTLINE); //add back chars after cursor // and fix the cursor - if(key_linepos > (int) strlen(key_lines[edit_line])) - key_linepos = (int) strlen(key_lines[edit_line]); + if(key_linepos > (int) strlen(key_line)) + key_linepos = (int) strlen(key_line); } return; } @@ -2425,12 +2652,12 @@ void Con_CompleteCommandLine (void) // and now do the actual work *s = 0; - strlcat(key_lines[edit_line], t, MAX_INPUTLINE); - strlcat(key_lines[edit_line], s2, MAX_INPUTLINE); //add back chars after cursor + strlcat(key_line, t, MAX_INPUTLINE); + strlcat(key_line, s2, MAX_INPUTLINE); //add back chars after cursor // and fix the cursor - if(key_linepos > (int) strlen(key_lines[edit_line])) - key_linepos = (int) strlen(key_lines[edit_line]); + if(key_linepos > (int) strlen(key_line)) + key_linepos = (int) strlen(key_line); } stringlistfreecontents(&resultbuf); stringlistfreecontents(&dirbuf); @@ -2459,7 +2686,7 @@ void Con_CompleteCommandLine (void) Con_Printf("\n%i possible aliases%s\n", a, (a > 1) ? "s: " : ":"); Cmd_CompleteAliasPrint(s); } - n = Nicks_CompleteCountPossible(key_lines[edit_line], key_linepos, s, true); + n = Nicks_CompleteCountPossible(key_line, key_linepos, s, true); if (n) { Con_Printf("\n%i possible nick%s\n", n, (n > 1) ? "s: " : ":"); @@ -2469,7 +2696,7 @@ void Con_CompleteCommandLine (void) if (!(c + v + a + n)) // No possible matches { if(s2[0]) - strlcpy(&key_lines[edit_line][key_linepos], s2, sizeof(key_lines[edit_line]) - key_linepos); + strlcpy(&key_line[key_linepos], s2, sizeof(key_line) - key_linepos); return; } @@ -2501,33 +2728,33 @@ void Con_CompleteCommandLine (void) done: // prevent a buffer overrun by limiting cmd_len according to remaining space - cmd_len = min(cmd_len, (int)sizeof(key_lines[edit_line]) - 1 - pos); + cmd_len = min(cmd_len, (int)sizeof(key_line) - 1 - pos); if (cmd) { key_linepos = pos; - memcpy(&key_lines[edit_line][key_linepos], cmd, cmd_len); + memcpy(&key_line[key_linepos], cmd, cmd_len); key_linepos += cmd_len; // if there is only one match, add a space after it - if (c + v + a + n == 1 && key_linepos < (int)sizeof(key_lines[edit_line]) - 1) + if (c + v + a + n == 1 && key_linepos < (int)sizeof(key_line) - 1) { if(n) { // was a nick, might have an offset, and needs colors ;) --blub key_linepos = pos - Nicks_offset[0]; cmd_len = strlen(Nicks_list[0]); - cmd_len = min(cmd_len, (int)sizeof(key_lines[edit_line]) - 3 - pos); + cmd_len = min(cmd_len, (int)sizeof(key_line) - 3 - pos); - memcpy(&key_lines[edit_line][key_linepos] , Nicks_list[0], cmd_len); + memcpy(&key_line[key_linepos] , Nicks_list[0], cmd_len); key_linepos += cmd_len; - if(key_linepos < (int)(sizeof(key_lines[edit_line])-4)) // space for ^, X and space and \0 - key_linepos = Nicks_AddLastColor(key_lines[edit_line], key_linepos); + if(key_linepos < (int)(sizeof(key_line)-4)) // space for ^, X and space and \0 + key_linepos = Nicks_AddLastColor(key_line, key_linepos); } - key_lines[edit_line][key_linepos++] = ' '; + key_line[key_linepos++] = ' '; } } // use strlcat to avoid a buffer overrun - key_lines[edit_line][key_linepos] = 0; - strlcat(key_lines[edit_line], s2, sizeof(key_lines[edit_line])); + key_line[key_linepos] = 0; + strlcat(key_line, s2, sizeof(key_line)); // free the command, cvar, and alias lists for (i = 0; i < 4; i++)