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 // Allocate a log queue
120 logqueue = Mem_Alloc (tempmempool, logq_size);
123 Cvar_RegisterVariable (&log_file);
124 Cvar_RegisterVariable (&log_sync);
126 // support for the classic Quake option
127 // COMMANDLINEOPTION: Console: -condebug logs console messages to qconsole.log with sync on (so it keeps every message up to a crash), see also log_file and log_sync
128 if (COM_CheckParm ("-condebug") != 0)
130 Cvar_SetQuick (&log_file, "qconsole.log");
131 Cvar_SetValueQuick (&log_sync, 1);
132 unlink (va("%s/qconsole.log", fs_gamedir));
144 if (logfile != NULL || log_file.string[0] == '\0')
147 logfile = FS_Open (log_file.string, "at", false);
150 strlcpy (crt_log_file, log_file.string, sizeof (crt_log_file));
151 FS_Print (logfile, Log_Timestamp ("Log started"));
161 void Log_Close (void)
166 FS_Print (logfile, Log_Timestamp ("Log stopped"));
167 FS_Print (logfile, "\n");
171 crt_log_file[0] = '\0';
180 void Log_Start (void)
184 // Dump the contents of the log queue into the log file and free it
185 if (logqueue != NULL)
187 if (logfile != NULL && logq_ind != 0)
188 FS_Write (logfile, logqueue, logq_ind);
202 void Log_ConPrint (const char *msg)
204 static qboolean inprogress = false;
205 // don't allow feedback loops with memory error reports
209 // Until the host is completely initialized, we maintain a log queue
210 // to store the messages, since the log can't be started before
211 if (logqueue != NULL)
213 size_t remain = logq_size - logq_ind;
214 size_t len = strlen (msg);
216 // If we need to enlarge the log queue
219 unsigned int factor = ((logq_ind + len) / logq_size) + 1;
223 newqueue = Mem_Alloc (tempmempool, logq_size);
224 memcpy (newqueue, logqueue, logq_ind);
227 remain = logq_size - logq_ind;
229 memcpy (&logqueue[logq_ind], msg, len);
236 // Check if log_file has changed
237 if (strcmp (crt_log_file, log_file.string) != 0)
243 // If a log file is available
246 FS_Print (logfile, msg);
247 if (log_sync.integer)
259 void Log_Print (const char *logfilename, const char *msg)
262 file = FS_Open(logfilename, "at", true);
275 void Log_Printf (const char *logfilename, const char *fmt, ...)
279 file = FS_Open (logfilename, "at", true);
284 va_start (argptr, fmt);
285 FS_VPrintf (file, fmt, argptr);
294 ==============================================================================
298 ==============================================================================
306 void Con_ToggleConsole_f (void)
308 // toggle the 'user wants console' bit
309 key_consoleactive ^= KEY_CONSOLEACTIVE_USER;
310 memset (con_times, 0, sizeof(con_times));
318 void Con_Clear_f (void)
321 memset (con_text, ' ', CON_TEXTSIZE);
330 void Con_ClearNotify (void)
334 for (i=0 ; i<MAX_NOTIFYLINES ; i++)
344 void Con_MessageMode_f (void)
346 key_dest = key_message;
356 void Con_MessageMode2_f (void)
358 key_dest = key_message;
367 If the line width has changed, reformat the buffer.
370 void Con_CheckResize (void)
372 int i, j, width, oldwidth, oldtotallines, numlines, numchars;
373 char tbuf[CON_TEXTSIZE];
375 width = (vid.conwidth >> 3);
377 if (width == con_linewidth)
380 if (width < 1) // video hasn't been initialized yet
383 con_linewidth = width;
384 con_totallines = CON_TEXTSIZE / con_linewidth;
385 memset (con_text, ' ', CON_TEXTSIZE);
389 oldwidth = con_linewidth;
390 con_linewidth = width;
391 oldtotallines = con_totallines;
392 con_totallines = CON_TEXTSIZE / con_linewidth;
393 numlines = oldtotallines;
395 if (con_totallines < numlines)
396 numlines = con_totallines;
400 if (con_linewidth < numchars)
401 numchars = con_linewidth;
403 memcpy (tbuf, con_text, CON_TEXTSIZE);
404 memset (con_text, ' ', CON_TEXTSIZE);
406 for (i=0 ; i<numlines ; i++)
408 for (j=0 ; j<numchars ; j++)
410 con_text[(con_totallines - 1 - i) * con_linewidth + j] =
411 tbuf[((con_current - i + oldtotallines) %
412 oldtotallines) * oldwidth + j];
420 con_current = con_totallines - 1;
430 console_mempool = Mem_AllocPool("console", 0, NULL);
431 con_text = Mem_Alloc(console_mempool, CON_TEXTSIZE);
432 memset (con_text, ' ', CON_TEXTSIZE);
436 Con_Print("Console initialized.\n");
438 // register our cvars
439 Cvar_RegisterVariable (&con_notifytime);
440 Cvar_RegisterVariable (&con_notify);
442 // register our commands
443 Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
444 Cmd_AddCommand ("messagemode", Con_MessageMode_f);
445 Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
446 Cmd_AddCommand ("clear", Con_Clear_f);
447 con_initialized = true;
456 void Con_Linefeed (void)
463 memset (&con_text[(con_current%con_totallines)*con_linewidth], ' ', con_linewidth);
470 Handles cursor positioning, line wrapping, etc
471 All console printing must go through this in order to be displayed
472 If no console is visible, the notify window will pop up.
475 void Con_PrintToHistory(const char *txt)
482 mask = 128; // go to colored text
483 S_LocalSound ("misc/talk.wav", true);
487 else if (txt[0] == 2)
489 mask = 128; // go to colored text
499 for (l=0 ; l< con_linewidth ; l++)
504 if (l != con_linewidth && (con_x + l > con_linewidth) )
519 // mark time for transparent overlay
520 if (con_current >= 0)
522 if (con_notify.integer < 0)
523 Cvar_SetValueQuick(&con_notify, 0);
524 if (con_notify.integer > MAX_NOTIFYLINES)
525 Cvar_SetValueQuick(&con_notify, MAX_NOTIFYLINES);
526 if (con_notify.integer > 0)
527 con_times[con_current % con_notify.integer] = cl.time;
542 default: // display character and advance
543 y = con_current % con_totallines;
544 con_text[y*con_linewidth+con_x] = c | mask;
546 if (con_x >= con_linewidth)
558 Prints to all appropriate console targets
561 void Con_Print(const char *msg)
563 // also echo to debugging console
566 // log all messages to file
569 if (!con_initialized)
572 if (cls.state == ca_dedicated)
573 return; // no graphics mode
575 // write it to the scrollable buffer
576 Con_PrintToHistory(msg);
580 // LordHavoc: increased from 4096 to 16384
581 #define MAXPRINTMSG 16384
587 Prints to all appropriate console targets
590 void Con_Printf(const char *fmt, ...)
593 char msg[MAXPRINTMSG];
595 va_start(argptr,fmt);
596 vsprintf(msg,fmt,argptr);
606 A Con_Print that only shows up if the "developer" cvar is set
609 void Con_DPrint(const char *msg)
611 if (!developer.integer)
612 return; // don't confuse non-developers with techie stuff...
620 A Con_Printf that only shows up if the "developer" cvar is set
623 void Con_DPrintf(const char *fmt, ...)
626 char msg[MAXPRINTMSG];
628 if (!developer.integer)
629 return; // don't confuse non-developers with techie stuff...
631 va_start(argptr,fmt);
632 vsprintf(msg,fmt,argptr);
643 Okay to call even when the screen can't be updated
646 void Con_SafePrint(const char *msg)
655 Okay to call even when the screen can't be updated
658 void Con_SafePrintf(const char *fmt, ...)
661 char msg[MAXPRINTMSG];
663 va_start(argptr,fmt);
664 vsprintf(msg,fmt,argptr);
672 ==============================================================================
676 ==============================================================================
684 The input line scrolls horizontally if typing goes beyond the right edge
686 Modified by EvilTypeGuy eviltypeguy@qeradiant.com
689 void Con_DrawInput (void)
693 char editlinecopy[257], *text;
695 if (!key_consoleactive)
696 return; // don't draw anything
698 text = strcpy(editlinecopy, key_lines[edit_line]);
700 // Advanced Console Editing by Radix radix@planetquake.com
701 // Added/Modified by EvilTypeGuy eviltypeguy@qeradiant.com
702 // use strlen of edit_line instead of key_linepos to allow editing
703 // of early characters w/o erasing
707 // fill out remainder with spaces
708 for (i = y; i < 256; i++)
711 // add the cursor frame
712 if ((int)(realtime*con_cursorspeed) & 1) // cursor is visible
713 text[key_linepos] = 11 + 130 * key_insert; // either solid or triangle facing right
715 // text[key_linepos + 1] = 0;
717 // prestep if horizontally scrolling
718 if (key_linepos >= con_linewidth)
719 text += 1 + key_linepos - con_linewidth;
722 DrawQ_String(0, con_vislines - 16, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
725 // key_lines[edit_line][key_linepos] = 0;
733 Draws the last few lines of output transparently over the game top
736 void Con_DrawNotify (void)
742 extern char chat_buffer[];
745 if (con_notify.integer < 0)
746 Cvar_SetValueQuick(&con_notify, 0);
747 if (con_notify.integer > MAX_NOTIFYLINES)
748 Cvar_SetValueQuick(&con_notify, MAX_NOTIFYLINES);
749 if (gamemode == GAME_TRANSFUSION)
753 for (i= con_current-con_notify.integer+1 ; i<=con_current ; i++)
757 time = con_times[i % con_notify.integer];
760 time = cl.time - time;
761 if (time > con_notifytime.value)
763 text = con_text + (i % con_totallines)*con_linewidth;
767 DrawQ_String(0, v, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
773 if (key_dest == key_message)
779 // LordHavoc: speedup, and other improvements
781 sprintf(temptext, "say_team:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
783 sprintf(temptext, "say:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
784 while (strlen(temptext) >= (size_t) con_linewidth)
786 DrawQ_String (0, v, temptext, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
787 strcpy(temptext, &temptext[con_linewidth]);
790 if (strlen(temptext) > 0)
792 DrawQ_String (0, v, temptext, 0, 8, 8, 1, 1, 1, 1, 0);
802 Draws the console with the solid background
803 The typing input line at the bottom should only be drawn if typing is allowed
806 extern char engineversion[40];
807 void Con_DrawConsole (int lines)
815 // draw the background
816 if (scr_conbrightness.value >= 0.01f)
817 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);
819 DrawQ_Fill(0, lines - vid.conheight, vid.conwidth, vid.conheight, 0, 0, 0, scr_conalpha.value, 0);
820 DrawQ_String(vid.conwidth - strlen(engineversion) * 8 - 8, lines - 8, engineversion, 0, 8, 8, 1, 0, 0, 1, 0);
823 con_vislines = lines;
825 rows = (lines-16)>>3; // rows of text to draw
826 y = lines - 16 - (rows<<3); // may start slightly negative
828 for (i = con_current - rows + 1;i <= con_current;i++, y += 8)
830 j = max(i - con_backscroll, 0);
831 text = con_text + (j % con_totallines)*con_linewidth;
833 DrawQ_String(0, y, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
836 // draw the input prompt, user text, and cursor if desired
843 New function for tab-completion system
845 MEGA Thanks to Taniwha
848 void Con_DisplayList(const char **list)
850 int i = 0, pos = 0, len = 0, maxlen = 0, width = (con_linewidth - 4);
851 const char **walk = list;
863 if (pos + maxlen >= width) {
869 for (i = 0; i < (maxlen - len); i++)
881 Con_CompleteCommandLine
883 New function for tab-completion system
885 Thanks to Fett erich@heintz.com
889 void Con_CompleteCommandLine (void)
891 const char *cmd = "", *s;
892 const char **list[3] = {0, 0, 0};
893 int c, v, a, i, cmd_len;
895 s = key_lines[edit_line] + 1;
896 // Count number of possible matches
897 c = Cmd_CompleteCountPossible(s);
898 v = Cvar_CompleteCountPossible(s);
899 a = Cmd_CompleteAliasCountPossible(s);
901 if (!(c + v + a)) // No possible matches
904 if (c + v + a == 1) {
906 list[0] = Cmd_CompleteBuildList(s);
908 list[0] = Cvar_CompleteBuildList(s);
910 list[0] = Cmd_CompleteAliasBuildList(s);
912 cmd_len = strlen (cmd);
915 cmd = *(list[0] = Cmd_CompleteBuildList(s));
917 cmd = *(list[1] = Cvar_CompleteBuildList(s));
919 cmd = *(list[2] = Cmd_CompleteAliasBuildList(s));
921 cmd_len = strlen (s);
923 for (i = 0; i < 3; i++) {
924 char ch = cmd[cmd_len];
925 const char **l = list[i];
927 while (*l && (*l)[cmd_len] == ch)
938 for (i = 0; i < con_linewidth - 4; i++)
942 // Print Possible Commands
944 Con_Printf("%i possible command%s\n", c, (c > 1) ? "s: " : ":");
945 Con_DisplayList(list[0]);
949 Con_Printf("%i possible variable%s\n", v, (v > 1) ? "s: " : ":");
950 Con_DisplayList(list[1]);
954 Con_Printf("%i possible aliases%s\n", a, (a > 1) ? "s: " : ":");
955 Con_DisplayList(list[2]);
960 strncpy(key_lines[edit_line] + 1, cmd, cmd_len);
961 key_linepos = cmd_len + 1;
962 if (c + v + a == 1) {
963 key_lines[edit_line][key_linepos] = ' ';
966 key_lines[edit_line][key_linepos] = 0;
968 for (i = 0; i < 3; i++)
970 Mem_Free((void *)list[i]);