]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - console.c
WIN32: changed stricmp and strnicmp to have an underscore prefix
[xonotic/darkplaces.git] / console.c
index dad21399faad4360cf23d39a90e4c417d354a0b9..d7e614a120c221380fd737cc8f314a9cfd2501f8 100644 (file)
--- a/console.c
+++ b/console.c
@@ -43,7 +43,15 @@ char con_text[CON_TEXTSIZE];
 
 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 (0-32)"};
-cvar_t con_textsize = {CVAR_SAVE, "con_textsize","8", "console text size in virtual 2D pixels"};       //[515]: console text size in pixels
+cvar_t con_textsize = {CVAR_SAVE, "con_textsize","8", "console text size in virtual 2D pixels"};
+
+
+cvar_t sys_specialcharactertranslation = {0, "sys_specialcharactertranslation", "1", "terminal console conchars to ASCII translation (set to 0 if your conchars.tga is for an 8bit character set or if you want raw output)"};
+#ifdef WIN32
+cvar_t sys_colortranslation = {0, "sys_colortranslation", "0", "terminal console color translation (supported values: 0 = strip color codes, 1 = translate to ANSI codes, 2 = no translation)"};
+#else
+cvar_t sys_colortranslation = {0, "sys_colortranslation", "1", "terminal console color translation (supported values: 0 = strip color codes, 1 = translate to ANSI codes, 2 = no translation)"};
+#endif
 
 #define MAX_NOTIFYLINES 32
 // cl.time time the line was generated for transparent notify lines
@@ -68,6 +76,10 @@ 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;
 char crt_log_file [MAX_OSPATH] = "";
 qfile_t* logfile = NULL;
 
@@ -77,6 +89,56 @@ size_t logq_size = 0;
 
 void Log_ConPrint (const char *msg);
 
+/*
+====================
+Log_DestBuffer_Init
+====================
+*/
+static void Log_DestBuffer_Init()
+{
+       memcpy(log_dest_buffer, "\377\377\377\377n", 5); // QW rcon print
+       log_dest_buffer_pos = 5;
+}
+
+/*
+====================
+Log_DestBuffer_Flush
+====================
+*/
+void Log_DestBuffer_Flush()
+{
+       lhnetaddress_t log_dest_addr;
+       lhnetsocket_t *log_dest_socket;
+       const char *s = log_dest_udp.string;
+       qboolean have_opened_temp_sockets = false;
+       if(s) if(log_dest_buffer_pos > 5)
+       {
+               ++log_dest_buffer_appending;
+               log_dest_buffer[log_dest_buffer_pos++] = 0;
+
+               if(!NetConn_HaveServerPorts() && !NetConn_HaveClientPorts()) // then temporarily open one
+               {
+                       have_opened_temp_sockets = true;
+                       NetConn_OpenServerPorts(true);
+               }
+
+               while(COM_ParseToken_Console(&s))
+                       if(LHNETADDRESS_FromString(&log_dest_addr, com_token, 26000))
+                       {
+                               log_dest_socket = NetConn_ChooseClientSocketForAddress(&log_dest_addr);
+                               if(!log_dest_socket)
+                                       log_dest_socket = NetConn_ChooseServerSocketForAddress(&log_dest_addr);
+                               if(log_dest_socket)
+                                       NetConn_WriteString(log_dest_socket, log_dest_buffer, &log_dest_addr);
+                       }
+
+               if(have_opened_temp_sockets)
+                       NetConn_CloseServerPorts();
+               --log_dest_buffer_appending;
+       }
+       log_dest_buffer_pos = 0;
+}
+
 /*
 ====================
 Log_Timestamp
@@ -148,6 +210,8 @@ Log_Start
 */
 void Log_Start (void)
 {
+       size_t pos;
+       size_t n;
        Log_Open ();
 
        // Dump the contents of the log queue into the log file and free it
@@ -155,8 +219,24 @@ void Log_Start (void)
        {
                unsigned char *temp = logqueue;
                logqueue = NULL;
-               if (logfile != NULL && logq_ind != 0)
-                       FS_Write (logfile, temp, logq_ind);
+               if(logq_ind != 0)
+               {
+                       if (logfile != NULL)
+                               FS_Write (logfile, temp, logq_ind);
+                       if(*log_dest_udp.string)
+                       {
+                               for(pos = 0; pos < logq_ind; )
+                               {
+                                       if(log_dest_buffer_pos == 0)
+                                               Log_DestBuffer_Init();
+                                       n = min(sizeof(log_dest_buffer) - log_dest_buffer_pos - 1, logq_ind - pos);
+                                       memcpy(log_dest_buffer + log_dest_buffer_pos, temp + pos, n);
+                                       log_dest_buffer_pos += n;
+                                       Log_DestBuffer_Flush();
+                                       pos += n;
+                               }
+                       }
+               }
                Mem_Free (temp);
                logq_ind = 0;
                logq_size = 0;
@@ -215,6 +295,7 @@ void Log_ConPrint (const char *msg)
        // If a log file is available
        if (logfile != NULL)
                FS_Print (logfile, msg);
+
        inprogress = false;
 }
 
@@ -382,6 +463,47 @@ static void Con_Maps_f (void)
                GetMapList("", NULL, 0);
 }
 
