DarkPlaces
Game engine based on the Quake 1 engine by id Software, developed by LadyHavoc
 
console.c
Go to the documentation of this file.
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3Copyright (C) 2000-2020 DarkPlaces contributors
4
5This program is free software; you can redistribute it and/or
6modify it under the terms of the GNU General Public License
7as published by the Free Software Foundation; either version 2
8of the License, or (at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
14See the GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program; if not, write to the Free Software
18Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20*/
21// console.c
22
23#if !defined(WIN32) || defined(__MINGW32__)
24# include <unistd.h>
25#endif
26#include <time.h>
27
28#include "quakedef.h"
29#include "thread.h"
30
31// for u8_encodech
32#include "ft2.h"
33
35
36// lines up from bottom to display
38
41
42#define CON_LINES(i) CONBUFFER_LINES(&con, i)
43#define CON_LINES_LAST CONBUFFER_LINES_LAST(&con)
44#define CON_LINES_COUNT CONBUFFER_LINES_COUNT(&con)
45
46cvar_t con_notifytime = {CF_CLIENT | CF_ARCHIVE, "con_notifytime","3", "how long notify lines last, in seconds"};
47cvar_t con_notify = {CF_CLIENT | CF_ARCHIVE, "con_notify","4", "how many notify lines to show"};
48cvar_t con_notifyalign = {CF_CLIENT | CF_ARCHIVE, "con_notifyalign", "", "how to align notify lines: 0 = left, 0.5 = center, 1 = right, empty string = game default)"};
49
50cvar_t con_chattime = {CF_CLIENT | CF_ARCHIVE, "con_chattime","30", "how long chat lines last, in seconds"};
51cvar_t con_chat = {CF_CLIENT | CF_ARCHIVE, "con_chat","0", "how many chat lines to show in a dedicated chat area"};
52cvar_t con_chatpos = {CF_CLIENT | CF_ARCHIVE, "con_chatpos","0", "where to put chat (negative: lines from bottom of screen, positive: lines below notify, 0: at top)"};
53cvar_t con_chatrect = {CF_CLIENT | CF_ARCHIVE, "con_chatrect","0", "use con_chatrect_x and _y to position con_notify and con_chat freely instead of con_chatpos"};
54cvar_t con_chatrect_x = {CF_CLIENT | CF_ARCHIVE, "con_chatrect_x","", "where to put chat, relative x coordinate of left edge on screen (use con_chatwidth for width)"};
55cvar_t con_chatrect_y = {CF_CLIENT | CF_ARCHIVE, "con_chatrect_y","", "where to put chat, relative y coordinate of top edge on screen (use con_chat for line count)"};
56cvar_t con_chatwidth = {CF_CLIENT | CF_ARCHIVE, "con_chatwidth","1.0", "relative chat window width"};
57cvar_t con_textsize = {CF_CLIENT | CF_ARCHIVE, "con_textsize","8", "console text size in virtual 2D pixels"};
58cvar_t con_notifysize = {CF_CLIENT | CF_ARCHIVE, "con_notifysize","8", "notify text size in virtual 2D pixels"};
59cvar_t con_chatsize = {CF_CLIENT | CF_ARCHIVE, "con_chatsize","8", "chat text size in virtual 2D pixels (if con_chat is enabled)"};
60cvar_t con_chatsound = {CF_CLIENT | CF_ARCHIVE, "con_chatsound","1", "enables chat sound to play on message"};
61cvar_t con_chatsound_file = {CF_CLIENT, "con_chatsound_file","sound/misc/talk.wav", "The sound to play for chat messages"};
62cvar_t con_chatsound_team_file = {CF_CLIENT, "con_chatsound_team_file","sound/misc/talk2.wav", "The sound to play for team chat messages"};
63cvar_t con_chatsound_team_mask = {CF_CLIENT, "con_chatsound_team_mask","40","Magic ASCII code that denotes a team chat message"};
64
65cvar_t sys_specialcharactertranslation = {CF_CLIENT | CF_SERVER, "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)"};
66cvar_t sys_colortranslation = {CF_CLIENT | CF_SERVER, "sys_colortranslation", "1", "terminal console color translation (supported values: -1 = print codes without translation, 0 = strip color codes, 1 = translate to ANSI codes, 2 = translate DP RGB to 24-bit and Quake colors to ANSI, 3 = translate all colors to 24-bit RGB)"};
67
68
69cvar_t con_nickcompletion = {CF_CLIENT | CF_ARCHIVE, "con_nickcompletion", "1", "tab-complete nicks in console and message input"};
70cvar_t con_nickcompletion_flags = {CF_CLIENT | CF_ARCHIVE, "con_nickcompletion_flags", "11", "Bitfield: "
71 "0: add nothing after completion. "
72 "1: add the last color after completion. "
73 "2: add a quote when starting a quote instead of the color. "
74 "4: will replace 1, will force color, even after a quote. "
75 "8: ignore non-alphanumerics. "
76 "16: ignore spaces. "};
77#define NICKS_ADD_COLOR 1
78#define NICKS_ADD_QUOTE 2
79#define NICKS_FORCE_COLOR 4
80#define NICKS_ALPHANUMERICS_ONLY 8
81#define NICKS_NO_SPACES 16
82
83cvar_t con_completion_playdemo = {CF_CLIENT | CF_ARCHIVE, "con_completion_playdemo", "*.dem", "completion pattern for the playdemo command"};
84cvar_t con_completion_timedemo = {CF_CLIENT | CF_ARCHIVE, "con_completion_timedemo", "*.dem", "completion pattern for the timedemo command"};
85cvar_t con_completion_exec = {CF_CLIENT | CF_ARCHIVE, "con_completion_exec", "*.cfg", "completion pattern for the exec command"};
86
87cvar_t condump_stripcolors = {CF_CLIENT | CF_SERVER| CF_ARCHIVE, "condump_stripcolors", "0", "strip color codes from console dumps"};
88
89cvar_t rcon_password = {CF_CLIENT | CF_SERVER | CF_PRIVATE, "rcon_password", "", "password to authenticate rcon commands; NOTE: changing rcon_secure clears rcon_password, so set rcon_secure always before rcon_password; may be set to a string of the form user1:pass1 user2:pass2 user3:pass3 to allow multiple user accounts - the client then has to specify ONE of these combinations"};
90cvar_t rcon_secure = {CF_CLIENT | CF_SERVER, "rcon_secure", "0", "force secure rcon authentication (1 = time based, 2 = challenge based); NOTE: changing rcon_secure clears rcon_password, so set rcon_secure always before rcon_password"};
91cvar_t rcon_secure_challengetimeout = {CF_CLIENT, "rcon_secure_challengetimeout", "5", "challenge-based secure rcon: time out requests if no challenge came within this time interval"};
92cvar_t rcon_address = {CF_CLIENT, "rcon_address", "", "server address to send rcon commands to (when not connected to a server)"};
93
96
98
99// used for server replies to rcon command
105
106// generic functions for console buffers
107
108void ConBuffer_Init(conbuffer_t *buf, int textsize, int maxlines, mempool_t *mempool)
109{
110 buf->active = true;
111 buf->textsize = textsize;
112 buf->text = (char *) Mem_Alloc(mempool, textsize);
113 buf->maxlines = maxlines;
114 buf->lines = (con_lineinfo_t *) Mem_Alloc(mempool, maxlines * sizeof(*buf->lines));
115 buf->lines_first = 0;
116 buf->lines_count = 0;
117}
118
120static char qfont_table[256] = {
121 '\0', '#', '#', '#', '#', '.', '#', '#',
122 '#', 9, 10, '#', ' ', 13, '.', '.',
123 '[', ']', '0', '1', '2', '3', '4', '5',
124 '6', '7', '8', '9', '.', '<', '=', '>',
125 ' ', '!', '"', '#', '$', '%', '&', '\'',
126 '(', ')', '*', '+', ',', '-', '.', '/',
127 '0', '1', '2', '3', '4', '5', '6', '7',
128 '8', '9', ':', ';', '<', '=', '>', '?',
129 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
130 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
131 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
132 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
133 '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
134 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
135 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
136 'x', 'y', 'z', '{', '|', '}', '~', '<',
137
138 '<', '=', '>', '#', '#', '.', '#', '#',
139 '#', '#', ' ', '#', ' ', '>', '.', '.',
140 '[', ']', '0', '1', '2', '3', '4', '5',
141 '6', '7', '8', '9', '.', '<', '=', '>',
142 ' ', '!', '"', '#', '$', '%', '&', '\'',
143 '(', ')', '*', '+', ',', '-', '.', '/',
144 '0', '1', '2', '3', '4', '5', '6', '7',
145 '8', '9', ':', ';', '<', '=', '>', '?',
146 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
147 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
148 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
149 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
150 '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
151 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
152 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
153 'x', 'y', 'z', '{', '|', '}', '~', '<'
154};
155
156/*
157 SanitizeString strips color tags from the string in
158 and writes the result on string out
159*/
160static void SanitizeString(char *in, char *out)
161{
162 while(*in)
163 {
164 if(*in == STRING_COLOR_TAG)
165 {
166 ++in;
167 if(!*in)
168 {
169 out[0] = STRING_COLOR_TAG;
170 out[1] = 0;
171 return;
172 }
173 else if (*in >= '0' && *in <= '9') // ^[0-9] found
174 {
175 ++in;
176 if(!*in)
177 {
178 *out = 0;
179 return;
180 } else if (*in == STRING_COLOR_TAG) // ^[0-9]^ found, don't print ^[0-9]
181 continue;
182 }
183 else if (*in == STRING_COLOR_RGB_TAG_CHAR) // ^x found
184 {
185 if ( isxdigit(in[1]) && isxdigit(in[2]) && isxdigit(in[3]) )
186 {
187 in+=4;
188 if (!*in)
189 {
190 *out = 0;
191 return;
192 } else if (*in == STRING_COLOR_TAG) // ^xrgb^ found, don't print ^xrgb
193 continue;
194 }
195 else in--;
196 }
197 else if (*in != STRING_COLOR_TAG)
198 --in;
199 }
200 *out = qfont_table[*(unsigned char*)in];
201 ++in;
202 ++out;
203 }
204 *out = 0;
205}
206
207/*
208================
209ConBuffer_Clear
210================
211*/
213{
214 buf->lines_count = 0;
215}
216
217/*
218================
219ConBuffer_Shutdown
220================
221*/
223{
224 buf->active = false;
225 if (buf->text)
226 Mem_Free(buf->text);
227 if (buf->lines)
228 Mem_Free(buf->lines);
229 buf->text = NULL;
230 buf->lines = NULL;
231}
232
233/*
234================
235ConBuffer_FixTimes
236
237Notifies the console code about the current time
238(and shifts back times of other entries when the time
239went backwards)
240================
241*/
243{
244 int i;
245 if(buf->lines_count >= 1)
246 {
247 double diff = cl.time - CONBUFFER_LINES_LAST(buf).addtime;
248 if(diff < 0)
249 {
250 for(i = 0; i < buf->lines_count; ++i)
251 CONBUFFER_LINES(buf, i).addtime += diff;
252 }
253 }
254}
255
256/*
257================
258ConBuffer_DeleteLine
259
260Deletes the first line from the console history.
261================
262*/
264{
265 if(buf->lines_count == 0)
266 return;
267 --buf->lines_count;
268 buf->lines_first = (buf->lines_first + 1) % buf->maxlines;
269}
270
271/*
272================
273ConBuffer_DeleteLastLine
274
275Deletes the last line from the console history.
276================
277*/
279{
280 if(buf->lines_count == 0)
281 return;
282 --buf->lines_count;
283}
284
285/*
286================
287ConBuffer_BytesLeft
288
289Checks if there is space for a line of the given length, and if yes, returns a
290pointer to the start of such a space, and NULL otherwise.
291================
292*/
293static char *ConBuffer_BytesLeft(conbuffer_t *buf, int len)
294{
295 if(len > buf->textsize)
296 return NULL;
297 if(buf->lines_count == 0)
298 return buf->text;
299 else
300 {
301 char *firstline_start = buf->lines[buf->lines_first].start;
302 char *lastline_onepastend = CONBUFFER_LINES_LAST(buf).start + CONBUFFER_LINES_LAST(buf).len;
303 // the buffer is cyclic, so we first have two cases...
304 if(firstline_start < lastline_onepastend) // buffer is contiguous
305 {
306 // put at end?
307 if(len <= buf->text + buf->textsize - lastline_onepastend)
308 return lastline_onepastend;
309 // put at beginning?
310 else if(len <= firstline_start - buf->text)
311 return buf->text;
312 else
313 return NULL;
314 }
315 else // buffer has a contiguous hole
316 {
317 if(len <= firstline_start - lastline_onepastend)
318 return lastline_onepastend;
319 else
320 return NULL;
321 }
322 }
323}
324
325/*
326================
327ConBuffer_AddLine
328
329Appends a given string as a new line to the console.
330================
331*/
332void ConBuffer_AddLine(conbuffer_t *buf, const char *line, int len, unsigned mask)
333{
334 char *putpos;
336
337 // developer_memory 1 during shutdown prints while conbuffer_t is being freed
338 if (!buf->active)
339 return;
340
342
343 if(len >= buf->textsize)
344 {
345 // line too large?
346 // only display end of line.
347 line += len - buf->textsize + 1;
348 len = buf->textsize - 1;
349 }
350 while(!(putpos = ConBuffer_BytesLeft(buf, len + 1)) || buf->lines_count >= buf->maxlines)
352 memcpy(putpos, line, len);
353 putpos[len] = 0;
354 ++buf->lines_count;
355
356 //fprintf(stderr, "Now have %d lines (%d -> %d).\n", buf->lines_count, buf->lines_first, CON_LINES_LAST);
357
359 p->start = putpos;
360 p->len = len;
361 p->addtime = cl.time;
362 p->mask = mask;
363 p->height = -1; // calculate when needed
364}
365
366int ConBuffer_FindPrevLine(conbuffer_t *buf, unsigned mask_must, unsigned mask_mustnot, int start)
367{
368 int i;
369 if(start == -1)
370 start = buf->lines_count;
371 for(i = start - 1; i >= 0; --i)
372 {
374
375 if((l->mask & mask_must) != mask_must)
376 continue;
377 if(l->mask & mask_mustnot)
378 continue;
379
380 return i;
381 }
382
383 return -1;
384}
385
387{
388 static char copybuf[MAX_INPUTLINE]; // client only
390
391 dp_ustr2stp(copybuf, sizeof(copybuf), l->start, l->len);
392 return copybuf;
393}
394
395/*
396==============================================================================
397
398LOGGING
399
400==============================================================================
401*/
402
404
405cvar_t log_file = {CF_CLIENT | CF_SERVER, "log_file", "", "filename to log messages to"};
406cvar_t log_file_stripcolors = {CF_CLIENT | CF_SERVER, "log_file_stripcolors", "0", "strip color codes from log messages"};
407cvar_t log_dest_udp = {CF_CLIENT | CF_SERVER, "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"};
408char log_dest_buffer[1400]; // UDP packet
412qfile_t* logfile = NULL;
413
414unsigned char* logqueue = NULL;
415size_t logq_ind = 0;
416size_t logq_size = 0;
417
418void Log_ConPrint (const char *msg);
420static void Log_DestBuffer_Init(void)
421{
422 memcpy(log_dest_buffer, "\377\377\377\377n", 5); // QW rcon print
424}
425
427{
428 lhnetaddress_t log_dest_addr;
429 lhnetsocket_t *log_dest_socket;
430 const char *s = log_dest_udp.string;
431 qbool have_opened_temp_sockets = false;
432 if(s) if(log_dest_buffer_pos > 5)
433 {
436
437 if(!NetConn_HaveServerPorts() && !NetConn_HaveClientPorts()) // then temporarily open one
438 {
439 have_opened_temp_sockets = true;
441 }
442
443 while(COM_ParseToken_Console(&s))
444 if(LHNETADDRESS_FromString(&log_dest_addr, com_token, 26000))
445 {
446 log_dest_socket = NetConn_ChooseClientSocketForAddress(&log_dest_addr);
447 if(!log_dest_socket)
448 log_dest_socket = NetConn_ChooseServerSocketForAddress(&log_dest_addr);
449 if(log_dest_socket)
450 NetConn_WriteString(log_dest_socket, log_dest_buffer, &log_dest_addr);
451 }
452
453 if(have_opened_temp_sockets)
456 }
458}
459
460/*
461====================
462Log_DestBuffer_Flush
463====================
464*/
473
474static const char* Log_Timestamp (const char *desc)
475{
476 static char timestamp [128]; // init/shutdown only
477 time_t crt_time;
478#if _MSC_VER >= 1400
479 struct tm crt_tm;
480#else
481 struct tm *crt_tm;
482#endif
483 char timestring [64];
484
485 // Build the time stamp (ex: "Wed Jun 30 21:49:08 1993");
486 time (&crt_time);
487#if _MSC_VER >= 1400
488 localtime_s (&crt_tm, &crt_time);
489 strftime (timestring, sizeof (timestring), "%a %b %d %H:%M:%S %Y", &crt_tm);
490#else
491 crt_tm = localtime (&crt_time);
492 strftime (timestring, sizeof (timestring), "%a %b %d %H:%M:%S %Y", crt_tm);
493#endif
494
495 if (desc != NULL)
496 dpsnprintf (timestamp, sizeof (timestamp), "====== %s (%s) ======\n", desc, timestring);
497 else
498 dpsnprintf (timestamp, sizeof (timestamp), "====== %s ======\n", timestring);
499
500 return timestamp;
501}
502
503static void Log_Open (void)
504{
505 if (logfile != NULL || log_file.string[0] == '\0')
506 return;
507
508 logfile = FS_OpenRealFile(log_file.string, "a", false);
509 if (logfile != NULL)
510 {
512 FS_Print (logfile, Log_Timestamp ("Log started"));
513 }
514}
515
516/*
517====================
518Log_Close
519====================
520*/
521void Log_Close (void)
522{
523 qfile_t* l = logfile;
524
525 if (l == NULL)
526 return;
527
528 FS_Print (l, Log_Timestamp ("Log stopped"));
529 FS_Print (l, "\n");
530 logfile = NULL;
531 FS_Close (l);
532
533 crt_log_file[0] = '\0';
534}
535
536
537/*
538====================
539Log_Start
540====================
541*/
542void Log_Start (void)
543{
544 size_t pos;
545 size_t n;
546 Log_Open ();
547
548 // Dump the contents of the log queue into the log file and free it
549 if (logqueue != NULL)
550 {
551 unsigned char *temp = logqueue;
552 logqueue = NULL;
553 if(logq_ind != 0)
554 {
555 if (logfile != NULL)
556 FS_Write (logfile, temp, logq_ind);
558 {
559 for(pos = 0; pos < logq_ind; )
560 {
561 if(log_dest_buffer_pos == 0)
563 n = min(sizeof(log_dest_buffer) - log_dest_buffer_pos - 1, logq_ind - pos);
564 memcpy(log_dest_buffer + log_dest_buffer_pos, temp + pos, n);
567 pos += n;
568 }
569 }
570 }
571 Mem_Free (temp);
572 logq_ind = 0;
573 logq_size = 0;
574 }
575}
576
577
578
579/*
580================
581Log_ConPrint
582================
583*/
584void Log_ConPrint (const char *msg)
585{
586 static qbool inprogress = false;
587
588 // don't allow feedback loops with memory error reports
589 if (inprogress)
590 return;
591 inprogress = true;
592
593 // Until the host is completely initialized, we maintain a log queue
594 // to store the messages, since the log can't be started before
595 if (logqueue != NULL)
596 {
597 size_t remain = logq_size - logq_ind;
598 size_t len = strlen (msg);
599
600 // If we need to enlarge the log queue
601 if (len > remain)
602 {
603 size_t factor = ((logq_ind + len) / logq_size) + 1;
604 unsigned char* newqueue;
605
606 logq_size *= factor;
607 newqueue = (unsigned char *)Mem_Alloc (tempmempool, logq_size);
608 memcpy (newqueue, logqueue, logq_ind);
610 logqueue = newqueue;
611 remain = logq_size - logq_ind;
612 }
613 memcpy (&logqueue[logq_ind], msg, len);
614 logq_ind += len;
615
616 inprogress = false;
617 return;
618 }
619
620 // Check if log_file has changed
621 if (strcmp (crt_log_file, log_file.string) != 0)
622 {
623 Log_Close ();
624 Log_Open ();
625 }
626
627 // If a log file is available
628 if (logfile != NULL)
629 {
631 {
632 // sanitize msg
633 size_t len = strlen(msg);
634 char* sanitizedmsg = (char*)Mem_Alloc(tempmempool, len + 1);
635 memcpy (sanitizedmsg, msg, len);
636 SanitizeString(sanitizedmsg, sanitizedmsg); // SanitizeString's in pointer is always ahead of the out pointer, so this should work.
637 FS_Print (logfile, sanitizedmsg);
638 Mem_Free(sanitizedmsg);
639 }
640 else
641 {
642 FS_Print (logfile, msg);
643 }
644 }
645
646 inprogress = false;
647}
648
649
650/*
651================
652Log_Printf
653================
654*/
655void Log_Printf (const char *logfilename, const char *fmt, ...)
656{
657 qfile_t *file;
658
659 file = FS_OpenRealFile(logfilename, "a", true);
660 if (file != NULL)
661 {
662 va_list argptr;
663
664 va_start (argptr, fmt);
665 FS_VPrintf (file, fmt, argptr);
666 va_end (argptr);
667
668 FS_Close (file);
669 }
670}
671
672
673/*
674==============================================================================
675
676CONSOLE
677
678==============================================================================
679*/
680
681/*
682================
683Con_ToggleConsole_f
684================
685*/
687{
688 if (Sys_CheckParm ("-noconsole"))
690 return; // only allow the key bind to turn off console
691
692 // toggle the 'user wants console' bit
695}
696
697/*
698================
699Con_ClearNotify
700================
701*/
703{
704 int i;
705 for(i = 0; i < CON_LINES_COUNT; ++i)
706 if(!(CON_LINES(i).mask & CON_MASK_CHAT))
708}
709
710static void Con_MsgCmdMode(cmd_state_t *cmd, signed char mode)
711{
712 if (cls.demoplayback && mode >= 0)
713 return;
715 chat_mode = mode;
716 if(Cmd_Argc(cmd) > 1)
717 {
719 if (chat_bufferpos < 0)
720 chat_bufferpos = 0;
721 }
722}
723
724/*
725================
726Con_MessageMode_f
727
728"say"
729================
730*/
732{
734}
735
736/*
737================
738Con_MessageMode2_f
739
740"say_team"
741================
742*/
744{
746}
747
748/*
749================
750Con_CommandMode_f
751================
752*/
754{
755 Con_MsgCmdMode(cmd, -1);
756}
757
758/*
759================
760Con_CheckResize
761================
762*/
764{
765 int i, width;
766 float f;
767
768 f = bound(1, con_textsize.value, 128);
769 if(f != con_textsize.value)
772 width = bound(1, width, con.textsize/4);
773 // FIXME uses con in a non abstracted way
774
775 if (width == con_linewidth)
776 return;
777
779
780 for(i = 0; i < CON_LINES_COUNT; ++i)
781 CON_LINES(i).height = -1; // recalculate when next needed
782
784 con_backscroll = 0;
785}
786
787//[515]: the simplest command ever
788//LadyHavoc: not so simple after I made it print usage...
790{
791 if (Cmd_Argc(cmd) > 2)
792 {
793 Con_Printf("usage: maps [mapnameprefix]\n");
794 return;
795 }
796 else if (Cmd_Argc(cmd) == 2)
797 GetMapList(Cmd_Argv(cmd, 1), NULL, 0);
798 else
799 GetMapList("", NULL, 0);
800}
801
803{
804 int i;
805 qfile_t *file;
806 if (Cmd_Argc(cmd) != 2)
807 {
808 Con_Printf("usage: condump <filename>\n");
809 return;
810 }
811 file = FS_OpenRealFile(Cmd_Argv(cmd, 1), "w", false);
812 if (!file)
813 {
814 Con_Printf(CON_ERROR "condump: unable to write file \"%s\"\n", Cmd_Argv(cmd, 1));
815 return;
816 }
818 for(i = 0; i < CON_LINES_COUNT; ++i)
819 {
821 {
822 // sanitize msg
823 size_t len = CON_LINES(i).len;
824 char* sanitizedmsg = (char*)Mem_Alloc(tempmempool, len + 1);
825 memcpy (sanitizedmsg, CON_LINES(i).start, len);
826 SanitizeString(sanitizedmsg, sanitizedmsg); // SanitizeString's in pointer is always ahead of the out pointer, so this should work.
827 FS_Write(file, sanitizedmsg, strlen(sanitizedmsg));
828 Mem_Free(sanitizedmsg);
829 }
830 else
831 {
832 FS_Write(file, CON_LINES(i).start, CON_LINES(i).len);
833 }
834 FS_Write(file, "\n", 1);
835 }
837 FS_Close(file);
838}
839
846
848{
849 // whenever rcon_secure is changed to 0, clear rcon_password for
850 // security reasons (prevents a send-rcon-password-as-plaintext
851 // attack based on NQ protocol session takeover and svc_stufftext)
852 if(var->integer <= 0)
854}
855
856/*
857================
858Con_Init
859================
860*/
861void Con_Init (void)
862{
863 con_linewidth = 80;
865 if (Thread_HasThreads())
867
868 // Allocate a log queue, this will be freed after configs are parsed
870 logqueue = (unsigned char *)Mem_Alloc (tempmempool, logq_size);
871 logq_ind = 0;
872
875#if defined(__linux__)
876 // Linux terminals natively support RGB 8bpc codes or convert them to a palette.
878#elif defined(WIN32)
879 // Windows 10 default PowerShell and cmd.exe have no RGB or ANSI support by default.
880 // TODO: it can be enabled on current versions using a platform-specific call,
881 // issue: https://gitlab.com/xonotic/darkplaces/-/issues/426
883#endif
884
888
889 // support for the classic Quake option
890// COMMANDLINEOPTION: Console: -condebug logs console messages to qconsole.log, see also log_file
891 if (Sys_CheckParm ("-condebug") != 0)
892 Cvar_SetQuick (&log_file, "qconsole.log");
893
894 // register our cvars
912
913 // --blub
916
920
922
928
929 // register our commands
930 Cmd_AddCommand(CF_CLIENT, "toggleconsole", Con_ToggleConsole_f, "opens or closes the console");
931 Cmd_AddCommand(CF_CLIENT, "messagemode", Con_MessageMode_f, "input a chat message to say to everyone");
932 Cmd_AddCommand(CF_CLIENT, "messagemode2", Con_MessageMode2_f, "input a chat message to say to only your team");
933 Cmd_AddCommand(CF_CLIENT, "commandmode", Con_CommandMode_f, "input a console command");
934 Cmd_AddCommand(CF_SHARED, "clear", Con_Clear_f, "clear console history");
935 Cmd_AddCommand(CF_SHARED, "maps", Con_Maps_f, "list information about available maps");
936 Cmd_AddCommand(CF_SHARED, "condump", Con_ConDump_f, "output console history to a file (see also log_file)");
937
938 con_initialized = true;
939}
940
949
950/*
951================
952Con_PrintToHistory
953
954Handles cursor positioning, line wrapping, etc
955All console printing must go through this in order to be displayed
956If no console is visible, the notify window will pop up.
957================
958*/
959static void Con_PrintToHistory(const char *txt, int mask)
960{
961 // process:
962 // \n goes to next line
963 // \r deletes current line and makes a new one
964
965 static int cr_pending = 0;
966 static char buf[CON_TEXTSIZE]; // con_mutex
967 static int bufpos = 0;
968
969 if(!con.text) // FIXME uses a non-abstracted property of con
970 return;
971
972 for(; *txt; ++txt)
973 {
974 if(cr_pending)
975 {
977 cr_pending = 0;
978 }
979 switch(*txt)
980 {
981 case 0:
982 break;
983 case '\r':
984 ConBuffer_AddLine(&con, buf, bufpos, mask);
985 bufpos = 0;
986 cr_pending = 1;
987 break;
988 case '\n':
989 ConBuffer_AddLine(&con, buf, bufpos, mask);
990 bufpos = 0;
991 break;
992 default:
993 buf[bufpos++] = *txt;
994 if(bufpos >= con.textsize - 1) // FIXME uses a non-abstracted property of con
995 {
996 ConBuffer_AddLine(&con, buf, bufpos, mask);
997 bufpos = 0;
998 }
999 break;
1000 }
1001 }
1002}
1003
1004void Con_Rcon_Redirect_Init(lhnetsocket_t *sock, lhnetaddress_t *dest, qbool proquakeprotocol)
1005{
1006 rcon_redirect_sock = sock;
1007 rcon_redirect_dest = dest;
1008 rcon_redirect_proquakeprotocol = proquakeprotocol;
1010 {
1011 // reserve space for the packet header
1012 rcon_redirect_buffer[0] = 0;
1013 rcon_redirect_buffer[1] = 0;
1014 rcon_redirect_buffer[2] = 0;
1015 rcon_redirect_buffer[3] = 0;
1016 // this is a reply to a CCREQ_RCON
1017 rcon_redirect_buffer[4] = (unsigned char)CCREP_RCON;
1018 }
1019 else
1020 memcpy(rcon_redirect_buffer, "\377\377\377\377n", 5); // QW rcon print
1022}
1023
1025{
1027 {
1030 {
1031 // update the length in the packet header
1033 }
1035 }
1036 memcpy(rcon_redirect_buffer, "\377\377\377\377n", 5); // QW rcon print
1039}
1040
1047
1053
1054/*
1055================
1056Con_Rcon_AddChar
1057================
1058*/
1060static void Con_Rcon_AddChar(int c)
1061{
1063 return;
1065
1066 // if this print is in response to an rcon command, add the character
1067 // to the rcon redirect buffer
1068
1070 {
1072 if(rcon_redirect_bufferpos >= (int)sizeof(rcon_redirect_buffer) - 1)
1074 }
1075 else if(*log_dest_udp.string) // don't duplicate rcon command responses here, these are sent another way
1076 {
1077 if(log_dest_buffer_pos == 0)
1080 if(log_dest_buffer_pos >= sizeof(log_dest_buffer) - 1) // minus one, to allow for terminating zero
1082 }
1083 else
1085
1087}
1088
1099static char Sys_Con_NearestColor(const unsigned char _r, const unsigned char _g, const unsigned char _b)
1100{
1101 float r = ((float)_r)/255.0;
1102 float g = ((float)_g)/255.0;
1103 float b = ((float)_b)/255.0;
1104 float min = min(r, min(g, b));
1105 float max = max(r, max(g, b));
1106
1107 int h;
1108 float s;
1109 float v = max;
1110
1111 if(max == min)
1112 s = 0;
1113 else
1114 s = 1.0 - (min/max);
1115
1116 // Saturation threshold. We now say 0.2 is the minimum value for a color!
1117 if(s < 0.2)
1118 {
1119 // If the value is less than half, return a black color code.
1120 // Otherwise return a white one.
1121 if(v < 0.5)
1122 return '0';
1123 return '7';
1124 }
1125
1126 // Let's get the hue angle to define some colors:
1127 if(max == min)
1128 h = 0;
1129 else if(max == r)
1130 h = (int)(60.0 * (g-b)/(max-min))%360;
1131 else if(max == g)
1132 h = (int)(60.0 * (b-r)/(max-min) + 120);
1133 else // if(max == b) redundant check
1134 h = (int)(60.0 * (r-g)/(max-min) + 240);
1135
1136 if(h < 36) // *red* to orange
1137 return '1';
1138 else if(h < 80) // orange over *yellow* to evilish-bright-green
1139 return '3';
1140 else if(h < 150) // evilish-bright-green over *green* to ugly bright blue
1141 return '2';
1142 else if(h < 200) // ugly bright blue over *bright blue* to darkish blue
1143 return '5';
1144 else if(h < 270) // darkish blue over *dark blue* to cool purple
1145 return '4';
1146 else if(h < 330) // cool purple over *purple* to ugly swiny red
1147 return '6';
1148 else // ugly red to red closes the circly
1149 return '1';
1150}
1151
1152/*
1153================
1154Con_MaskPrint
1155================
1156*/
1157extern cvar_t timestamps;
1158extern cvar_t timeformat;
1159extern cvar_t r_textcontrast;
1161void Con_MaskPrint(unsigned additionalmask, const char *msg)
1162{
1163 static unsigned mask = 0;
1164 static unsigned index = 0;
1165 static char line[MAX_INPUTLINE];
1166
1167 if (con_mutex)
1169
1170 for (;*msg;msg++)
1171 {
1172 Con_Rcon_AddChar(*msg);
1173 // if this is the beginning of a new line, print timestamp
1174 if (index == 0)
1175 {
1176 // reset the color
1177 // FIXME: 1. perhaps we should use a terminal system 2. use a constant instead of 7!
1178 line[index++] = STRING_COLOR_TAG;
1179 // assert( STRING_COLOR_DEFAULT < 10 )
1180 line[index++] = STRING_COLOR_DEFAULT + '0';
1181 // special color codes for chat messages must always come first
1182 // for Con_PrintToHistory to work properly
1183 if (*msg == 1 || *msg == 2 || *msg == 3)
1184 {
1185 // play talk wav
1186 if (*msg == 1)
1187 {
1188 if (con_chatsound.value)
1189 {
1192 else
1194 }
1195 }
1196 // Send to chatbox for say/tell (1) and messages (3)
1197 // 3 is just so that a message can be sent to the chatbox without a sound.
1198 if (*msg == 1 || *msg == 3)
1200
1201 line[index++] = STRING_COLOR_TAG;
1202 line[index++] = '3';
1203 msg++;
1204 Con_Rcon_AddChar(*msg);
1205 }
1206 // store timestamp
1207 if (timestamps.integer)
1208 index += Sys_TimeString(&line[index], sizeof(line) - index, timeformat.string);
1209 // add the mask
1210 mask |= additionalmask;
1211 }
1212 // append the character
1213 line[index++] = *msg;
1214 // if this is a newline character, we have a complete line to print
1215 // bones_was_here: why do we only use half the line buffer?
1216 if (*msg == '\n' || index >= (int)sizeof(line) / 2)
1217 {
1218 // terminate the line
1219 line[index] = 0;
1220 // send to log file
1221 Log_ConPrint(line);
1222 // send to scrollable buffer
1224 {
1225 Con_PrintToHistory(line, mask);
1226 }
1227 // send to terminal or dedicated server window
1228 if (sys.outfd >= 0)
1230 {
1232 {
1233 char *p;
1234 const char *q;
1235 p = line;
1236 while(*p)
1237 {
1238 int ch = u8_getchar(p, &q);
1239 if(ch >= 0xE000 && ch <= 0xE0FF && ((unsigned char) qfont_table[ch - 0xE000]) >= 0x20)
1240 {
1241 *p = qfont_table[ch - 0xE000];
1242 if(q > p+1)
1243 memmove(p+1, q, strlen(q)+1);
1244 p = p + 1;
1245 }
1246 else
1247 p = p + (q - p);
1248 }
1249 }
1250
1251 if(sys_colortranslation.integer > 0) // ANSI, RGB, or both
1252 {
1253 // ANSI translation:
1254 // 2 can become 7 bytes, rounding that up to 8, and 3 bytes are added at the end
1255 // a newline can transform into four bytes, but then prevents the three extra bytes from appearing
1256 // 8bpc RGB brings new worst-cases:
1257 // 5 can become 21 bytes, rounding that up to * 5, plenty of space for extra bytes at the end.
1258 // sys_colortranslation 3: 2 can become 21 bytes, rounding that up to * 11
1259 char printline[sizeof(line) * 11];
1260 int lastcolor = 0;
1261 const char *in;
1262 char *out;
1263 int color;
1264 u8 rgb[3];
1265 for(in = line, out = printline; *in; ++in)
1266 {
1267 switch(*in)
1268 {
1269 case STRING_COLOR_TAG:
1270 if( in[1] == STRING_COLOR_RGB_TAG_CHAR && isxdigit(in[2]) && isxdigit(in[3]) && isxdigit(in[4]) )
1271 {
1272 VectorCopy(in + 2, rgb);
1273 // it's a hex digit already, so the else part needs no check --blub
1274 for (int i = 0; i < 3; ++i)
1275 {
1276 if (isdigit(rgb[i])) rgb[i] -= '0';
1277 else rgb[i] = tolower(rgb[i]) - 87;
1278 rgb[i] *= 17;
1279 }
1280
1281 if (sys_colortranslation.integer > 1) // 8bpc RGB
1282 {
1283 char *p;
1284 float B;
1285
1286 in += 4;
1287 rgbout:
1288 color = rgb[0]<<16 | rgb[1]<<8 | rgb[2] | /* disambiguates from quake colours */ 0x40000000;
1289 if (lastcolor == color)
1290 break;
1291 else
1292 lastcolor = color;
1293
1294 B = r_textbrightness.value * 255;
1295 for (int i = 0; i < 3; ++i)
1296 rgb[i] = bound(0, rgb[i] * r_textcontrast.value + B, 255);
1297
1298 // format must be decimal 0-255, max length is 21 bytes
1300 memcpy(out, "\x1B[1;38;2", 8);
1301 else
1302 memcpy(out, "\x1B[0;38;2", 8);
1303 out += 8;
1304 for (int i = 0; i < 3; ++i)
1305 {
1306 *out++ = ';';
1307 p = out += ((rgb[i] > 99) ? 3 : (rgb[i] > 9) ? 2 : 1);
1308 do { *--p = (rgb[i] % 10) + '0';
1309 } while ((rgb[i] /= 10) > 0);
1310 }
1311 *out++ = 'm';
1312
1313 break;
1314 }
1315
1316 color = Sys_Con_NearestColor(rgb[0], rgb[1], rgb[2]);
1317 in += 3; // 3 only, the switch down there does the fourth
1318 }
1319 else
1320 {
1321 color = in[1];
1322
1323 if (sys_colortranslation.integer == 3 && isdigit(color)) // Quake to RGB
1324 {
1325 color -= '0';
1327 ++in;
1328 goto rgbout;
1329 }
1330 }
1331
1332 switch(color)
1333 {
1334 case STRING_COLOR_TAG:
1335 ++in;
1336 *out++ = STRING_COLOR_TAG;
1337 break;
1338 case '0':
1339 case '7':
1340 // normal color
1341 ++in;
1342 if(lastcolor == 0) break; else lastcolor = 0;
1343 *out++ = 0x1B; *out++ = '['; *out++ = 'm';
1344 break;
1345 case '1':
1346 // light red
1347 ++in;
1348 if(lastcolor == 1) break; else lastcolor = 1;
1349 *out++ = 0x1B; *out++ = '['; *out++ = '1'; *out++ = ';'; *out++ = '3'; *out++ = '1'; *out++ = 'm';
1350 break;
1351 case '2':
1352 // light green
1353 ++in;
1354 if(lastcolor == 2) break; else lastcolor = 2;
1355 *out++ = 0x1B; *out++ = '['; *out++ = '1'; *out++ = ';'; *out++ = '3'; *out++ = '2'; *out++ = 'm';
1356 break;
1357 case '3':
1358 // yellow
1359 ++in;
1360 if(lastcolor == 3) break; else lastcolor = 3;
1361 *out++ = 0x1B; *out++ = '['; *out++ = '1'; *out++ = ';'; *out++ = '3'; *out++ = '3'; *out++ = 'm';
1362 break;
1363 case '4':
1364 // light blue
1365 ++in;
1366 if(lastcolor == 4) break; else lastcolor = 4;
1367 *out++ = 0x1B; *out++ = '['; *out++ = '1'; *out++ = ';'; *out++ = '3'; *out++ = '4'; *out++ = 'm';
1368 break;
1369 case '5':
1370 // light cyan
1371 ++in;
1372 if(lastcolor == 5) break; else lastcolor = 5;
1373 *out++ = 0x1B; *out++ = '['; *out++ = '1'; *out++ = ';'; *out++ = '3'; *out++ = '6'; *out++ = 'm';
1374 break;
1375 case '6':
1376 // light magenta
1377 ++in;
1378 if(lastcolor == 6) break; else lastcolor = 6;
1379 *out++ = 0x1B; *out++ = '['; *out++ = '1'; *out++ = ';'; *out++ = '3'; *out++ = '5'; *out++ = 'm';
1380 break;
1381 // 7 handled above
1382 case '8':
1383 case '9':
1384 // bold normal color
1385 ++in;
1386 if(lastcolor == 8) break; else lastcolor = 8;
1387 *out++ = 0x1B; *out++ = '['; *out++ = '0'; *out++ = ';'; *out++ = '1'; *out++ = 'm';
1388 break;
1389 default:
1390 *out++ = STRING_COLOR_TAG;
1391 break;
1392 }
1393 break;
1394 case '\n':
1395 if(lastcolor != 0)
1396 {
1397 *out++ = 0x1B; *out++ = '['; *out++ = 'm';
1398 lastcolor = 0;
1399 }
1400 *out++ = *in;
1401 break;
1402 default:
1403 *out++ = *in;
1404 break;
1405 }
1406 }
1407 if(lastcolor != 0)
1408 {
1409 *out++ = 0x1B;
1410 *out++ = '[';
1411 *out++ = 'm';
1412 }
1413 *out = '\0';
1414 Sys_Print(printline, out - printline);
1415 }
1416 else if(sys_colortranslation.integer == -1) // print as text
1417 {
1418 Sys_Print(line, index);
1419 }
1420 else // strip
1421 {
1422 char printline[MAX_INPUTLINE]; // it can only get shorter here
1423 const char *in;
1424 char *out;
1425 for(in = line, out = printline; *in; ++in)
1426 {
1427 switch(*in)
1428 {
1429 case STRING_COLOR_TAG:
1430 switch(in[1])
1431 {
1433 if ( isxdigit(in[2]) && isxdigit(in[3]) && isxdigit(in[4]) )
1434 {
1435 in+=4;
1436 break;
1437 }
1438 *out++ = STRING_COLOR_TAG;
1440 ++in;
1441 break;
1442 case STRING_COLOR_TAG:
1443 ++in;
1444 *out++ = STRING_COLOR_TAG;
1445 break;
1446 case '0':
1447 case '1':
1448 case '2':
1449 case '3':
1450 case '4':
1451 case '5':
1452 case '6':
1453 case '7':
1454 case '8':
1455 case '9':
1456 ++in;
1457 break;
1458 default:
1459 *out++ = STRING_COLOR_TAG;
1460 break;
1461 }
1462 break;
1463 default:
1464 *out++ = *in;
1465 break;
1466 }
1467 }
1468 *out = '\0';
1469 Sys_Print(printline, out - printline);
1470 }
1471 }
1472 // empty the line buffer
1473 index = 0;
1474 mask = 0;
1475 }
1476 }
1477
1478 if (con_mutex)
1480}
1481
1482/*
1483================
1484Con_MaskPrintf
1485================
1486*/
1487void Con_MaskPrintf(unsigned mask, const char *fmt, ...)
1488{
1489 va_list argptr;
1490 char msg[MAX_INPUTLINE];
1491
1492 va_start(argptr,fmt);
1493 dpvsnprintf(msg,sizeof(msg),fmt,argptr);
1494 va_end(argptr);
1495
1496 Con_MaskPrint(mask, msg);
1497}
1498
1499/*
1500================
1501Con_Print
1502================
1503*/
1504void Con_Print(const char *msg)
1505{
1507}
1508
1509/*
1510================
1511Con_Printf
1512================
1513*/
1514void Con_Printf(const char *fmt, ...)
1515{
1516 va_list argptr;
1517 char msg[MAX_INPUTLINE];
1518
1519 va_start(argptr,fmt);
1520 dpvsnprintf(msg,sizeof(msg),fmt,argptr);
1521 va_end(argptr);
1522
1524}
1525
1526/*
1527================
1528Con_DPrint
1529================
1530*/
1531void Con_DPrint(const char *msg)
1532{
1533 if(developer.integer < 0) // at 0, we still add to the buffer but hide
1534 return;
1535
1537}
1538
1539/*
1540================
1541Con_DPrintf
1542================
1543*/
1544void Con_DPrintf(const char *fmt, ...)
1545{
1546 va_list argptr;
1547 char msg[MAX_INPUTLINE];
1548
1549 if(developer.integer < 0) // at 0, we still add to the buffer but hide
1550 return;
1551
1552 va_start(argptr,fmt);
1553 dpvsnprintf(msg,sizeof(msg),fmt,argptr);
1554 va_end(argptr);
1555
1557}
1558
1559
1570const char *Con_Quakebar(int len, char *bar, size_t barsize)
1571{
1572 assert(barsize >= 5);
1573
1574 len = min(len, (int)barsize - 2);
1575 len = min(len, con_linewidth);
1576
1577 bar[0] = '\35';
1578 memset(&bar[1], '\36', len - 2);
1579 bar[len - 1] = '\37';
1580
1581 if (len < con_linewidth)
1582 {
1583 bar[len] = '\n';
1584 bar[len + 1] = 0;
1585 }
1586 else
1587 bar[len] = 0;
1588
1589 return bar;
1590}
1591
1600void Con_CenterPrintf(int maxLineLength, const char *fmt, ...)
1601{
1602 va_list argptr;
1603 char msg[MAX_INPUTLINE]; // the original message
1604 char spaces[21]; // buffer for spaces
1605 char *msgCursor, *lineEnding;
1606 int lineLength, msgLength;
1607 size_t indentSize;
1608
1609 va_start(argptr, fmt);
1610 msgLength = dpvsnprintf(msg, sizeof (msg), fmt, argptr);
1611 va_end(argptr);
1612
1613 if (msgLength < 0)
1614 {
1615 Con_Printf(CON_WARN "The message given to Con_CenterPrintf was too long\n");
1616 return;
1617 }
1618
1619 maxLineLength = min(maxLineLength, con_linewidth);
1620
1621 for (msgCursor = msg; *msgCursor;)
1622 {
1623 lineEnding = strchr(msgCursor, '\n');
1624 if (lineEnding)
1625 {
1626 lineLength = lineEnding - msgCursor; // print just the line
1627 lineEnding++; // set cursor to next character after new line
1628 }
1629 else // last line
1630 {
1631 lineLength = msgLength; // print entire message
1632 lineEnding = msgCursor + lineLength; // set next line cursor to terminator
1633 }
1634
1635 if (lineLength < maxLineLength)
1636 {
1637 indentSize = min(sizeof(spaces) - 1, (size_t)(maxLineLength - lineLength) / 2);
1638 memset(spaces, ' ', indentSize);
1639 spaces[indentSize] = 0;
1640 Con_MaskPrintf(CON_MASK_HIDENOTIFY, "%s%.*s\n", spaces, lineLength, msgCursor);
1641 }
1642 else
1643 Con_MaskPrintf(CON_MASK_HIDENOTIFY, "%.*s\n", lineLength, msgCursor);
1644 msgLength -= lineEnding - msgCursor; // Consume all characters until end of line
1645 msgCursor = lineEnding; // Update message cursor
1646 }
1647}
1648
1655void Con_CenterPrint(const char *str)
1656{
1657 char bar[42];
1658
1659 Con_MaskPrintf(CON_MASK_HIDENOTIFY, "%s", Con_Quakebar(40, bar, sizeof(bar)));
1660 Con_CenterPrintf(40, "%s\n", str);
1662}
1663
1664
1665
1666/*
1667==============================================================================
1668
1669DRAWING
1670
1671==============================================================================
1672*/
1673
1674/*
1675================
1676Con_DrawInput
1677
1678It draws either the console input line or the chat input line (if is_console is false)
1679The input line scrolls horizontally if typing goes beyond the right edge
1680
1681Modified by EvilTypeGuy eviltypeguy@qeradiant.com
1682================
1683*/
1684static void Con_DrawInput(qbool is_console, float x, float v, float inputsize)
1685{
1686 int y, i, col_out, linepos, text_start, prefix_start = 0;
1687 char text[MAX_INPUTLINE + 5 + 9 + 1]; // space for ^xRGB, "say_team:" and \0
1688 float xo;
1689 size_t len_out;
1690 const char *prefix;
1691 dp_font_t *fnt;
1692
1693 if (is_console && !key_consoleactive)
1694 return; // don't draw anything
1695
1696 if (is_console)
1697 {
1698 // empty prefix because ] is part of the console edit line
1699 prefix = "";
1700 dp_strlcpy(text, key_line, sizeof(text));
1701 linepos = key_linepos;
1702 fnt = FONT_CONSOLE;
1703 }
1704 else
1705 {
1706 if (chat_mode < 0)
1707 prefix = "]";
1708 else if(chat_mode)
1709 prefix = "say_team:";
1710 else
1711 prefix = "say:";
1712 dp_strlcpy(text, chat_buffer, sizeof(text));
1713 linepos = chat_bufferpos;
1714 fnt = FONT_CHAT;
1715 }
1716
1717 y = (int)strlen(text);
1718
1719 // make the color code visible when the cursor is inside it
1720 if(text[linepos] != 0)
1721 {
1722 for(i=1; i < 5 && linepos - i > 0; ++i)
1723 if(text[linepos-i] == STRING_COLOR_TAG)
1724 {
1725 int caret_pos, ofs = 0;
1726 caret_pos = linepos - i;
1727 if(i == 1 && text[caret_pos+1] == STRING_COLOR_TAG)
1728 ofs = 1;
1729 else if(i == 1 && isdigit(text[caret_pos+1]))
1730 ofs = 2;
1731 else if(text[caret_pos+1] == STRING_COLOR_RGB_TAG_CHAR && isxdigit(text[caret_pos+2]) && isxdigit(text[caret_pos+3]) && isxdigit(text[caret_pos+4]))
1732 ofs = 5;
1733 if(ofs && (size_t)(y + ofs + 1) < sizeof(text))
1734 {
1735 int carets = 1;
1736 while(caret_pos - carets >= 1 && text[caret_pos - carets] == STRING_COLOR_TAG)
1737 ++carets;
1738 if(carets & 1)
1739 {
1740 // str^2ing (displayed as string) --> str^2^^2ing (displayed as str^2ing)
1741 // str^^ing (displayed as str^ing) --> str^^^^ing (displayed as str^^ing)
1742 memmove(&text[caret_pos + ofs + 1], &text[caret_pos], y - caret_pos);
1743 text[caret_pos + ofs] = STRING_COLOR_TAG;
1744 y += ofs + 1;
1745 text[y] = 0;
1746 }
1747 }
1748 break;
1749 }
1750 }
1751
1752 if (!is_console)
1753 {
1754 prefix_start = x;
1755 x += DrawQ_TextWidth(prefix, 0, inputsize, inputsize, false, fnt);
1756 }
1757
1758 len_out = linepos;
1759 col_out = -1;
1760 xo = 0;
1761 if (linepos > 0)
1762 xo = DrawQ_TextWidth_UntilWidth_TrackColors(text, &len_out, inputsize, inputsize, &col_out, false, fnt, 1000000000);
1763
1764 text_start = x + (vid_conwidth.value - x) * 0.95 - xo; // scroll
1765 if(text_start >= x)
1766 text_start = x;
1767 else if (!is_console)
1768 prefix_start -= (x - text_start);
1769
1770 if (!is_console)
1771 DrawQ_String(prefix_start, v, prefix, 0, inputsize, inputsize, 1.0, 1.0, 1.0, 1.0, 0, NULL, false, fnt);
1772
1773 DrawQ_String(text_start, v, text, y + 3, inputsize, inputsize, 1.0, 1.0, 1.0, 1.0, 0, NULL, false, fnt);
1774
1775 // draw a cursor on top of this
1776 if ((int)(host.realtime*con_cursorspeed) & 1) // cursor is visible
1777 {
1778 if (!utf8_enable.integer)
1779 {
1780 text[0] = 11 + 130 * key_insert; // either solid or triangle facing right
1781 text[1] = 0;
1782 }
1783 else
1784 {
1785 size_t len;
1786 const char *curbuf;
1787 char charbuf16[16];
1788 curbuf = u8_encodech(0xE000 + 11 + 130 * key_insert, &len, charbuf16);
1789 memcpy(text, curbuf, len);
1790 text[len] = 0;
1791 }
1792 DrawQ_String(text_start + xo, v, text, 0, inputsize, inputsize, 1.0, 1.0, 1.0, 1.0, 0, &col_out, false, fnt);
1793 }
1794}
1795
1796typedef struct
1797{
1799 float alignment; // 0 = left, 0.5 = center, 1 = right
1801 float x;
1802 float y;
1803 float width;
1804 float ymin, ymax;
1806
1807 // PRIVATE:
1808 int colorindex; // init to -1
1809}
1811
1812static float Con_WordWidthFunc(void *passthrough, const char *w, size_t *length, float maxWidth)
1813{
1814 con_text_info_t *ti = (con_text_info_t *) passthrough;
1815 if(w == NULL)
1816 {
1817 ti->colorindex = -1;
1818 return ti->fontsize * ti->font->maxwidth;
1819 }
1820 if(maxWidth >= 0)
1821 return DrawQ_TextWidth_UntilWidth(w, length, ti->fontsize, ti->fontsize, false, ti->font, -maxWidth); // -maxWidth: we want at least one char
1822 else if(maxWidth == -1)
1823 return DrawQ_TextWidth(w, *length, ti->fontsize, ti->fontsize, false, ti->font);
1824 else
1825 {
1826 Sys_Printf("Con_WordWidthFunc: can't get here (maxWidth should never be %f)\n", maxWidth);
1827 // Note: this is NOT a Con_Printf, as it could print recursively
1828 return 0;
1829 }
1830}
1831
1832static int Con_CountLineFunc(void *passthrough, const char *line, size_t length, float width, qbool isContinuation)
1833{
1834 (void) passthrough;
1835 (void) line;
1836 (void) length;
1837 (void) width;
1838 (void) isContinuation;
1839 return 1;
1840}
1841
1842static int Con_DisplayLineFunc(void *passthrough, const char *line, size_t length, float width, qbool isContinuation)
1843{
1844 con_text_info_t *ti = (con_text_info_t *) passthrough;
1845
1846 if(ti->y < ti->ymin - 0.001)
1847 (void) 0;
1848 else if(ti->y > ti->ymax - ti->fontsize + 0.001)
1849 (void) 0;
1850 else
1851 {
1852 int x = (int) (ti->x + (ti->width - width) * ti->alignment);
1853 if(isContinuation && *ti->continuationString)
1854 x = (int) DrawQ_String(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);
1855 if(length > 0)
1856 DrawQ_String(x, ti->y, line, length, ti->fontsize, ti->fontsize, 1.0, 1.0, 1.0, 1.0, 0, &(ti->colorindex), false, ti->font);
1857 }
1858
1859 ti->y += ti->fontsize;
1860 return 1;
1861}
1862
1863static int Con_DrawNotifyRect(unsigned mask_must, unsigned mask_mustnot, float maxage, float x, float y, float width, float height, float fontsize, float alignment_x, float alignment_y, const char *continuationString)
1864{
1865 int i;
1866 int lines = 0;
1867 int maxlines = (int) floor(height / fontsize + 0.01f);
1868 int startidx;
1869 int nskip = 0;
1870 int continuationWidth = 0;
1871 size_t len;
1872 double t = cl.time; // saved so it won't change
1873 con_text_info_t ti;
1874
1875 ti.font = (mask_must & CON_MASK_CHAT) ? FONT_CHAT : FONT_NOTIFY;
1876 ti.fontsize = fontsize;
1877 ti.alignment = alignment_x;
1878 ti.width = width;
1879 ti.ymin = y;
1880 ti.ymax = y + height;
1881 ti.continuationString = continuationString;
1882
1883 len = 0;
1884 Con_WordWidthFunc(&ti, NULL, &len, -1);
1885 len = strlen(continuationString);
1886 continuationWidth = (int) Con_WordWidthFunc(&ti, continuationString, &len, -1);
1887
1888 // first find the first line to draw by backwards iterating and word wrapping to find their length...
1889 startidx = CON_LINES_COUNT;
1890 for(i = CON_LINES_COUNT - 1; i >= 0; --i)
1891 {
1892 con_lineinfo_t *l = &CON_LINES(i);
1893 int mylines;
1894
1895 if((l->mask & mask_must) != mask_must)
1896 continue;
1897 if(l->mask & mask_mustnot)
1898 continue;
1899 if(maxage && (l->addtime < t - maxage))
1900 continue;
1901
1902 // WE FOUND ONE!
1903 // Calculate its actual height...
1904 mylines = COM_Wordwrap(l->start, l->len, continuationWidth, width, Con_WordWidthFunc, &ti, Con_CountLineFunc, &ti);
1905 if(lines + mylines >= maxlines)
1906 {
1907 nskip = lines + mylines - maxlines;
1908 lines = maxlines;
1909 startidx = i;
1910 break;
1911 }
1912 lines += mylines;
1913 startidx = i;
1914 }
1915
1916 // then center according to the calculated amount of lines...
1917 ti.x = x;
1918 ti.y = y + alignment_y * (height - lines * fontsize) - nskip * fontsize;
1919
1920 // then actually draw
1921 for(i = startidx; i < CON_LINES_COUNT; ++i)
1922 {
1923 con_lineinfo_t *l = &CON_LINES(i);
1924
1925 if((l->mask & mask_must) != mask_must)
1926 continue;
1927 if(l->mask & mask_mustnot)
1928 continue;
1929 if(maxage && (l->addtime < t - maxage))
1930 continue;
1931
1932 COM_Wordwrap(l->start, l->len, continuationWidth, width, Con_WordWidthFunc, &ti, Con_DisplayLineFunc, &ti);
1933 }
1934
1935 return lines;
1936}
1937
1938/*
1939================
1940Con_DrawNotify
1941
1942Draws the last few lines of output transparently over the game top
1943================
1944*/
1946{
1947 float x, v;
1948 float chatstart, notifystart, inputsize, height;
1949 float align;
1950 int numChatlines;
1951 int chatpos;
1952
1955
1956 numChatlines = con_chat.integer;
1957
1958 chatpos = con_chatpos.integer;
1959
1960 if (con_notify.integer < 0)
1963 v = 8; // vertical offset
1964 else
1965 v = 0;
1966
1967 // GAME_NEXUIZ: center, otherwise left justify
1968 align = con_notifyalign.value;
1969 if(!*con_notifyalign.string) // empty string, evaluated to 0 above
1970 {
1972 align = 0.5;
1973 }
1974
1975 if(numChatlines || !con_chatrect.integer)
1976 {
1977 if(chatpos == 0)
1978 {
1979 // first chat, input line, then notify
1980 chatstart = v;
1981 notifystart = v + (numChatlines + 1) * con_chatsize.value;
1982 }
1983 else if(chatpos > 0)
1984 {
1985 // first notify, then (chatpos-1) empty lines, then chat, then input
1986 notifystart = v;
1987 chatstart = v + (con_notify.value + (chatpos - 1)) * con_notifysize.value;
1988 }
1989 else // if(chatpos < 0)
1990 {
1991 // first notify, then much space, then chat, then input, then -chatpos-1 empty lines
1992 notifystart = v;
1993 chatstart = vid_conheight.value - (-chatpos-1 + numChatlines + 1) * con_chatsize.value;
1994 }
1995 }
1996 else
1997 {
1998 // just notify and input
1999 notifystart = v;
2000 chatstart = 0; // shut off gcc warning
2001 }
2002
2004
2006 {
2009 }
2010 else
2011 {
2012 x = 0;
2013 if(numChatlines) // only do this if chat area is enabled, or this would move the input line wrong
2014 v = chatstart;
2015 }
2016 height = numChatlines * con_chatsize.value;
2017
2018 if(numChatlines)
2019 {
2021 v += height;
2022 }
2023 if (key_dest == key_message)
2024 {
2025 inputsize = (numChatlines ? con_chatsize : con_notifysize).value;
2026 Con_DrawInput(false, x, v, inputsize);
2027 }
2028 else
2029 chat_bufferpos = 0;
2030
2032}
2033
2034/*
2035================
2036Con_LineHeight
2037
2038Returns the height of a given console line; calculates it if necessary.
2039================
2040*/
2041static int Con_LineHeight(int lineno)
2042{
2043 con_lineinfo_t *li = &CON_LINES(lineno);
2044 if(li->height == -1)
2045 {
2046 float width = vid_conwidth.value;
2047 con_text_info_t ti;
2049 ti.font = FONT_CONSOLE;
2051 }
2052 return li->height;
2053}
2054
2055/*
2056================
2057Con_DrawConsoleLine
2058
2059Draws a line of the console; returns its height in lines.
2060If alpha is 0, the line is not drawn, but still wrapped and its height
2061returned.
2062================
2063*/
2064static int Con_DrawConsoleLine(unsigned mask_must, unsigned mask_mustnot, float y, int lineno, float ymin, float ymax)
2065{
2066 float width = vid_conwidth.value;
2067 con_text_info_t ti;
2068 con_lineinfo_t *li = &CON_LINES(lineno);
2069
2070 if((li->mask & mask_must) != mask_must)
2071 return 0;
2072 if((li->mask & mask_mustnot) != 0)
2073 return 0;
2074
2075 ti.continuationString = "";
2076 ti.alignment = 0;
2078 ti.font = FONT_CONSOLE;
2079 ti.x = 0;
2080 ti.y = y - (Con_LineHeight(lineno) - 1) * ti.fontsize;
2081 ti.ymin = ymin;
2082 ti.ymax = ymax;
2083 ti.width = width;
2084
2085 return COM_Wordwrap(li->start, li->len, 0, width, Con_WordWidthFunc, &ti, Con_DisplayLineFunc, &ti);
2086}
2087
2088/*
2089================
2090Con_LastVisibleLine
2091
2092Calculates the last visible line index and how much to show of it based on
2093con_backscroll.
2094================
2095*/
2096static void Con_LastVisibleLine(unsigned mask_must, unsigned mask_mustnot, int *last, int *limitlast)
2097{
2098 int lines_seen = 0;
2099 int i;
2100
2101 if(con_backscroll < 0)
2102 con_backscroll = 0;
2103
2104 *last = 0;
2105
2106 // now count until we saw con_backscroll actual lines
2107 for(i = CON_LINES_COUNT - 1; i >= 0; --i)
2108 if((CON_LINES(i).mask & mask_must) == mask_must)
2109 if((CON_LINES(i).mask & mask_mustnot) == 0)
2110 {
2111 int h = Con_LineHeight(i);
2112
2113 // line is the last visible line?
2114 *last = i;
2115 if(lines_seen + h > con_backscroll && lines_seen <= con_backscroll)
2116 {
2117 *limitlast = lines_seen + h - con_backscroll;
2118 return;
2119 }
2120
2121 lines_seen += h;
2122 }
2123
2124 // if we get here, no line was on screen - scroll so that one line is
2125 // visible then.
2126 con_backscroll = lines_seen - 1;
2127 *limitlast = 1;
2128}
2129
2130/*
2131================
2132Con_DrawConsole
2133
2134Draws the console with the solid background
2135The typing input line at the bottom should only be drawn if typing is allowed
2136================
2137*/
2138void Con_DrawConsole (int lines, qbool forcedfullscreen)
2139{
2140 float alpha, alpha0;
2141 double sx, sy;
2142 int mask_must = 0;
2143 int mask_mustnot = (developer.integer>0) ? 0 : CON_MASK_DEVELOPER;
2144 cachepic_t *conbackpic;
2145 unsigned int conbackflags;
2146
2147 if (lines <= 0)
2148 return;
2149
2151
2152 if (con_backscroll < 0)
2153 con_backscroll = 0;
2154
2155 con_vislines = lines;
2156
2157 r_draw2d_force = true;
2158
2159// draw the background
2160 alpha0 = forcedfullscreen ? 1.0f : scr_conalpha.value; // always full alpha when not forced fullscreen
2161 if((alpha = alpha0 * scr_conalphafactor.value) > 0)
2162 {
2165 conbackflags = CACHEPICFLAG_FAILONMISSING; // So console is readable when game content is missing
2166 if (sx != 0 || sy != 0)
2167 conbackflags &= CACHEPICFLAG_NOCLAMP;
2168 conbackpic = scr_conbrightness.value >= 0.01f ? Draw_CachePic_Flags("gfx/conback", conbackflags) : NULL;
2169 sx *= host.realtime; sy *= host.realtime;
2170 sx -= floor(sx); sy -= floor(sy);
2171 if (Draw_IsPicLoaded(conbackpic))
2177 0);
2178 else
2179 DrawQ_Fill(0, lines - vid_conheight.integer, vid_conwidth.integer, vid_conheight.integer, 0.0f, 0.0f, 0.0f, alpha, 0);
2180 }
2181 if((alpha = alpha0 * scr_conalpha2factor.value) > 0)
2182 {
2185 conbackpic = Draw_CachePic_Flags("gfx/conback2", (sx != 0 || sy != 0) ? CACHEPICFLAG_NOCLAMP : 0);
2186 sx *= host.realtime; sy *= host.realtime;
2187 sx -= floor(sx); sy -= floor(sy);
2188 if(Draw_IsPicLoaded(conbackpic))
2194 0);
2195 }
2196 if((alpha = alpha0 * scr_conalpha3factor.value) > 0)
2197 {
2200 conbackpic = Draw_CachePic_Flags("gfx/conback3", (sx != 0 || sy != 0) ? CACHEPICFLAG_NOCLAMP : 0);
2201 sx *= host.realtime; sy *= host.realtime;
2202 sx -= floor(sx); sy -= floor(sy);
2203 if(Draw_IsPicLoaded(conbackpic))
2209 0);
2210 }
2212
2213// draw the text
2214#if 0
2215 {
2216 int i;
2217 int count = CON_LINES_COUNT;
2218 float ymax = con_vislines - 2 * con_textsize.value;
2219 float y = ymax + con_textsize.value * con_backscroll;
2220 for (i = 0;i < count && y >= 0;i++)
2221 y -= Con_DrawConsoleLine(mask_must, mask_mustnot, y - con_textsize.value, CON_LINES_COUNT - 1 - i, 0, ymax) * con_textsize.value;
2222 // fix any excessive scrollback for the next frame
2223 if (i >= count && y >= 0)
2224 {
2226 if (con_backscroll < 0)
2227 con_backscroll = 0;
2228 }
2229 }
2230#else
2231 if(CON_LINES_COUNT > 0)
2232 {
2233 int i, last, limitlast;
2234 float y;
2235 float ymax = con_vislines - 2 * con_textsize.value;
2236 Con_LastVisibleLine(mask_must, mask_mustnot, &last, &limitlast);
2237 //Con_LastVisibleLine(mask_must, mask_mustnot, &last, &limitlast);
2238 y = ymax - con_textsize.value;
2239
2240 if(limitlast)
2241 y += (CON_LINES(last).height - limitlast) * con_textsize.value;
2242 i = last;
2243
2244 for(;;)
2245 {
2246 y -= Con_DrawConsoleLine(mask_must, mask_mustnot, y, i, 0, ymax) * con_textsize.value;
2247 if(i == 0)
2248 break; // top of console buffer
2249 if(y < 0)
2250 break; // top of console window
2251 limitlast = 0;
2252 --i;
2253 }
2254 }
2255#endif
2256
2257// draw the input prompt, user text, and cursor if desired
2259
2260 r_draw2d_force = false;
2262}
2263
2264/*
2265GetMapList
2266
2267Made by [515]
2268Prints not only map filename, but also
2269its format (q1/q2/q3/hl) and even its message
2270*/
2271//[515]: here is an ugly hack.. two gotos... oh my... *but it works*
2272//LadyHavoc: rewrote bsp type detection, rewrote message extraction to do proper worldspawn parsing
2273//LadyHavoc: added .ent file loading, and redesigned error handling to still try the .ent file even if the map format is not recognized, this also eliminated one goto
2274//LadyHavoc: FIXME: man this GetMapList is STILL ugly code even after my cleanups...
2275qbool GetMapList (const char *s, char *completedname, int completednamebufferlength)
2276{
2277 fssearch_t *t;
2278 char message[1024];
2279 int i, k, max, p, o, min;
2280 unsigned char *len;
2281 qfile_t *f;
2282 unsigned char buf[1024];
2283
2284 dpsnprintf(message, sizeof(message), "maps/%s*.bsp", s);
2285 t = FS_Search(message, 1, true, NULL);
2286 if(!t)
2287 return false;
2288 if (t->numfilenames > 1)
2289 Con_Printf("^1 %i maps found :\n", t->numfilenames);
2290 len = (unsigned char *)Z_Malloc(t->numfilenames);
2291 min = 666;
2292 for(max=i=0;i<t->numfilenames;i++)
2293 {
2294 k = (int)strlen(t->filenames[i]);
2295 k -= 9;
2296 if(max < k)
2297 max = k;
2298 else
2299 if(min > k)
2300 min = k;
2301 len[i] = k;
2302 }
2303 o = (int)strlen(s);
2304 for(i=0;i<t->numfilenames;i++)
2305 {
2306 int lumpofs = 0, lumplen = 0;
2307 char *entities = NULL;
2308 const char *data = NULL;
2309 char keyname[64];
2310 char entfilename[MAX_QPATH];
2311 char desc[64];
2312 desc[0] = 0;
2313 dp_strlcpy(message, "^1ERROR: open failed^7", sizeof(message));
2314 p = 0;
2315 f = FS_OpenVirtualFile(t->filenames[i], true);
2316 if(f)
2317 {
2318 dp_strlcpy(message, "^1ERROR: not a known map format^7", sizeof(message));
2319 memset(buf, 0, 1024);
2320 FS_Read(f, buf, 1024);
2321 if (!memcmp(buf, "IBSP", 4))
2322 {
2323 p = LittleLong(((int *)buf)[1]);
2324 if (p == Q3BSPVERSION || p == Q3BSPVERSION_LIVE || p == Q3BSPVERSION_IG)
2325 {
2326 q3dheader_t *header = (q3dheader_t *)buf;
2327 lumpofs = LittleLong(header->lumps[Q3LUMP_ENTITIES].fileofs);
2328 lumplen = LittleLong(header->lumps[Q3LUMP_ENTITIES].filelen);
2329 dpsnprintf(desc, sizeof(desc), "Q3BSP%i", p);
2330 }
2331 else if (p == Q2BSPVERSION)
2332 {
2333 q2dheader_t *header = (q2dheader_t *)buf;
2334 lumpofs = LittleLong(header->lumps[Q2LUMP_ENTITIES].fileofs);
2335 lumplen = LittleLong(header->lumps[Q2LUMP_ENTITIES].filelen);
2336 dpsnprintf(desc, sizeof(desc), "Q2BSP%i", p);
2337 }
2338 else
2339 dpsnprintf(desc, sizeof(desc), "IBSP%i", p);
2340 }
2341 else if (BuffLittleLong(buf) == BSPVERSION)
2342 {
2343 lumpofs = BuffLittleLong(buf + 4 + 8 * LUMP_ENTITIES);
2344 lumplen = BuffLittleLong(buf + 4 + 8 * LUMP_ENTITIES + 4);
2345 dpsnprintf(desc, sizeof(desc), "BSP29");
2346 }
2347 else if (BuffLittleLong(buf) == 30)
2348 {
2349 lumpofs = BuffLittleLong(buf + 4 + 8 * LUMP_ENTITIES);
2350 lumplen = BuffLittleLong(buf + 4 + 8 * LUMP_ENTITIES + 4);
2351 dpsnprintf(desc, sizeof(desc), "BSPHL");
2352 }
2353 else if (!memcmp(buf, "BSP2", 4))
2354 {
2355 lumpofs = BuffLittleLong(buf + 4 + 8 * LUMP_ENTITIES);
2356 lumplen = BuffLittleLong(buf + 4 + 8 * LUMP_ENTITIES + 4);
2357 dpsnprintf(desc, sizeof(desc), "BSP2");
2358 }
2359 else if (!memcmp(buf, "2PSB", 4))
2360 {
2361 lumpofs = BuffLittleLong(buf + 4 + 8 * LUMP_ENTITIES);
2362 lumplen = BuffLittleLong(buf + 4 + 8 * LUMP_ENTITIES + 4);
2363 dpsnprintf(desc, sizeof(desc), "BSP2RMQe");
2364 }
2365 else if(!memcmp(buf, "VBSP", 4))
2366 {
2367 hl2dheader_t *header = (hl2dheader_t *)buf;
2368 lumpofs = LittleLong(header->lumps[HL2LUMP_ENTITIES].fileofs);
2369 lumplen = LittleLong(header->lumps[HL2LUMP_ENTITIES].filelen);
2370 dpsnprintf(desc, sizeof(desc), "VBSP%i", LittleLong(((int *)buf)[1]));
2371 }
2372 else
2373 dpsnprintf(desc, sizeof(desc), "unknown%i", BuffLittleLong(buf));
2374 dp_strlcpy(entfilename, t->filenames[i], sizeof(entfilename));
2375 memcpy(entfilename + strlen(entfilename) - 4, ".ent", 5);
2376 entities = (char *)FS_LoadFile(entfilename, tempmempool, true, NULL);
2377 if (!entities && lumplen >= 10)
2378 {
2379 FS_Seek(f, lumpofs, SEEK_SET);
2380 entities = (char *)Z_Malloc(lumplen + 1);
2381 FS_Read(f, entities, lumplen);
2382 }
2383 if (entities)
2384 {
2385 // if there are entities to parse, a missing message key just
2386 // means there is no title, so clear the message string now
2387 message[0] = 0;
2388 data = entities;
2389 for (;;)
2390 {
2391 int l;
2392 if (!COM_ParseToken_Simple(&data, false, false, true))
2393 break;
2394 if (com_token[0] == '{')
2395 continue;
2396 if (com_token[0] == '}')
2397 break;
2398 // skip leading whitespace
2399 for (k = 0;com_token[k] && ISWHITESPACE(com_token[k]);k++);
2400 for (l = 0;l < (int)sizeof(keyname) - 1 && com_token[k+l] && !ISWHITESPACE(com_token[k+l]);l++)
2401 keyname[l] = com_token[k+l];
2402 keyname[l] = 0;
2403 if (!COM_ParseToken_Simple(&data, false, false, true))
2404 break;
2406 Con_DPrintf("key: %s %s\n", keyname, com_token);
2407 if (!strcmp(keyname, "message"))
2408 {
2409 // get the message contents
2411 break;
2412 }
2413 }
2414 }
2415 }
2416 if (entities)
2417 Z_Free(entities);
2418 if(f)
2419 FS_Close(f);
2420 *(t->filenames[i]+len[i]+5) = 0;
2421 Con_Printf("%16s (%-8s) %s\n", t->filenames[i]+5, desc, message);
2422 }
2423 Con_Print("\n");
2424 for(p=o;p<min;p++)
2425 {
2426 k = *(t->filenames[0]+5+p);
2427 if(k == 0)
2428 goto endcomplete;
2429 for(i=1;i<t->numfilenames;i++)
2430 if(*(t->filenames[i]+5+p) != k)
2431 goto endcomplete;
2432 }
2433endcomplete:
2434 if(p > o && completedname && completednamebufferlength > 0)
2435 {
2436 memset(completedname, 0, completednamebufferlength);
2437 memcpy(completedname, (t->filenames[0]+5), min(p, completednamebufferlength - 1));
2438 }
2439 Z_Free(len);
2440 FS_FreeSearch(t);
2441 return p > o;
2442}
2443
2444/*
2445 Con_DisplayList
2446
2447 New function for tab-completion system
2448 Added by EvilTypeGuy
2449 MEGA Thanks to Taniwha
2450
2451*/
2452void Con_DisplayList(const char **list)
2453{
2454 int i = 0, pos = 0, len = 0, maxlen = 0, width = (con_linewidth - 4);
2455 const char **walk = list;
2456
2457 while (*walk) {
2458 len = (int)strlen(*walk);
2459 if (len > maxlen)
2460 maxlen = len;
2461 walk++;
2462 }
2463 maxlen += 1;
2464
2465 while (*list) {
2466 len = (int)strlen(*list);
2467 if (pos + maxlen >= width) {
2468 Con_Print("\n");
2469 pos = 0;
2470 }
2471
2472 Con_Print(*list);
2473 for (i = 0; i < (maxlen - len); i++)
2474 Con_Print(" ");
2475
2476 pos += maxlen;
2477 list++;
2478 }
2479
2480 if (pos)
2481 Con_Print("\n\n");
2482}
2483
2484
2485// Now it becomes TRICKY :D --blub
2486static char Nicks_list[MAX_SCOREBOARD][MAX_SCOREBOARDNAME]; // contains the nicks with colors and all that
2487static char Nicks_sanlist[MAX_SCOREBOARD][MAX_SCOREBOARDNAME]; // sanitized list for completion when there are other possible matches.
2488// means: when somebody uses a cvar's name as his name, we won't ever get his colors in there...
2489static int Nicks_offset[MAX_SCOREBOARD]; // when nicks use a space, we need this to move the completion list string starts to avoid invalid memcpys
2491
2492// co against <<:BLASTER:>> is true!?
2493static int Nicks_strncasecmp_nospaces(char *a, char *b, unsigned int a_len)
2494{
2495 while(a_len)
2496 {
2497 if(tolower(*a) == tolower(*b))
2498 {
2499 if(*a == 0)
2500 return 0;
2501 --a_len;
2502 ++a;
2503 ++b;
2504 continue;
2505 }
2506 if(!*a)
2507 return -1;
2508 if(!*b)
2509 return 1;
2510 if(*a == ' ')
2511 return (*a < *b) ? -1 : 1;
2512 if(*b == ' ')
2513 ++b;
2514 else
2515 return (*a < *b) ? -1 : 1;
2516 }
2517 return 0;
2518}
2519static int Nicks_strncasecmp(char *a, char *b, unsigned int a_len)
2520{
2521 char space_char;
2523 {
2525 return Nicks_strncasecmp_nospaces(a, b, a_len);
2526 return strncasecmp(a, b, a_len);
2527 }
2528
2529 space_char = (con_nickcompletion_flags.integer & NICKS_NO_SPACES) ? 'a' : ' ';
2530
2531 // ignore non alphanumerics of B
2532 // if A contains a non-alphanumeric, B must contain it as well though!
2533 while(a_len)
2534 {
2535 qbool alnum_a, alnum_b;
2536
2537 if(tolower(*a) == tolower(*b))
2538 {
2539 if(*a == 0) // end of both strings, they're equal
2540 return 0;
2541 --a_len;
2542 ++a;
2543 ++b;
2544 continue;
2545 }
2546 // not equal, end of one string?
2547 if(!*a)
2548 return -1;
2549 if(!*b)
2550 return 1;
2551 // ignore non alphanumerics
2552 alnum_a = ( (*a >= 'a' && *a <= 'z') || (*a >= 'A' && *a <= 'Z') || (*a >= '0' && *a <= '9') || *a == space_char);
2553 alnum_b = ( (*b >= 'a' && *b <= 'z') || (*b >= 'A' && *b <= 'Z') || (*b >= '0' && *b <= '9') || *b == space_char);
2554 if(!alnum_a) // b must contain this
2555 return (*a < *b) ? -1 : 1;
2556 if(!alnum_b)
2557 ++b;
2558 // otherwise, both are alnum, they're just not equal, return the appropriate number
2559 else
2560 return (*a < *b) ? -1 : 1;
2561 }
2562 return 0;
2563}
2564
2565
2566/* Nicks_CompleteCountPossible
2567
2568 Count the number of possible nicks to complete
2569 */
2570static int Nicks_CompleteCountPossible(char *line, int pos, char *s, qbool isCon)
2571{
2573 int i, p;
2574 int match;
2575 int spos;
2576 int count = 0;
2577
2579 return 0;
2580
2581 // changed that to 1
2582 if(!line[0])// || !line[1]) // we want at least... 2 written characters
2583 return 0;
2584
2585 for(i = 0; i < cl.maxclients; ++i)
2586 {
2587 p = i;
2588 if(!cl.scores[p].name[0])
2589 continue;
2590
2592 //Con_Printf(" ^2Sanitized: ^7%s -> %s", cl.scores[p].name, name);
2593
2594 if(!name[0])
2595 continue;
2596
2597 match = -1;
2598 spos = pos - 1; // no need for a minimum of characters :)
2599
2600 while(spos >= 0)
2601 {
2602 if(spos > 0 && line[spos-1] != ' ' && line[spos-1] != ';' && line[spos-1] != '\"' && line[spos-1] != '\'')
2603 {
2604 if(!(isCon && spos == 1)) // console start
2605 {
2606 --spos;
2607 continue;
2608 }
2609 }
2610 if(isCon && spos == 0)
2611 break;
2612 if(Nicks_strncasecmp(line+spos, name, pos-spos) == 0)
2613 match = spos;
2614 --spos;
2615 }
2616 if(match < 0)
2617 continue;
2618 //Con_Printf("Possible match: %s|%s\n", cl.scores[p].name, name);
2620
2621 // the sanitized list
2623 if(!count)
2624 {
2625 Nicks_matchpos = match;
2626 }
2627
2628 Nicks_offset[count] = s - (&line[match]);
2629 //Con_Printf("offset for %s: %i\n", name, Nicks_offset[count]);
2630
2631 ++count;
2632 }
2633 return count;
2634}
2635
2637{
2638 int i;
2639 for(i = 0; i < count; ++i)
2640 Con_Printf("%s\n", Nicks_list[i]);
2641}
2642
2644{
2645 // cut match 0 down to the longest possible completion
2646 int i;
2647 unsigned int c, l;
2648 c = (unsigned int)strlen(Nicks_sanlist[0]) - 1;
2649 for(i = 1; i < count; ++i)
2650 {
2651 l = (unsigned int)strlen(Nicks_sanlist[i]) - 1;
2652 if(l < c)
2653 c = l;
2654
2655 for(l = 0; l <= c; ++l)
2656 if(tolower(Nicks_sanlist[0][l]) != tolower(Nicks_sanlist[i][l]))
2657 {
2658 c = l-1;
2659 break;
2660 }
2661 }
2662 Nicks_sanlist[0][c+1] = 0;
2663 //Con_Printf("List0: %s\n", Nicks_sanlist[0]);
2664}
2665
2666static unsigned int Nicks_strcleanlen(const char *s)
2667{
2668 unsigned int l = 0;
2669 while(*s)
2670 {
2671 if( (*s >= 'a' && *s <= 'z') ||
2672 (*s >= 'A' && *s <= 'Z') ||
2673 (*s >= '0' && *s <= '9') ||
2674 *s == ' ')
2675 ++l;
2676 ++s;
2677 }
2678 return l;
2679}
2680
2682{
2683 // cut match 0 down to the longest possible completion
2684 int i;
2685 unsigned int c, l;
2686 char tempstr[sizeof(Nicks_sanlist[0])];
2687 char *a, *b;
2688 char space_char = (con_nickcompletion_flags.integer & NICKS_NO_SPACES) ? 'a' : ' '; // yes this is correct, we want NO spaces when no spaces
2689
2690 c = (unsigned int)strlen(Nicks_sanlist[0]);
2691 for(i = 0, l = 0; i < (int)c; ++i)
2692 {
2693 if( (Nicks_sanlist[0][i] >= 'a' && Nicks_sanlist[0][i] <= 'z') ||
2694 (Nicks_sanlist[0][i] >= 'A' && Nicks_sanlist[0][i] <= 'Z') ||
2695 (Nicks_sanlist[0][i] >= '0' && Nicks_sanlist[0][i] <= '9') || Nicks_sanlist[0][i] == space_char) // this is what's COPIED
2696 {
2697 tempstr[l++] = Nicks_sanlist[0][i];
2698 }
2699 }
2700 tempstr[l] = 0;
2701
2702 for(i = 1; i < count; ++i)
2703 {
2704 a = tempstr;
2705 b = Nicks_sanlist[i];
2706 while(1)
2707 {
2708 if(!*a)
2709 break;
2710 if(!*b)
2711 {
2712 *a = 0;
2713 break;
2714 }
2715 if(tolower(*a) == tolower(*b))
2716 {
2717 ++a;
2718 ++b;
2719 continue;
2720 }
2721 if( (*b >= 'a' && *b <= 'z') || (*b >= 'A' && *b <= 'Z') || (*b >= '0' && *b <= '9') || *b == space_char)
2722 {
2723 // b is alnum, so cut
2724 *a = 0;
2725 break;
2726 }
2727 ++b;
2728 }
2729 }
2730 // Just so you know, if cutmatchesnormal doesn't kill the first entry, then even the non-alnums fit
2732 //if(!Nicks_sanlist[0][0])
2733 if(Nicks_strcleanlen(Nicks_sanlist[0]) < strlen(tempstr))
2734 {
2735 // if the clean sanitized one is longer than the current one, use it, it has crap chars which definitely are in there
2736 dp_strlcpy(Nicks_sanlist[0], tempstr, sizeof(Nicks_sanlist[0]));
2737 }
2738}
2739
2741{
2742 // cut match 0 down to the longest possible completion
2743 int i;
2744 unsigned int c, l;
2745 char tempstr[sizeof(Nicks_sanlist[0])];
2746 char *a, *b;
2747
2748 c = (unsigned int)strlen(Nicks_sanlist[0]);
2749 for(i = 0, l = 0; i < (int)c; ++i)
2750 {
2751 if(Nicks_sanlist[0][i] != ' ') // here it's what's NOT copied
2752 {
2753 tempstr[l++] = Nicks_sanlist[0][i];
2754 }
2755 }
2756 tempstr[l] = 0;
2757
2758 for(i = 1; i < count; ++i)
2759 {
2760 a = tempstr;
2761 b = Nicks_sanlist[i];
2762 while(1)
2763 {
2764 if(!*a)
2765 break;
2766 if(!*b)
2767 {
2768 *a = 0;
2769 break;
2770 }
2771 if(tolower(*a) == tolower(*b))
2772 {
2773 ++a;
2774 ++b;
2775 continue;
2776 }
2777 if(*b != ' ')
2778 {
2779 *a = 0;
2780 break;
2781 }
2782 ++b;
2783 }
2784 }
2785 // Just so you know, if cutmatchesnormal doesn't kill the first entry, then even the non-alnums fit
2787 //if(!Nicks_sanlist[0][0])
2788 //Con_Printf("TS: %s\n", tempstr);
2789 if(Nicks_strcleanlen(Nicks_sanlist[0]) < strlen(tempstr))
2790 {
2791 // if the clean sanitized one is longer than the current one, use it, it has crap chars which definitely are in there
2792 dp_strlcpy(Nicks_sanlist[0], tempstr, sizeof(Nicks_sanlist[0]));
2793 }
2794}
2795
2805
2806static const char **Nicks_CompleteBuildList(int count)
2807{
2808 const char **buf;
2809 int bpos = 0;
2810 // the list is freed by Con_CompleteCommandLine, so create a char**
2811 buf = (const char **)Mem_Alloc(tempmempool, count * sizeof(const char *) + sizeof (const char *));
2812
2813 for(; bpos < count; ++bpos)
2814 buf[bpos] = Nicks_sanlist[bpos] + Nicks_offset[bpos];
2815
2817
2818 buf[bpos] = NULL;
2819 return buf;
2820}
2821
2822/*
2823 Nicks_AddLastColor
2824 Restores the previous used color, after the autocompleted name.
2825*/
2826static int Nicks_AddLastColor(char *buffer, int pos)
2827{
2828 qbool quote_added = false;
2829 int match;
2830 int color = STRING_COLOR_DEFAULT + '0';
2831 char r = 0, g = 0, b = 0;
2832
2834 {
2835 // we'll have to add a quote :)
2836 buffer[pos++] = '\"';
2837 quote_added = true;
2838 }
2839
2841 {
2842 // add color when no quote was added, or when flags &4?
2843 // find last color
2844 for(match = Nicks_matchpos-1; match >= 0; --match)
2845 {
2846 if(buffer[match] == STRING_COLOR_TAG)
2847 {
2848 if( isdigit(buffer[match+1]) )
2849 {
2850 color = buffer[match+1];
2851 break;
2852 }
2853 else if(buffer[match+1] == STRING_COLOR_RGB_TAG_CHAR)
2854 {
2855 if ( isxdigit(buffer[match+2]) && isxdigit(buffer[match+3]) && isxdigit(buffer[match+4]) )
2856 {
2857 r = buffer[match+2];
2858 g = buffer[match+3];
2859 b = buffer[match+4];
2860 color = -1;
2861 break;
2862 }
2863 }
2864 }
2865 }
2866 if(!quote_added)
2867 {
2868 if( pos >= 2 && buffer[pos-2] == STRING_COLOR_TAG && isdigit(buffer[pos-1]) ) // when thes use &4
2869 pos -= 2;
2870 else if( pos >= 5 && buffer[pos-5] == STRING_COLOR_TAG && buffer[pos-4] == STRING_COLOR_RGB_TAG_CHAR
2871 && isxdigit(buffer[pos-3]) && isxdigit(buffer[pos-2]) && isxdigit(buffer[pos-1]) )
2872 pos -= 5;
2873 }
2874 buffer[pos++] = STRING_COLOR_TAG;
2875 if (color == -1)
2876 {
2878 buffer[pos++] = r;
2879 buffer[pos++] = g;
2880 buffer[pos++] = b;
2881 }
2882 else
2883 buffer[pos++] = color;
2884 }
2885 return pos;
2886}
2887
2888/*
2889 Con_CompleteCommandLine
2890
2891 New function for tab-completion system
2892 Added by EvilTypeGuy
2893 Thanks to Fett erich@heintz.com
2894 Thanks to taniwha
2895 Enhanced to tab-complete map names by [515]
2896
2897*/
2899{
2900 const char *text = "";
2901 char *s;
2902 const char **list[4] = {0, 0, 0, 0};
2903 char s2[512];
2904 char command[512];
2905 int c, v, a, i, cmd_len, pos, k;
2906 int n; // nicks --blub
2907 const char *space, *patterns;
2908 char vabuf[1024];
2909
2910 char *line;
2911 int linestart, linepos;
2912 unsigned int linesize;
2913 if (is_console)
2914 {
2915 line = key_line;
2916 linepos = key_linepos;
2917 linesize = sizeof(key_line);
2918 linestart = 1;
2919 }
2920 else
2921 {
2922 line = chat_buffer;
2923 linepos = chat_bufferpos;
2924 linesize = sizeof(chat_buffer);
2925 linestart = 0;
2926 }
2927
2928 //find what we want to complete
2929 pos = linepos;
2930 while(--pos >= linestart)
2931 {
2932 k = line[pos];
2933 if(k == '\"' || k == ';' || k == ' ' || k == '\'')
2934 break;
2935 }
2936 pos++;
2937
2938 s = line + pos;
2939 dp_strlcpy(s2, line + linepos, sizeof(s2)); //save chars after cursor
2940 line[linepos] = 0; //hide them
2941
2942 c = v = a = n = cmd_len = 0;
2943 if (!is_console)
2944 goto nicks;
2945
2946 space = strchr(line + 1, ' ');
2947 if(space && pos == (space - line) + 1)
2948 {
2949 // adding 1 to line drops the leading ]
2950 dp_ustr2stp(command, sizeof(command), line + 1, space - (line + 1));
2951
2952 patterns = Cvar_VariableString(cmd->cvars, va(vabuf, sizeof(vabuf), "con_completion_%s", command), CF_CLIENT | CF_SERVER); // TODO maybe use a better place for this?
2953 if(patterns && !*patterns)
2954 patterns = NULL; // get rid of the empty string
2955
2956 if(!strcmp(command, "map") || !strcmp(command, "changelevel") || (patterns && !strcmp(patterns, "map")))
2957 {
2958 //maps search
2959 char t[MAX_QPATH];
2960 if (GetMapList(s, t, sizeof(t)))
2961 {
2962 // first move the cursor
2963 linepos += (int)strlen(t) - (int)strlen(s);
2964
2965 // and now do the actual work
2966 *s = 0;
2967 dp_strlcat(line, t, MAX_INPUTLINE);
2968 dp_strlcat(line, s2, MAX_INPUTLINE); //add back chars after cursor
2969
2970 // and fix the cursor
2971 if(linepos > (int) strlen(line))
2972 linepos = (int) strlen(line);
2973 }
2974 return linepos;
2975 }
2976 else
2977 {
2978 if(patterns)
2979 {
2980 char t[MAX_QPATH];
2981 stringlist_t resultbuf, dirbuf;
2982
2983 // Usage:
2984 // // store completion patterns (space separated) for command foo in con_completion_foo
2985 // set con_completion_foo "foodata/*.foodefault *.foo"
2986 // foo <TAB>
2987 //
2988 // Note: patterns with slash are always treated as absolute
2989 // patterns; patterns without slash search in the innermost
2990 // directory the user specified. There is no way to "complete into"
2991 // a directory as of now, as directories seem to be unknown to the
2992 // FS subsystem.
2993 //
2994 // Examples:
2995 // set con_completion_playermodel "models/player/*.zym models/player/*.md3 models/player/*.psk models/player/*.dpm"
2996 // set con_completion_playdemo "*.dem"
2997 // set con_completion_play "*.wav *.ogg"
2998 //
2999 // TODO somehow add support for directories; these shall complete
3000 // to their name + an appended slash.
3001
3002 stringlistinit(&resultbuf);
3003 stringlistinit(&dirbuf);
3004 while(COM_ParseToken_Simple(&patterns, false, false, true))
3005 {
3006 fssearch_t *search;
3007 if(strchr(com_token, '/'))
3008 {
3009 search = FS_Search(com_token, true, true, NULL);
3010 }
3011 else
3012 {
3013 const char *slash = strrchr(s, '/');
3014 if(slash)
3015 {
3016 dp_strlcpy(t, s, min(sizeof(t), (unsigned int)(slash - s + 2))); // + 2, because I want to include the slash
3017 dp_strlcat(t, com_token, sizeof(t));
3018 search = FS_Search(t, true, true, NULL);
3019 }
3020 else
3021 search = FS_Search(com_token, true, true, NULL);
3022 }
3023 if(search)
3024 {
3025 for(i = 0; i < search->numfilenames; ++i)
3026 if(!strncmp(search->filenames[i], s, strlen(s)))
3027 if(FS_FileType(search->filenames[i]) == FS_FILETYPE_FILE)
3028 stringlistappend(&resultbuf, search->filenames[i]);
3029 FS_FreeSearch(search);
3030 }
3031 }
3032
3033 // In any case, add directory names
3034 {
3035 fssearch_t *search;
3036 const char *slash = strrchr(s, '/');
3037 if(slash)
3038 {
3039 dp_strlcpy(t, s, min(sizeof(t), (unsigned int)(slash - s + 2))); // + 2, because I want to include the slash
3040 dp_strlcat(t, "*", sizeof(t));
3041 search = FS_Search(t, true, true, NULL);
3042 }
3043 else
3044 search = FS_Search("*", true, true, NULL);
3045 if(search)
3046 {
3047 for(i = 0; i < search->numfilenames; ++i)
3048 if(!strncmp(search->filenames[i], s, strlen(s)))
3050 stringlistappend(&dirbuf, search->filenames[i]);
3051 FS_FreeSearch(search);
3052 }
3053 }
3054
3055 if(resultbuf.numstrings > 0 || dirbuf.numstrings > 0)
3056 {
3057 const char *p, *q;
3058 unsigned int matchchars;
3059 if(resultbuf.numstrings == 0 && dirbuf.numstrings == 1)
3060 {
3061 dpsnprintf(t, sizeof(t), "%s/", dirbuf.strings[0]);
3062 }
3063 else
3064 if(resultbuf.numstrings == 1 && dirbuf.numstrings == 0)
3065 {
3066 dpsnprintf(t, sizeof(t), "%s ", resultbuf.strings[0]);
3067 }
3068 else
3069 {
3070 stringlistsort(&resultbuf, true); // dirbuf is already sorted
3071 Con_Printf("\n%i possible filenames\n", resultbuf.numstrings + dirbuf.numstrings);
3072 for(i = 0; i < dirbuf.numstrings; ++i)
3073 {
3074 Con_Printf("^4%s^7/\n", dirbuf.strings[i]);
3075 }
3076 for(i = 0; i < resultbuf.numstrings; ++i)
3077 {
3078 Con_Printf("%s\n", resultbuf.strings[i]);
3079 }
3080 matchchars = sizeof(t) - 1;
3081 if(resultbuf.numstrings > 0)
3082 {
3083 p = resultbuf.strings[0];
3084 q = resultbuf.strings[resultbuf.numstrings - 1];
3085 for(; *p && *p == *q; ++p, ++q);
3086 matchchars = (unsigned int)(p - resultbuf.strings[0]);
3087 }
3088 if(dirbuf.numstrings > 0)
3089 {
3090 p = dirbuf.strings[0];
3091 q = dirbuf.strings[dirbuf.numstrings - 1];
3092 for(; *p && *p == *q; ++p, ++q);
3093 matchchars = min(matchchars, (unsigned int)(p - dirbuf.strings[0]));
3094 }
3095 // now p points to the first non-equal character, or to the end
3096 // of resultbuf.strings[0]. We want to append the characters
3097 // from resultbuf.strings[0] to (not including) p as these are
3098 // the unique prefix
3099 dp_strlcpy(t, (resultbuf.numstrings > 0 ? resultbuf : dirbuf).strings[0], min(matchchars + 1, sizeof(t)));
3100 }
3101
3102 // first move the cursor
3103 linepos += (int)strlen(t) - (int)strlen(s);
3104
3105 // and now do the actual work
3106 *s = 0;
3107 dp_strlcat(line, t, MAX_INPUTLINE);
3108 dp_strlcat(line, s2, MAX_INPUTLINE); //add back chars after cursor
3109
3110 // and fix the cursor
3111 if(linepos > (int) strlen(line))
3112 linepos = (int) strlen(line);
3113 }
3114 stringlistfreecontents(&resultbuf);
3115 stringlistfreecontents(&dirbuf);
3116
3117 return linepos; // bail out, when we complete for a command that wants a file name
3118 }
3119 }
3120 }
3121
3122 // Count number of possible matches and print them
3124 if (c)
3125 {
3126 Con_Printf("\n%i possible command%s\n", c, (c > 1) ? "s: " : ":");
3128 }
3130 if (v)
3131 {
3132 Con_Printf("\n%i possible variable%s\n", v, (v > 1) ? "s: " : ":");
3134 }
3136 if (a)
3137 {
3138 Con_Printf("\n%i possible alias%s\n", a, (a > 1) ? "es: " : ":");
3140 }
3141
3142nicks:
3143 n = Nicks_CompleteCountPossible(line, linepos, s, is_console);
3144 if (n)
3145 {
3146 Con_Printf("\n%i possible nick%s\n", n, (n > 1) ? "s: " : ":");
3148 }
3149
3150 if (!(c + v + a + n)) // No possible matches
3151 {
3152 if(s2[0])
3153 dp_strlcpy(&line[linepos], s2, linesize - linepos);
3154 return linepos;
3155 }
3156
3157 if (c)
3158 text = *(list[0] = Cmd_CompleteBuildList(cmd, s));
3159 if (v)
3160 text = *(list[1] = Cvar_CompleteBuildList(cmd->cvars, s, cmd->cvars_flagsmask));
3161 if (a)
3162 text = *(list[2] = Cmd_CompleteAliasBuildList(cmd, s));
3163 if (n)
3164 {
3165 if (is_console)
3166 text = *(list[3] = Nicks_CompleteBuildList(n));
3167 else
3168 text = *(Nicks_CompleteBuildList(n));
3169 }
3170
3171 for (cmd_len = (int)strlen(s);;cmd_len++)
3172 {
3173 const char **l;
3174 for (i = 0; i < 3; i++)
3175 if (list[i])
3176 for (l = list[i];*l;l++)
3177 if ((*l)[cmd_len] != text[cmd_len])
3178 goto done;
3179 // all possible matches share this character, so we continue...
3180 if (!text[cmd_len])
3181 {
3182 // if all matches ended at the same position, stop
3183 // (this means there is only one match)
3184 break;
3185 }
3186 }
3187done:
3188
3189 // prevent a buffer overrun by limiting cmd_len according to remaining space
3190 cmd_len = min(cmd_len, (int)linesize - 1 - pos);
3191 if (text)
3192 {
3193 linepos = pos;
3194 memcpy(&line[linepos], text, cmd_len);
3195 linepos += cmd_len;
3196 // if there is only one match, add a space after it
3197 if (c + v + a + n == 1 && linepos < (int)linesize - 1)
3198 {
3199 if(n)
3200 { // was a nick, might have an offset, and needs colors ;) --blub
3201 linepos = pos - Nicks_offset[0];
3202 cmd_len = (int)strlen(Nicks_list[0]);
3203 cmd_len = min(cmd_len, (int)linesize - 3 - pos);
3204
3205 memcpy(&line[linepos] , Nicks_list[0], cmd_len);
3206 linepos += cmd_len;
3207 if(linepos < (int)(linesize - 7)) // space for color code (^[0-9] or ^xrgb), space and \0
3208 linepos = Nicks_AddLastColor(line, linepos);
3209 }
3210 line[linepos++] = ' ';
3211 }
3212 }
3213
3214 // use strlcat to avoid a buffer overrun
3215 line[linepos] = 0;
3216 dp_strlcat(line, s2, linesize);
3217
3218 if (!is_console)
3219 return linepos;
3220
3221 // free the command, cvar, and alias lists
3222 for (i = 0; i < 4; i++)
3223 if (list[i])
3224 Mem_Free((void *)list[i]);
3225
3226 return linepos;
3227}
3228
#define BSPVERSION
Definition bspfile.h:29
#define LUMP_ENTITIES
Definition bspfile.h:39
client_state_t cl
Definition cl_main.c:117
client_static_t cls
Definition cl_main.c:116
cvar_t scr_conscroll2_y
Definition cl_screen.c:31
cvar_t scr_conbrightness
Definition cl_screen.c:25
cvar_t scr_conscroll2_x
Definition cl_screen.c:30
cvar_t scr_conscroll3_y
Definition cl_screen.c:33
cvar_t scr_conalphafactor
Definition cl_screen.c:22
cvar_t scr_conalpha
Definition cl_screen.c:21
cvar_t scr_conscroll_x
Definition cl_screen.c:28
cvar_t scr_conscroll3_x
Definition cl_screen.c:32
cvar_t scr_conalpha2factor
Definition cl_screen.c:23
cvar_t scr_conscroll_y
Definition cl_screen.c:29
cvar_t scr_conalpha3factor
Definition cl_screen.c:24
cvar_t vid_conheight
Definition cl_screen.c:57
cvar_t vid_conwidth
Definition cl_screen.c:56
@ ca_dedicated
Definition client.h:530
void Cmd_CompleteCommandPrint(cmd_state_t *cmd, const char *partial)
Definition cmd.c:1870
const char ** Cmd_CompleteBuildList(cmd_state_t *cmd, const char *partial)
Definition cmd.c:1847
int Cmd_CompleteCountPossible(cmd_state_t *cmd, const char *partial)
Definition cmd.c:1814
void Cmd_AddCommand(unsigned flags, const char *cmd_name, xcommand_t function, const char *description)
called by the init functions of other parts of the program to register commands and functions to call...
Definition cmd.c:1661
void Cmd_CompleteAliasPrint(cmd_state_t *cmd, const char *partial)
Definition cmd.c:1911
int Cmd_CompleteAliasCountPossible(cmd_state_t *cmd, const char *partial)
Definition cmd.c:1931
const char ** Cmd_CompleteAliasBuildList(cmd_state_t *cmd, const char *partial)
Definition cmd.c:1961
#define CF_SHARED
Definition cmd.h:67
#define CF_SERVER
cvar/command that only the server can change/execute
Definition cmd.h:49
static int Cmd_Argc(cmd_state_t *cmd)
Definition cmd.h:249
static const char * Cmd_Argv(cmd_state_t *cmd, int arg)
Cmd_Argv(cmd, ) will return an empty string (not a NULL) if arg > argc, so string operations are alwa...
Definition cmd.h:254
#define CF_CLIENT
cvar/command that only the client can change/execute
Definition cmd.h:48
static const char * Cmd_Args(cmd_state_t *cmd)
Definition cmd.h:260
#define CF_ARCHIVE
cvar should have its set value saved to config.cfg and persist across sessions
Definition cmd.h:53
#define CF_PRIVATE
cvar should not be $ expanded or sent to the server under any circumstances (rcon_password,...
Definition cmd.h:59
gamemode_t gamemode
Definition com_game.c:26
#define IS_OLDNEXUIZ_DERIVED(g)
Definition com_game.h:73
@ GAME_TRANSFUSION
Definition com_game.h:35
int BuffLittleLong(const unsigned char *buffer)
Extract a little endian 32bit int from the given buffer.
Definition com_msg.c:71
void StoreBigLong(unsigned char *buffer, unsigned int i)
Encode a big endian 32bit int to the given buffer.
Definition com_msg.c:81
int dpvsnprintf(char *buffer, size_t buffersize, const char *format, va_list args)
Returns the number of printed characters, excluding the final '\0' or returns -1 if the buffer isn't ...
Definition common.c:1010
char * dp_ustr2stp(char *dst, size_t dsize, const char *src, size_t slen)
Copies a measured byte sequence (unterminated string) to a null-terminated string.
Definition common.c:1388
int COM_Wordwrap(const char *string, size_t length, float continuationWidth, float maxWidth, COM_WordWidthFunc_t wordWidth, void *passthroughCW, COM_LineProcessorFunc processLine, void *passthroughPL)
Definition common.c:174
char com_token[MAX_INPUTLINE]
Definition common.c:39
char * va(char *buf, size_t buflen, const char *format,...)
Definition common.c:972
qbool COM_ParseToken_Console(const char **datapointer)
Definition common.c:819
qbool COM_ParseToken_Simple(const char **datapointer, qbool returnnewline, qbool parsebackslash, qbool parsecomments)
Definition common.c:463
int dpsnprintf(char *buffer, size_t buffersize, const char *format,...)
Returns the number of printed characters, excluding the final '\0' or returns -1 if the buffer isn't ...
Definition common.c:997
#define dp_strlcat(dst, src, dsize)
Definition common.h:304
#define LittleLong(l)
Definition common.h:92
#define dp_strlcpy(dst, src, dsize)
Definition common.h:303
void Con_Clear_f(cmd_state_t *cmd)
Definition console.c:840
void Con_Init(void)
Definition console.c:861
cvar_t con_chatsound_team_file
Definition console.c:62
static char Nicks_sanlist[MAX_SCOREBOARD][MAX_SCOREBOARDNAME]
Definition console.c:2487
cvar_t con_notifysize
Definition console.c:58
static void Nicks_CutMatchesNoSpaces(int count)
Definition console.c:2740
cvar_t rcon_password
Definition console.c:89
cvar_t timeformat
Definition host.c:56
#define NICKS_ADD_COLOR
Definition console.c:77
const char * ConBuffer_GetLine(conbuffer_t *buf, int i)
Definition console.c:386
static void Con_MessageMode_f(cmd_state_t *cmd)
Definition console.c:731
void Con_CenterPrint(const char *str)
Prints a center-aligned message to the console.
Definition console.c:1655
cvar_t con_chattime
Definition console.c:50
cvar_t sys_specialcharactertranslation
Definition console.c:65
static void Con_DrawInput(qbool is_console, float x, float v, float inputsize)
Definition console.c:1684
static void Con_CommandMode_f(cmd_state_t *cmd)
Definition console.c:753
void Con_Print(const char *msg)
Prints to all appropriate console targets, and adds timestamps.
Definition console.c:1504
cvar_t r_textbrightness
Definition gl_draw.c:55
static void Con_Rcon_AddChar(int c)
Adds a character to the rcon buffer.
Definition console.c:1060
void ConBuffer_FixTimes(conbuffer_t *buf)
Definition console.c:242
void Con_DPrintf(const char *fmt,...)
A Con_Printf that only shows up if the "developer" cvar is set.
Definition console.c:1544
static unsigned int Nicks_strcleanlen(const char *s)
Definition console.c:2666
unsigned char * logqueue
Definition console.c:414
static void Log_Open(void)
Definition console.c:503
static void Con_ConDump_f(cmd_state_t *cmd)
Definition console.c:802
static int Con_CountLineFunc(void *passthrough, const char *line, size_t length, float width, qbool isContinuation)
Definition console.c:1832
qbool GetMapList(const char *s, char *completedname, int completednamebufferlength)
Definition console.c:2275
#define NICKS_NO_SPACES
Definition console.c:81
qfile_t * logfile
Definition console.c:412
void Con_MaskPrintf(unsigned mask, const char *fmt,...)
Definition console.c:1487
void * con_mutex
Definition console.c:40
conbuffer_t con
Definition console.c:39
void ConBuffer_Clear(conbuffer_t *buf)
Definition console.c:212
int rcon_redirect_bufferpos
Definition console.c:102
void Con_DrawNotify(void)
Definition console.c:1945
static int Nicks_AddLastColor(char *buffer, int pos)
Definition console.c:2826
cvar_t log_dest_udp
Definition console.c:407
static void Con_MessageMode2_f(cmd_state_t *cmd)
Definition console.c:743
cvar_t con_completion_exec
Definition console.c:85
void Con_Printf(const char *fmt,...)
Prints to all appropriate console targets.
Definition console.c:1514
static int Nicks_strncasecmp(char *a, char *b, unsigned int a_len)
Definition console.c:2519
static char Sys_Con_NearestColor(const unsigned char _r, const unsigned char _g, const unsigned char _b)
Convert an RGB color to its nearest quake color.
Definition console.c:1099
cvar_t con_notifytime
Definition console.c:46
void Con_DrawConsole(int lines, qbool forcedfullscreen)
Definition console.c:2138
void ConBuffer_Shutdown(conbuffer_t *buf)
Definition console.c:222
cvar_t con_chatsound
Definition console.c:60
#define NICKS_ALPHANUMERICS_ONLY
Definition console.c:80
void ConBuffer_DeleteLine(conbuffer_t *buf)
Deletes the first line from the console history.
Definition console.c:263
cvar_t con_chatrect_x
Definition console.c:54
void Con_MaskPrint(unsigned additionalmask, const char *msg)
Prints to a chosen console target.
Definition console.c:1161
static int Nicks_CompleteCountPossible(char *line, int pos, char *s, qbool isCon)
Definition console.c:2570
cvar_t con_chatrect_y
Definition console.c:55
cvar_t con_chat
Definition console.c:51
int ConBuffer_FindPrevLine(conbuffer_t *buf, unsigned mask_must, unsigned mask_mustnot, int start)
Definition console.c:366
static int Con_DrawConsoleLine(unsigned mask_must, unsigned mask_mustnot, float y, int lineno, float ymin, float ymax)
Definition console.c:2064
lhnetaddress_t * rcon_redirect_dest
Definition console.c:101
char crt_log_file[MAX_OSPATH]
Definition console.c:411
cvar_t condump_stripcolors
Definition console.c:87
cvar_t con_notify
Definition console.c:47
#define NICKS_FORCE_COLOR
Definition console.c:79
cvar_t con_chatsize
Definition console.c:59
static void Con_Maps_f(cmd_state_t *cmd)
Definition console.c:789
cvar_t con_nickcompletion_flags
Definition console.c:70
static void Con_LastVisibleLine(unsigned mask_must, unsigned mask_mustnot, int *last, int *limitlast)
Definition console.c:2096
void Con_CenterPrintf(int maxLineLength, const char *fmt,...)
Left-pad a string with spaces to make it appear centered.
Definition console.c:1600
static void Nicks_CutMatchesNormal(int count)
Definition console.c:2643
cvar_t con_notifyalign
Definition console.c:48
#define NICKS_ADD_QUOTE
Definition console.c:78
qbool con_initialized
Definition console.c:97
static void Con_RCon_ClearPassword_c(cvar_t *var)
Definition console.c:847
void ConBuffer_DeleteLastLine(conbuffer_t *buf)
Deletes the last line from the console history.
Definition console.c:278
static void Con_PrintToHistory(const char *txt, int mask)
Definition console.c:959
#define CON_LINES_COUNT
Definition console.c:44
size_t logq_ind
Definition console.c:415
cvar_t rcon_secure_challengetimeout
Definition console.c:91
cvar_t rcon_secure
Definition console.c:90
static const char * Log_Timestamp(const char *desc)
Definition console.c:474
cvar_t con_completion_playdemo
Definition console.c:83
static void Log_DestBuffer_Init(void)
Definition console.c:420
void Con_ClearNotify(void)
Clear all notify lines.
Definition console.c:702
static int Con_LineHeight(int lineno)
Definition console.c:2041
static int Con_DrawNotifyRect(unsigned mask_must, unsigned mask_mustnot, float maxage, float x, float y, float width, float height, float fontsize, float alignment_x, float alignment_y, const char *continuationString)
Definition console.c:1863
int Con_CompleteCommandLine(cmd_state_t *cmd, qbool is_console)
wrapper function to attempt to either complete the command line or to list possible matches grouped b...
Definition console.c:2898
unsigned int log_dest_buffer_appending
Definition console.c:410
void Con_Rcon_Redirect_Init(lhnetsocket_t *sock, lhnetaddress_t *dest, qbool proquakeprotocol)
Definition console.c:1004
size_t log_dest_buffer_pos
Definition console.c:409
static void Nicks_CutMatches(int count)
Definition console.c:2796
void Log_Start(void)
Definition console.c:542
void ConBuffer_AddLine(conbuffer_t *buf, const char *line, int len, unsigned mask)
Appends a given string as a new line to the console.
Definition console.c:332
void Log_DestBuffer_Flush(void)
call this once per frame to send out replies to rcon streaming clients
Definition console.c:465
void Con_DPrint(const char *msg)
A Con_Print that only shows up if the "developer" cvar is set.
Definition console.c:1531
static void Cmd_CompleteNicksPrint(int count)
Definition console.c:2636
cvar_t log_file_stripcolors
Definition console.c:406
cvar_t con_nickcompletion
Definition console.c:69
void Con_Rcon_Redirect_End(void)
Definition console.c:1041
static int Nicks_matchpos
Definition console.c:2490
cvar_t log_file
Definition console.c:405
char rcon_redirect_buffer[1400]
Definition console.c:103
cvar_t rcon_address
Definition console.c:92
cvar_t con_chatsound_team_mask
Definition console.c:63
size_t logq_size
Definition console.c:416
cvar_t r_textcontrast
Definition gl_draw.c:56
static const char ** Nicks_CompleteBuildList(int count)
Definition console.c:2806
static int Nicks_strncasecmp_nospaces(char *a, char *b, unsigned int a_len)
Definition console.c:2493
static void Nicks_CutMatchesAlphaNumeric(int count)
Definition console.c:2681
cvar_t con_chatwidth
Definition console.c:56
static void Con_Rcon_Redirect_Flush(void)
Definition console.c:1024
static int Nicks_offset[MAX_SCOREBOARD]
Definition console.c:2489
static float Con_WordWidthFunc(void *passthrough, const char *w, size_t *length, float maxWidth)
Definition console.c:1812
void Con_Rcon_Redirect_Abort(void)
Definition console.c:1048
cvar_t con_completion_timedemo
Definition console.c:84
void ConBuffer_Init(conbuffer_t *buf, int textsize, int maxlines, mempool_t *mempool)
Definition console.c:108
int con_vislines
Definition console.c:95
#define CON_LINES(i)
Definition console.c:42
static char Nicks_list[MAX_SCOREBOARD][MAX_SCOREBOARDNAME]
Definition console.c:2486
const char * Con_Quakebar(int len, char *bar, size_t barsize)
Returns a horizontal line.
Definition console.c:1570
cvar_t sys_colortranslation
Definition console.c:66
void Con_CheckResize(void)
If the line width has changed, reformat the buffer.
Definition console.c:763
static void SanitizeString(char *in, char *out)
Definition console.c:160
cvar_t con_textsize
Definition console.c:57
lhnetsocket_t * rcon_redirect_sock
Definition console.c:100
static char qfont_table[256]
Definition console.c:120
cvar_t con_chatpos
Definition console.c:52
void Con_Shutdown(void)
Definition console.c:941
cvar_t con_chatsound_file
Definition console.c:61
char log_dest_buffer[1400]
Definition console.c:408
static void Log_DestBuffer_Flush_NoLock(void)
Definition console.c:426
void Con_DisplayList(const char **list)
Generic libs/util/console.c function to display a list formatted in columns on the console.
Definition console.c:2452
static void Con_MsgCmdMode(cmd_state_t *cmd, signed char mode)
Definition console.c:710
float con_cursorspeed
Definition console.c:34
int con_linewidth
Definition console.c:94
static int Con_DisplayLineFunc(void *passthrough, const char *line, size_t length, float width, qbool isContinuation)
Definition console.c:1842
void Con_ToggleConsole_f(cmd_state_t *cmd)
Definition console.c:686
cvar_t timestamps
Definition host.c:55
qbool rcon_redirect_proquakeprotocol
Definition console.c:104
static char * ConBuffer_BytesLeft(conbuffer_t *buf, int len)
Definition console.c:293
cvar_t con_chatrect
Definition console.c:53
void Log_Printf(const char *logfilename, const char *fmt,...)
Definition console.c:655
void Log_Close(void)
Definition console.c:521
void Log_ConPrint(const char *msg)
Definition console.c:584
int con_backscroll
Definition console.c:37
#define CONBUFFER_LINES(buf, i)
Definition console.h:136
#define CON_MASK_HIDENOTIFY
Definition console.h:106
#define CON_WARN
Definition console.h:101
#define CONBUFFER_LINES_LAST(buf)
Definition console.h:138
#define CON_MASK_DEVELOPER
Definition console.h:109
#define CON_MASK_PRINT
Definition console.h:110
#define CON_MASK_CHAT
Definition console.h:107
#define CON_MASK_INPUT
Definition console.h:108
#define CON_ERROR
Definition console.h:102
const char * prefix
void() predraw
float time
void Cvar_SetValueQuick(cvar_t *var, float value)
Definition cvar.c:473
void Cvar_SetQuick(cvar_t *var, const char *value)
Definition cvar.c:436
const char * Cvar_VariableString(cvar_state_t *cvars, const char *var_name, unsigned neededflags)
Definition cvar.c:149
void Cvar_RegisterVariable(cvar_t *variable)
registers a cvar that already has the name, string, and optionally the archive elements set.
Definition cvar.c:599
const char ** Cvar_CompleteBuildList(cvar_state_t *cvars, const char *partial, unsigned neededflags)
Definition cvar.c:250
void Cvar_CompleteCvarPrint(cvar_state_t *cvars, const char *partial, unsigned neededflags)
Definition cvar.c:288
int Cvar_CompleteCountPossible(cvar_state_t *cvars, const char *partial, unsigned neededflags)
Definition cvar.c:217
void Cvar_RegisterCallback(cvar_t *variable, void(*callback)(cvar_t *))
Definition cvar.c:495
char engineversion[128]
version string for the corner of the console, crash messages, status command, etc
Definition host.c:304
vector color
float alpha
@ CACHEPICFLAG_FAILONMISSING
Definition draw.h:44
@ CACHEPICFLAG_NOCLAMP
Definition draw.h:39
float DrawQ_TextWidth_UntilWidth_TrackColors(const char *text, size_t *maxlen, float w, float h, int *outcolor, qbool ignorecolorcodes, const dp_font_t *fnt, float maxwidth)
Definition gl_draw.c:1325
void DrawQ_Fill(float x, float y, float width, float height, float red, float green, float blue, float alpha, int flags)
Definition gl_draw.c:847
#define STRING_COLOR_RGB_TAG_CHAR
Definition draw.h:143
void DrawQ_SuperPic(float x, float y, cachepic_t *pic, float width, float height, float s1, float t1, float r1, float g1, float b1, float a1, float s2, float t2, float r2, float g2, float b2, float a2, float s3, float t3, float r3, float g3, float b3, float a3, float s4, float t4, float r4, float g4, float b4, float a4, int flags)
Definition gl_draw.c:1380
#define FONT_CHAT
Definition draw.h:132
#define FONT_CONSOLE
Definition draw.h:129
float DrawQ_String(float x, float y, const char *text, size_t maxlen, float scalex, float scaley, float basered, float basegreen, float baseblue, float basealpha, int flags, int *outcolor, qbool ignorecolorcodes, const dp_font_t *fnt)
Definition gl_draw.c:1320
const vec4_t string_colors[]
color tag printing
Definition gl_draw.c:853
cachepic_t * Draw_CachePic_Flags(const char *path, unsigned int cachepicflags)
Definition gl_draw.c:86
#define FONT_NOTIFY
Definition draw.h:131
float DrawQ_TextWidth(const char *text, size_t maxlen, float w, float h, qbool ignorecolorcodes, const dp_font_t *fnt)
Definition gl_draw.c:1330
float DrawQ_TextWidth_UntilWidth(const char *text, size_t *maxlen, float w, float h, qbool ignorecolorcodes, const dp_font_t *fnt, float maxWidth)
Definition gl_draw.c:1335
#define STRING_COLOR_DEFAULT
Definition draw.h:141
qbool Draw_IsPicLoaded(cachepic_t *pic)
Definition gl_draw.c:211
#define STRING_COLOR_TAG
Definition draw.h:140
void stringlistfreecontents(stringlist_t *list)
Definition filematch.c:87
void stringlistinit(stringlist_t *list)
Definition filematch.c:82
void stringlistsort(stringlist_t *list, qbool uniq)
Definition filematch.c:129
void stringlistappend(stringlist_t *list, const char *text)
Definition filematch.c:103
#define n(x, y)
fs_offset_t FS_Read(qfile_t *file, void *buffer, size_t buffersize)
Definition fs.c:3066
qfile_t * FS_OpenVirtualFile(const char *filepath, qbool quiet)
Definition fs.c:2928
fs_offset_t FS_Write(qfile_t *file, const void *data, size_t datasize)
Definition fs.c:3019
unsigned char * FS_LoadFile(const char *path, mempool_t *pool, qbool quiet, fs_offset_t *filesizepointer)
Definition fs.c:3540
void FS_FreeSearch(fssearch_t *search)
Definition fs.c:3963
fssearch_t * FS_Search(const char *pattern, int caseinsensitive, int quiet, const char *packfile)
Definition fs.c:3756
int FS_VPrintf(qfile_t *file, const char *format, va_list ap)
Definition fs.c:3293
int FS_Seek(qfile_t *file, fs_offset_t offset, int whence)
Definition fs.c:3359
qfile_t * FS_OpenRealFile(const char *filepath, const char *mode, qbool quiet)
Definition fs.c:2901
int FS_FileType(const char *filename)
Look for a file in the packages and in the filesystem.
Definition fs.c:3667
static int(ZEXPORT *qz_inflate)(z_stream *strm
int FS_Close(qfile_t *file)
Definition fs.c:2970
int FS_Print(qfile_t *file, const char *msg)
Definition fs.c:3261
#define FS_FILETYPE_DIRECTORY
Definition fs.h:139
#define FS_FILETYPE_FILE
Definition fs.h:138
qbool r_draw2d_force
Definition gl_draw.c:795
GLenum GLsizei width
Definition glquake.h:622
GLenum GLsizei GLsizei height
Definition glquake.h:622
GLubyte GLubyte GLubyte GLubyte w
Definition glquake.h:782
GLenum mode
Definition glquake.h:718
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
Definition glquake.h:609
GLsizei const GLfloat * value
Definition glquake.h:740
GLuint buffer
Definition glquake.h:630
GLenum GLuint GLenum GLsizei length
Definition glquake.h:657
const GLdouble * v
Definition glquake.h:762
GLenum GLenum GLsizei count
Definition glquake.h:656
GLint GLenum GLint GLint y
Definition glquake.h:651
GLint GLenum GLint x
Definition glquake.h:651
GLsizeiptr const GLvoid * data
Definition glquake.h:639
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition glquake.h:657
const GLchar * name
Definition glquake.h:601
GLuint index
Definition glquake.h:629
cvar_t developer
Definition host.c:48
host_static_t host
Definition host.c:41
cvar_t developer_extra
Definition host.c:49
int chat_bufferpos
Definition keys.c:701
int key_linepos
Definition keys.c:35
signed char chat_mode
Definition keys.c:699
char chat_buffer[MAX_INPUTLINE]
Definition keys.c:700
char key_line[MAX_INPUTLINE]
Definition keys.c:34
keydest_t key_dest
Definition keys.c:37
qbool key_insert
Definition keys.c:36
int key_consoleactive
Definition keys.c:38
#define KEY_CONSOLEACTIVE_USER
Definition keys.h:380
@ key_message
Definition keys.h:372
int LHNETADDRESS_FromString(lhnetaddress_t *vaddress, const char *string, int defaultport)
Definition lhnet.c:204
#define max(A, B)
Definition mathlib.h:38
#define min(A, B)
Definition mathlib.h:37
#define bound(min, num, max)
Definition mathlib.h:34
#define VectorCopy(in, out)
Definition mathlib.h:101
#define VectorScale(in, scale, out)
Definition mathlib.h:111
float strlen(string s)
void cmd(string command,...)
float floor(float f)
#define Q2LUMP_ENTITIES
Definition model_q2bsp.h:14
#define Q2BSPVERSION
Definition model_q2bsp.h:7
#define Q3BSPVERSION_IG
Definition model_q3bsp.h:13
#define Q3BSPVERSION_LIVE
Definition model_q3bsp.h:12
#define Q3LUMP_ENTITIES
Definition model_q3bsp.h:15
#define Q3BSPVERSION
Definition model_q3bsp.h:11
#define HL2LUMP_ENTITIES
Definition model_vbsp.h:74
int NetConn_Write(lhnetsocket_t *mysocket, const void *data, int length, const lhnetaddress_t *peeraddress)
Definition netconn.c:758
int NetConn_WriteString(lhnetsocket_t *mysocket, const char *string, const lhnetaddress_t *peeraddress)
Definition netconn.c:783
lhnetsocket_t * NetConn_ChooseClientSocketForAddress(lhnetaddress_t *address)
Definition netconn.c:1198
qbool NetConn_HaveServerPorts(void)
Definition netconn.c:1057
lhnetsocket_t * NetConn_ChooseServerSocketForAddress(lhnetaddress_t *address)
Definition netconn.c:1209
qbool NetConn_HaveClientPorts(void)
Definition netconn.c:1052
void NetConn_OpenServerPorts(int opennetports)
Definition netconn.c:1168
void NetConn_CloseServerPorts(void)
Definition netconn.c:1121
#define NETFLAG_CTL
Definition netconn.h:44
#define NETFLAG_LENGTH_MASK
Definition netconn.h:35
#define CCREP_RCON
Definition netconn.h:130
string message
Definition progsdefs.qc:205
prvm_uint_t ofs
int i
#define MAX_INPUTLINE
maximum size of console commandline, QuakeC strings, and many other text processing buffers
Definition qdefs.h:94
#define MAX_OSPATH
max length of a filesystem pathname
Definition qdefs.h:175
#define ISWHITESPACE(ch)
Definition qdefs.h:184
#define CON_TEXTSIZE
max scrollback buffer characters in console
Definition qdefs.h:95
#define MAX_SCOREBOARDNAME
max length of player name in game
Definition qdefs.h:111
#define MAX_QPATH
max length of a quake game pathname
Definition qdefs.h:169
#define CON_MAXLINES
max scrollback buffer lines in console
Definition qdefs.h:96
#define MAX_SCOREBOARD
max number of players in game at once (255 protocol limit)
Definition qdefs.h:110
#define NULL
Definition qtypes.h:12
uint8_t u8
Definition qtypes.h:35
bool qbool
Definition qtypes.h:9
dp_FragColor r
dp_FragColor g
precision highp float
Definition shader_glsl.h:53
float f
dp_FragColor b
dp_FragColor rgb
ret a
qbool S_LocalSound(const char *sound)
Definition snd_main.c:2246
qbool foundteamchatsound
Definition client.h:929
scoreboard_t * scores
Definition client.h:945
double time
Definition client.h:868
qbool demoplayback
Definition client.h:587
cactive_t state
Definition client.h:568
command interpreter state - the tokenizing and execution of commands, as well as pointers to which cv...
Definition cmd.h:127
unsigned mask
Definition console.h:116
double addtime
used only by console.c
Definition console.h:119
char * start
Definition console.h:114
int height
recalculated line height when needed (-1 to unset)
Definition console.h:120
const char * continuationString
Definition console.c:1805
dp_font_t * font
Definition console.c:1798
char * text
Definition console.h:128
int textsize
Definition console.h:127
Definition cvar.h:66
float value
Definition cvar.h:74
int integer
Definition cvar.h:73
const char * string
Definition cvar.h:71
float maxwidth
Definition draw.h:102
char ** filenames
Definition fs.h:117
int numfilenames
Definition fs.h:116
hl2lump_t lumps[HL2HEADER_LUMPS]
Definition model_vbsp.h:159
int32_t filelen
Definition model_vbsp.h:150
int32_t fileofs
Definition model_vbsp.h:150
double realtime
the accumulated mainloop time since application started (with filtering), without any slowmo or clamp...
Definition host.h:46
int fileofs
Definition bspfile.h:36
int filelen
Definition bspfile.h:36
lump_t lumps[Q2HEADER_LUMPS]
Definition model_q2bsp.h:39
lump_t lumps[Q3HEADER_LUMPS_MAX]
Definition model_q3bsp.h:41
char name[MAX_SCOREBOARDNAME]
Definition client.h:489
char ** strings
Definition filematch.h:31
int outfd
Definition sys.h:149
size_t Sys_TimeString(char buf[], size_t bufsize, const char *timeformat)
Definition sys_shared.c:45
void Sys_Print(const char *text, size_t textlen)
(may) output text to terminal which launched program is POSIX async-signal-safe textlen excludes any ...
Definition sys_shared.c:615
void Sys_Printf(const char *fmt,...)
used to report failures inside Con_Printf()
Definition sys_shared.c:652
sys_t sys
Definition sys_shared.c:42
int Sys_CheckParm(const char *parm)
Definition sys_shared.c:327
#define Thread_DestroyMutex(m)
Definition thread.h:16
qbool Thread_HasThreads(void)
Definition thread_null.c:13
#define Thread_CreateMutex()
Definition thread.h:15
#define Thread_LockMutex(m)
Definition thread.h:17
#define Thread_UnlockMutex(m)
Definition thread.h:18
char * u8_encodech(Uchar ch, size_t *l, char *buf16)
uses u8_fromchar on a static buffer
Definition utf8lib.c:697
cvar_t utf8_enable
Definition utf8lib.c:11
#define u8_getchar(c, e)
Definition utf8lib.h:71
mempool_t * tempmempool
Definition zone.c:794
mempool_t * zonemempool
Definition zone.c:796
#define Mem_Free(mem)
Definition zone.h:96
#define Mem_Alloc(pool, size)
Definition zone.h:92
#define Z_Malloc(size)
Definition zone.h:161
#define Z_Free(data)
Definition zone.h:164