2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 #if !defined(WIN32) || defined(__MINGW32__)
30 float con_cursorspeed = 4;
32 #define CON_TEXTSIZE 131072
34 // total lines in console scrollback
36 // lines up from bottom to display
38 // where next message will be printed
40 // offset in current line for next print
45 cvar_t con_notifytime = {CVAR_SAVE, "con_notifytime","3"};
46 cvar_t con_notify = {CVAR_SAVE, "con_notify","4"};
48 #define MAX_NOTIFYLINES 32
49 // cl.time time the line was generated for transparent notify lines
50 float con_times[MAX_NOTIFYLINES];
54 #define MAXCMDLINE 256
55 extern char key_lines[32][MAXCMDLINE];
57 extern int key_linepos;
58 extern int key_insert;
61 qboolean con_initialized;
63 mempool_t *console_mempool;
67 ==============================================================================
71 ==============================================================================
74 cvar_t log_file = {0, "log_file",""};
75 cvar_t log_sync = {0, "log_sync","0"};
76 char crt_log_file [MAX_OSPATH] = "";
77 qfile_t* logfile = NULL;
79 qbyte* logqueue = NULL;
83 void Log_ConPrint (const char *msg);
90 const char* Log_Timestamp (const char *desc)
92 static char timestamp [128];
94 const struct tm *crt_tm;
97 // Build the time stamp (ex: "Wed Jun 30 21:49:08 1993");
99 crt_tm = localtime (&crt_time);
100 strftime (timestring, sizeof (timestring), "%a %b %d %H:%M:%S %Y", crt_tm);
103 snprintf (timestamp, sizeof (timestamp), "====== %s (%s) ======\n", desc, timestring);
105 snprintf (timestamp, sizeof (timestamp), "====== %s ======\n", timestring);
118 Cvar_RegisterVariable (&log_file);
119 Cvar_RegisterVariable (&log_sync);
121 // support for the classic Quake option
122 if (COM_CheckParm ("-condebug") != 0)
124 Cvar_SetQuick (&log_file, "qconsole.log");
125 Cvar_SetValueQuick (&log_sync, 1);
126 unlink (va("%s/qconsole.log", fs_gamedir));
129 // Allocate a log queue
131 logqueue = Mem_Alloc (tempmempool, logq_size);
143 if (logfile != NULL || log_file.string[0] == '\0')
146 logfile = FS_Open (log_file.string, "at", false);
149 strlcpy (crt_log_file, log_file.string, sizeof (crt_log_file));
150 FS_Print (logfile, Log_Timestamp ("Log started"));
160 void Log_Close (void)
165 FS_Print (logfile, Log_Timestamp ("Log stopped"));
166 FS_Print (logfile, "\n");
170 crt_log_file[0] = '\0';
179 void Log_Start (void)
183 // Dump the contents of the log queue into the log file and free it
184 if (logqueue != NULL)
186 if (logfile != NULL && logq_ind != 0)
187 FS_Write (logfile, logqueue, logq_ind);
201 void Log_ConPrint (const char *msg)
203 // Until the host is completely initialized, we maintain a log queue
204 // to store the messages, since the log can't be started before
205 if (logqueue != NULL)
207 size_t remain = logq_size - logq_ind;
208 size_t len = strlen (msg);
210 // If we need to enlarge the log queue
213 unsigned int factor = ((logq_ind + len) / logq_size) + 1;
217 newqueue = Mem_Alloc (tempmempool, logq_size);
218 memcpy (newqueue, logqueue, logq_ind);
221 remain = logq_size - logq_ind;
223 memcpy (&logqueue[logq_ind], msg, len);
229 // Check if log_file has changed
230 if (strcmp (crt_log_file, log_file.string) != 0)
236 // If a log file is available
239 FS_Print (logfile, msg);
240 if (log_sync.integer)
251 void Log_Print (const char *logfilename, const char *msg)
254 file = FS_Open(logfilename, "at", true);
267 void Log_Printf (const char *logfilename, const char *fmt, ...)
271 file = FS_Open (logfilename, "at", true);
276 va_start (argptr, fmt);
277 FS_VPrintf (file, fmt, argptr);
286 ==============================================================================
290 ==============================================================================
298 void Con_ToggleConsole_f (void)
300 // toggle the 'user wants console' bit
301 key_consoleactive ^= KEY_CONSOLEACTIVE_USER;
302 memset (con_times, 0, sizeof(con_times));
310 void Con_Clear_f (void)
313 memset (con_text, ' ', CON_TEXTSIZE);
322 void Con_ClearNotify (void)
326 for (i=0 ; i<MAX_NOTIFYLINES ; i++)
336 void Con_MessageMode_f (void)
338 key_dest = key_message;
348 void Con_MessageMode2_f (void)
350 key_dest = key_message;
359 If the line width has changed, reformat the buffer.
362 void Con_CheckResize (void)
364 int i, j, width, oldwidth, oldtotallines, numlines, numchars;
365 char tbuf[CON_TEXTSIZE];
367 width = (vid.conwidth >> 3);
369 if (width == con_linewidth)
372 if (width < 1) // video hasn't been initialized yet
375 con_linewidth = width;
376 con_totallines = CON_TEXTSIZE / con_linewidth;
377 memset (con_text, ' ', CON_TEXTSIZE);
381 oldwidth = con_linewidth;
382 con_linewidth = width;
383 oldtotallines = con_totallines;
384 con_totallines = CON_TEXTSIZE / con_linewidth;
385 numlines = oldtotallines;
387 if (con_totallines < numlines)
388 numlines = con_totallines;
392 if (con_linewidth < numchars)
393 numchars = con_linewidth;
395 memcpy (tbuf, con_text, CON_TEXTSIZE);
396 memset (con_text, ' ', CON_TEXTSIZE);
398 for (i=0 ; i<numlines ; i++)
400 for (j=0 ; j<numchars ; j++)
402 con_text[(con_totallines - 1 - i) * con_linewidth + j] =
403 tbuf[((con_current - i + oldtotallines) %
404 oldtotallines) * oldwidth + j];
412 con_current = con_totallines - 1;
422 console_mempool = Mem_AllocPool("console", 0, NULL);
423 con_text = Mem_Alloc(console_mempool, CON_TEXTSIZE);
424 memset (con_text, ' ', CON_TEXTSIZE);
428 Con_Print("Console initialized.\n");
430 // register our cvars
431 Cvar_RegisterVariable (&con_notifytime);
432 Cvar_RegisterVariable (&con_notify);
434 // register our commands
435 Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
436 Cmd_AddCommand ("messagemode", Con_MessageMode_f);
437 Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
438 Cmd_AddCommand ("clear", Con_Clear_f);
439 con_initialized = true;
448 void Con_Linefeed (void)
455 memset (&con_text[(con_current%con_totallines)*con_linewidth], ' ', con_linewidth);
462 Handles cursor positioning, line wrapping, etc
463 All console printing must go through this in order to be displayed
464 If no console is visible, the notify window will pop up.
467 void Con_PrintToHistory(const char *txt)
474 mask = 128; // go to colored text
475 S_LocalSound ("misc/talk.wav", true);
479 else if (txt[0] == 2)
481 mask = 128; // go to colored text
491 for (l=0 ; l< con_linewidth ; l++)
496 if (l != con_linewidth && (con_x + l > con_linewidth) )
511 // mark time for transparent overlay
512 if (con_current >= 0)
514 if (con_notify.integer < 0)
515 Cvar_SetValueQuick(&con_notify, 0);
516 if (con_notify.integer > MAX_NOTIFYLINES)
517 Cvar_SetValueQuick(&con_notify, MAX_NOTIFYLINES);
518 if (con_notify.integer > 0)
519 con_times[con_current % con_notify.integer] = cl.time;
534 default: // display character and advance
535 y = con_current % con_totallines;
536 con_text[y*con_linewidth+con_x] = c | mask;
538 if (con_x >= con_linewidth)
550 Prints to all appropriate console targets
553 void Con_Print(const char *msg)
555 // also echo to debugging console
558 // log all messages to file
561 if (!con_initialized)
564 if (cls.state == ca_dedicated)
565 return; // no graphics mode
567 // write it to the scrollable buffer
568 Con_PrintToHistory(msg);
572 // LordHavoc: increased from 4096 to 16384
573 #define MAXPRINTMSG 16384
579 Prints to all appropriate console targets
582 void Con_Printf(const char *fmt, ...)
585 char msg[MAXPRINTMSG];
587 va_start(argptr,fmt);
588 vsprintf(msg,fmt,argptr);
598 A Con_Print that only shows up if the "developer" cvar is set
601 void Con_DPrint(const char *msg)
603 if (!developer.integer)
604 return; // don't confuse non-developers with techie stuff...
612 A Con_Printf that only shows up if the "developer" cvar is set
615 void Con_DPrintf(const char *fmt, ...)
618 char msg[MAXPRINTMSG];
620 if (!developer.integer)
621 return; // don't confuse non-developers with techie stuff...
623 va_start(argptr,fmt);
624 vsprintf(msg,fmt,argptr);
635 Okay to call even when the screen can't be updated
638 void Con_SafePrint(const char *msg)
647 Okay to call even when the screen can't be updated
650 void Con_SafePrintf(const char *fmt, ...)
653 char msg[MAXPRINTMSG];
655 va_start(argptr,fmt);
656 vsprintf(msg,fmt,argptr);
664 ==============================================================================
668 ==============================================================================
676 The input line scrolls horizontally if typing goes beyond the right edge
678 Modified by EvilTypeGuy eviltypeguy@qeradiant.com
681 void Con_DrawInput (void)
685 char editlinecopy[257], *text;
687 if (!key_consoleactive)
688 return; // don't draw anything
690 text = strcpy(editlinecopy, key_lines[edit_line]);
692 // Advanced Console Editing by Radix radix@planetquake.com
693 // Added/Modified by EvilTypeGuy eviltypeguy@qeradiant.com
694 // use strlen of edit_line instead of key_linepos to allow editing
695 // of early characters w/o erasing
699 // fill out remainder with spaces
700 for (i = y; i < 256; i++)
703 // add the cursor frame
704 if ((int)(realtime*con_cursorspeed) & 1) // cursor is visible
705 text[key_linepos] = 11 + 130 * key_insert; // either solid or triangle facing right
707 // text[key_linepos + 1] = 0;
709 // prestep if horizontally scrolling
710 if (key_linepos >= con_linewidth)
711 text += 1 + key_linepos - con_linewidth;
714 DrawQ_String(0, con_vislines - 16, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
717 // key_lines[edit_line][key_linepos] = 0;
725 Draws the last few lines of output transparently over the game top
728 void Con_DrawNotify (void)
734 extern char chat_buffer[];
737 if (con_notify.integer < 0)
738 Cvar_SetValueQuick(&con_notify, 0);
739 if (con_notify.integer > MAX_NOTIFYLINES)
740 Cvar_SetValueQuick(&con_notify, MAX_NOTIFYLINES);
741 if (gamemode == GAME_TRANSFUSION)
745 for (i= con_current-con_notify.integer+1 ; i<=con_current ; i++)
749 time = con_times[i % con_notify.integer];
752 time = cl.time - time;
753 if (time > con_notifytime.value)
755 text = con_text + (i % con_totallines)*con_linewidth;
759 DrawQ_String(0, v, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
765 if (key_dest == key_message)
771 // LordHavoc: speedup, and other improvements
773 sprintf(temptext, "say_team:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
775 sprintf(temptext, "say:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
776 while (strlen(temptext) >= (size_t) con_linewidth)
778 DrawQ_String (0, v, temptext, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
779 strcpy(temptext, &temptext[con_linewidth]);
782 if (strlen(temptext) > 0)
784 DrawQ_String (0, v, temptext, 0, 8, 8, 1, 1, 1, 1, 0);
794 Draws the console with the solid background
795 The typing input line at the bottom should only be drawn if typing is allowed
798 extern char engineversion[40];
799 void Con_DrawConsole (int lines)
807 // draw the background
808 if (scr_conbrightness.value >= 0.01f)
809 DrawQ_Pic(0, lines - vid.conheight, "gfx/conback", vid.conwidth, vid.conheight, scr_conbrightness.value, scr_conbrightness.value, scr_conbrightness.value, scr_conalpha.value, 0);
811 DrawQ_Fill(0, lines - vid.conheight, vid.conwidth, vid.conheight, 0, 0, 0, scr_conalpha.value, 0);
812 DrawQ_String(vid.conwidth - strlen(engineversion) * 8 - 8, lines - 8, engineversion, 0, 8, 8, 1, 0, 0, 1, 0);
815 con_vislines = lines;
817 rows = (lines-16)>>3; // rows of text to draw
818 y = lines - 16 - (rows<<3); // may start slightly negative
820 for (i = con_current - rows + 1;i <= con_current;i++, y += 8)
822 j = max(i - con_backscroll, 0);
823 text = con_text + (j % con_totallines)*con_linewidth;
825 DrawQ_String(0, y, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
828 // draw the input prompt, user text, and cursor if desired
835 New function for tab-completion system
837 MEGA Thanks to Taniwha
840 void Con_DisplayList(const char **list)
842 int i = 0, pos = 0, len = 0, maxlen = 0, width = (con_linewidth - 4);
843 const char **walk = list;
855 if (pos + maxlen >= width) {
861 for (i = 0; i < (maxlen - len); i++)
873 Con_CompleteCommandLine
875 New function for tab-completion system
877 Thanks to Fett erich@heintz.com
881 void Con_CompleteCommandLine (void)
883 const char *cmd = "", *s;
884 const char **list[3] = {0, 0, 0};
885 int c, v, a, i, cmd_len;
887 s = key_lines[edit_line] + 1;
888 // Count number of possible matches
889 c = Cmd_CompleteCountPossible(s);
890 v = Cvar_CompleteCountPossible(s);
891 a = Cmd_CompleteAliasCountPossible(s);
893 if (!(c + v + a)) // No possible matches
896 if (c + v + a == 1) {
898 list[0] = Cmd_CompleteBuildList(s);
900 list[0] = Cvar_CompleteBuildList(s);
902 list[0] = Cmd_CompleteAliasBuildList(s);
904 cmd_len = strlen (cmd);
907 cmd = *(list[0] = Cmd_CompleteBuildList(s));
909 cmd = *(list[1] = Cvar_CompleteBuildList(s));
911 cmd = *(list[2] = Cmd_CompleteAliasBuildList(s));
913 cmd_len = strlen (s);
915 for (i = 0; i < 3; i++) {
916 char ch = cmd[cmd_len];
917 const char **l = list[i];
919 while (*l && (*l)[cmd_len] == ch)
930 for (i = 0; i < con_linewidth - 4; i++)
934 // Print Possible Commands
936 Con_Printf("%i possible command%s\n", c, (c > 1) ? "s: " : ":");
937 Con_DisplayList(list[0]);
941 Con_Printf("%i possible variable%s\n", v, (v > 1) ? "s: " : ":");
942 Con_DisplayList(list[1]);
946 Con_Printf("%i possible aliases%s\n", a, (a > 1) ? "s: " : ":");
947 Con_DisplayList(list[2]);
952 strncpy(key_lines[edit_line] + 1, cmd, cmd_len);
953 key_linepos = cmd_len + 1;
954 if (c + v + a == 1) {
955 key_lines[edit_line][key_linepos] = ' ';
958 key_lines[edit_line][key_linepos] = 0;
960 for (i = 0; i < 3; i++)
962 Mem_Free((void *)list[i]);