+void Con_ConDump_f (void)
+{
+       int i, l;
+       qboolean allblankssofar;
+       const char *text;
+       qfile_t *file;
+       char temp[MAX_INPUTLINE+2];
+       if (Cmd_Argc() != 2)
+       {
+               Con_Printf("usage: condump <filename>\n");
+               return;
+       }
+       file = FS_Open(Cmd_Argv(1), "wb", false, false);
+       if (!file)
+       {
+               Con_Printf("condump: unable to write file \"%s\"\n", Cmd_Argv(1));
+               return;
+       }
+       // iterate over the entire console history buffer line by line
+       allblankssofar = true;
+       for (i = 0;i < con_totallines;i++)
+       {
+               text = con_text + ((con_current + 1 + i) % con_totallines)*con_linewidth;
+               // count the used characters on this line
+               for (l = min(con_linewidth, (int)sizeof(temp));l > 0 && text[l-1] == ' ';l--);
+               // if not a blank line, begin output
+               if (l)
+                       allblankssofar = false;
+               // output the current line to the file
+               if (!allblankssofar)
+               {
+                       if (l)
+                               memcpy(temp, text, l);
+                       temp[l] = '\n';
+                       temp[l+1] = 0;
+                       FS_Print(file, temp);
+               }
+       }
+       FS_Close(file);
+}
+
 /*
 ================
 Con_Init
@@ -398,16 +520,17 @@ void Con_Init (void)
        logqueue = (unsigned char *)Mem_Alloc (tempmempool, logq_size);
        logq_ind = 0;
 
+       Cvar_RegisterVariable (&sys_colortranslation);
+       Cvar_RegisterVariable (&sys_specialcharactertranslation);
+
        Cvar_RegisterVariable (&log_file);
+       Cvar_RegisterVariable (&log_dest_udp);
 
        // support for the classic Quake option
 // COMMANDLINEOPTION: Console: -condebug logs console messages to qconsole.log, see also log_file
        if (COM_CheckParm ("-condebug") != 0)
                Cvar_SetQuick (&log_file, "qconsole.log");
-}
 
-void Con_Init_Commands (void)
-{
        // register our cvars
        Cvar_RegisterVariable (&con_notifytime);
        Cvar_RegisterVariable (&con_notify);
@@ -418,7 +541,8 @@ void Con_Init_Commands (void)
        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 ("clear", Con_Clear_f, "clear console history");
-       Cmd_AddCommand ("maps", Con_Maps_f, "list information about available maps");   // By [515]
+       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)");
 
        con_initialized = true;
        Con_Print("Console initialized.\n");
@@ -549,6 +673,38 @@ static char qfont_table[256] = {
        'x',  'y',  'z',  '{',  '|',  '}',  '~',  '<'
 };
 
+/*
+================
+Con_Rcon_AddChar
+
+Adds a character to the rcon buffer
+================
+*/
+void Con_Rcon_AddChar(char c)
+{
+       if(log_dest_buffer_appending)
+               return;
+       ++log_dest_buffer_appending;
+
+       // if this print is in response to an rcon command, add the character
+       // to the rcon redirect buffer
+
+       if (rcon_redirect && rcon_redirect_bufferpos < (int)sizeof(rcon_redirect_buffer) - 1)
+               rcon_redirect_buffer[rcon_redirect_bufferpos++] = c;
+       else if(*log_dest_udp.string) // don't duplicate rcon command responses here, these are sent another way
+       {
+               if(log_dest_buffer_pos == 0)
+                       Log_DestBuffer_Init();
+               log_dest_buffer[log_dest_buffer_pos++] = c;
+               if(log_dest_buffer_pos >= sizeof(log_dest_buffer) - 1) // minus one, to allow for terminating zero
+                       Log_DestBuffer_Flush();
+       }
+       else
+               log_dest_buffer_pos = 0;
+
+       --log_dest_buffer_appending;
+}
+
 /*
 ================
 Con_Print
@@ -561,16 +717,13 @@ extern cvar_t timeformat;
 extern qboolean sys_nostdout;
 void Con_Print(const char *msg)
 {
-       int mask = 0;
+       static int mask = 0;
        static int index = 0;
        static char line[MAX_INPUTLINE];
 
        for (;*msg;msg++)
        {
-               // if this print is in response to an rcon command, add the character
-               // to the rcon redirect buffer
-               if (rcon_redirect && rcon_redirect_bufferpos < (int)sizeof(rcon_redirect_buffer) - 1)
-                       rcon_redirect_buffer[rcon_redirect_bufferpos++] = *msg;
+               Con_Rcon_AddChar(*msg);
                // if this is the beginning of a new line, print timestamp
                if (index == 0)
                {
@@ -586,10 +739,16 @@ void Con_Print(const char *msg)
                        {
                                // play talk wav
                                if (*msg == 1)
-                                       S_LocalSound ("sound/misc/talk.wav");
+                               {
+                                       if (msg[1] == '(' && cl.foundtalk2wav)
+                                               S_LocalSound ("sound/misc/talk2.wav");
+                                       else
+                                               S_LocalSound ("sound/misc/talk.wav");
+                               }
                                line[index++] = STRING_COLOR_TAG;
                                line[index++] = '3';
                                msg++;
+                               Con_Rcon_AddChar(*msg);
                        }
                        // store timestamp
                        for (;*timestamp;index++, timestamp++)
@@ -612,9 +771,154 @@ void Con_Print(const char *msg)
                        if (!sys_nostdout)
                        {
                                unsigned char *p;
-                               for (p = (unsigned char *) line;*p; p++)
-                                       *p = qfont_table[*p];
-                               Sys_PrintToTerminal(line);
+                               if(sys_specialcharactertranslation.integer)
+                               {
+                                       for (p = (unsigned char *) line;*p; p++)
+                                               *p = qfont_table[*p];
+                               }
+
+                               if(sys_colortranslation.integer == 1) // ANSI
+                               {
+                                       static char printline[MAX_INPUTLINE * 4 + 3];
+                                               // 2 can become 7 bytes, rounding that up to 8, and 3 bytes are added at the end
+                                               // a newline can transform into four bytes, but then prevents the three extra bytes from appearing
+                                       int lastcolor = 0;
+                                       const char *in;
+                                       char *out;
+                                       for(in = line, out = printline; *in; ++in)
+                                       {
+                                               switch(*in)
+                                               {
+                                                       case STRING_COLOR_TAG:
+                                                               switch(in[1])
+                                                               {
+                                                                       case STRING_COLOR_TAG:
+                                                                               ++in;
+                                                                               *out++ = STRING_COLOR_TAG;
+                                                                               break;
+                                                                       case '0':
+                                                                       case '7':
+                                                                               // normal color
+                                                                               ++in;
+                                                                               if(lastcolor == 0) break; else lastcolor = 0;
+                                                                               *out++ = 0x1B; *out++ = '['; *out++ = 'm';
+                                                                               break;
+                                                                       case '1':
+                                                                               // light red
+                                                                               ++in;
+                                                                               if(lastcolor == 1) break; else lastcolor = 1;
+                                                                               *out++ = 0x1B; *out++ = '['; *out++ = '1'; *out++ = ';'; *out++ = '3'; *out++ = '1'; *out++ = 'm';
+                                                                               break;
+                                                                       case '2':
+                                                                               // light green
+                                                                               ++in;
+                                                                               if(lastcolor == 2) break; else lastcolor = 2;
+                                                                               *out++ = 0x1B; *out++ = '['; *out++ = '1'; *out++ = ';'; *out++ = '3'; *out++ = '2'; *out++ = 'm';
+                                                                               break;
+                                                                       case '3':
+                                                                               // yellow
+                                                                               ++in;
+                                                                               if(lastcolor == 3) break; else lastcolor = 3;
+                                                                               *out++ = 0x1B; *out++ = '['; *out++ = '1'; *out++ = ';'; *out++ = '3'; *out++ = '3'; *out++ = 'm';
+                                                                               break;
+                                                                       case '4':
+                                                                               // light blue
+                                                                               ++in;
+                                                                               if(lastcolor == 4) break; else lastcolor = 4;
+                                                                               *out++ = 0x1B; *out++ = '['; *out++ = '1'; *out++ = ';'; *out++ = '3'; *out++ = '4'; *out++ = 'm';
+                                                                               break;
+                                                                       case '5':
+                                                                               // light cyan
+                                                                               ++in;
+                                                                               if(lastcolor == 5) break; else lastcolor = 5;
+                                                                               *out++ = 0x1B; *out++ = '['; *out++ = '1'; *out++ = ';'; *out++ = '3'; *out++ = '6'; *out++ = 'm';
+                                                                               break;
+                                                                       case '6':
+                                                                               // light magenta
+                                                                               ++in;
+                                                                               if(lastcolor == 6) break; else lastcolor = 6;
+                                                                               *out++ = 0x1B; *out++ = '['; *out++ = '1'; *out++ = ';'; *out++ = '3'; *out++ = '5'; *out++ = 'm';
+                                                                               break;
+                                                                       // 7 handled above
+                                                                       case '8':
+                                                                       case '9':
+                                                                               // bold normal color
+                                                                               ++in;
+                                                                               if(lastcolor == 8) break; else lastcolor = 8;
+                                                                               *out++ = 0x1B; *out++ = '['; *out++ = '0'; *out++ = ';'; *out++ = '1'; *out++ = 'm';
+                                                                               break;
+                                                                       default:
+                                                                               *out++ = STRING_COLOR_TAG;
+                                                                               break;
+                                                               }
+                                                               break;
+                                                       case '\n':
+                                                               if(lastcolor != 0)
+                                                               {
+                                                                       *out++ = 0x1B; *out++ = '['; *out++ = 'm';
+                                                                       lastcolor = 0;
+                                                               }
+                                                               *out++ = *in;
+                                                               break;
+                                                       default:
+                                                               *out++ = *in;
+                                                               break;
+                                               }
+                                       }
+                                       if(lastcolor != 0)
+                                       {
+                                               *out++ = 0x1B;
+                                               *out++ = '[';
+                                               *out++ = 'm';
+                                       }
+                                       *out++ = 0;
+                                       Sys_PrintToTerminal(printline);
+                               }
+                               else if(sys_colortranslation.integer == 2) // Quake
+                               {
+                                       Sys_PrintToTerminal(line);
+                               }
+                               else // strip
+                               {
+                                       static char printline[MAX_INPUTLINE]; // it can only get shorter here
+                                       const char *in;
+                                       char *out;
+                                       for(in = line, out = printline; *in; ++in)
+                                       {
+                                               switch(*in)
+                                               {
+                                                       case STRING_COLOR_TAG:
+                                                               switch(in[1])
+                                                               {
+                                                                       case STRING_COLOR_TAG:
+                                                                               ++in;
+                                                                               *out++ = STRING_COLOR_TAG;
+                                                                               break;
+                                                                       case '0':
+                                                                       case '1':
+                                                                       case '2':
+                                                                       case '3':
+                                                                       case '4':
+                                                                       case '5':
+                                                                       case '6':
+                                                                       case '7':
+                                                                       case '8':
+                                                                       case '9':
+                                                                               ++in;
+                                                                               break;
+                                                                       default:
+                                                                               *out++ = STRING_COLOR_TAG;
+                                                                               break;
+                                                               }
+                                                               break;
+                                                       default:
+                                                               *out++ = *in;
+                                                               break;
+                                               }
+                                       }
+                                       *out++ = 0;
+                                       Sys_PrintToTerminal(printline);
+                               }
                        }
                        // empty the line buffer
                        index = 0;
@@ -730,7 +1034,7 @@ void Con_DrawInput (void)
                text += 1 + key_linepos - con_linewidth;
 
        // draw it
-       DrawQ_ColoredString(0, con_vislines - con_textsize.value*2, text, con_linewidth, con_textsize.value, con_textsize.value, 1.0, 1.0, 1.0, 1.0, 0, NULL );
+       DrawQ_String(0, con_vislines - con_textsize.value*2, text, con_linewidth, con_textsize.value, con_textsize.value, 1.0, 1.0, 1.0, 1.0, 0, NULL, false );
 
        // remove cursor
 //     key_lines[edit_line][key_linepos] = 0;
@@ -784,7 +1088,7 @@ void Con_DrawNotify (void)
                        // count up to the last non-whitespace, and ignore color codes
                        for (j = 0;j < con_linewidth && text[j];j++)
                        {
-                               if (text[j] == '^' && (text[j+1] >= '0' && text[j+1] <= '9'))
+                               if (text[j] == STRING_COLOR_TAG && (text[j+1] >= '0' && text[j+1] <= '9'))
                                {
                                        j++;
                                        continue;
@@ -799,7 +1103,7 @@ void Con_DrawNotify (void)
                } else
                        x = 0;
 
-               DrawQ_ColoredString( x, v, text, con_linewidth, con_textsize.value, con_textsize.value, 1.0, 1.0, 1.0, 1.0, 0, &colorindex );
+               DrawQ_String( x, v, text, con_linewidth, con_textsize.value, con_textsize.value, 1.0, 1.0, 1.0, 1.0, 0, &colorindex, false );
 
                v += con_textsize.value;
        }
@@ -818,13 +1122,13 @@ void Con_DrawNotify (void)
                        sprintf(temptext, "say:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
                while ((int)strlen(temptext) >= con_linewidth)
                {
-                       DrawQ_ColoredString( 0, v, temptext, con_linewidth, con_textsize.value, con_textsize.value, 1.0, 1.0, 1.0, 1.0, 0, &colorindex );
+                       DrawQ_String( 0, v, temptext, con_linewidth, con_textsize.value, con_textsize.value, 1.0, 1.0, 1.0, 1.0, 0, &colorindex, false );
                        strlcpy(temptext, &temptext[con_linewidth], sizeof(temptext));
                        v += con_textsize.value;
                }
                if (strlen(temptext) > 0)
                {
-                       DrawQ_ColoredString( 0, v, temptext, 0, con_textsize.value, con_textsize.value, 1.0, 1.0, 1.0, 1.0, 0, &colorindex );
+                       DrawQ_String( 0, v, temptext, 0, con_textsize.value, con_textsize.value, 1.0, 1.0, 1.0, 1.0, 0, &colorindex, false );
                        v += con_textsize.value;
                }
        }
@@ -850,7 +1154,7 @@ void Con_DrawConsole (int lines)
 
 // draw the background
        DrawQ_Pic(0, lines - vid_conheight.integer, scr_conbrightness.value >= 0.01f ? Draw_CachePic("gfx/conback", true) : NULL, vid_conwidth.integer, vid_conheight.integer, scr_conbrightness.value, scr_conbrightness.value, scr_conbrightness.value, scr_conalpha.value, 0);
-       DrawQ_String(vid_conwidth.integer - strlen(engineversion) * con_textsize.value - con_textsize.value, lines - con_textsize.value, engineversion, 0, con_textsize.value, con_textsize.value, 1, 0, 0, 1, 0);
+       DrawQ_String(vid_conwidth.integer - strlen(engineversion) * con_textsize.value - con_textsize.value, lines - con_textsize.value, engineversion, 0, con_textsize.value, con_textsize.value, 1, 0, 0, 1, 0, NULL, true);
 
 // draw the text
        con_vislines = lines;
@@ -865,7 +1169,7 @@ void Con_DrawConsole (int lines)
                j = max(i - con_backscroll, 0);
                text = con_text + (j % con_totallines)*con_linewidth;
 
-               DrawQ_ColoredString( 0, y, text, con_linewidth, con_textsize.value, con_textsize.value, 1.0, 1.0, 1.0, 1.0, 0, &colorindex );
+               DrawQ_String( 0, y, text, con_linewidth, con_textsize.value, con_textsize.value, 1.0, 1.0, 1.0, 1.0, 0, &colorindex, false );
        }
 
 // draw the input prompt, user text, and cursor if desired
@@ -978,7 +1282,7 @@ qboolean GetMapList (const char *s, char *completedname, int completednamebuffer
                                for (;;)
                                {
                                        int l;
-                                       if (!COM_ParseTokenConsole(&data))
+                                       if (!COM_ParseToken_Simple(&data, false))
                                                break;
                                        if (com_token[0] == '{')
                                                continue;
@@ -989,7 +1293,7 @@ qboolean GetMapList (const char *s, char *completedname, int completednamebuffer
                                        for (l = 0;l < (int)sizeof(keyname) - 1 && com_token[k+l] && com_token[k+l] > ' ';l++)
                                                keyname[l] = com_token[k+l];
                                        keyname[l] = 0;
-                                       if (!COM_ParseTokenConsole(&data))
+                                       if (!COM_ParseToken_Simple(&data, false))
                                                break;
                                        if (developer.integer >= 100)
                                                Con_Printf("key: %s %s\n", keyname, com_token);
@@ -1029,7 +1333,7 @@ qboolean GetMapList (const char *s, char *completedname, int completednamebuffer
                                goto endcomplete;
        }
 endcomplete:
-       if(p > o)
+       if(p > o && completedname && completednamebufferlength > 0)
        {
                memset(completedname, 0, completednamebufferlength);
                memcpy(completedname, (t->filenames[0]+5), min(p, completednamebufferlength - 1));