Bug Summary

File:client/cl_console.cpp
Location:line 98, column 29
Description:The left operand of '>>' is a garbage value

Annotated Source Code

1/**
2 * @file
3 * @brief Console related code.
4 */
5
6/*
7All original material Copyright (C) 2002-2011 UFO: Alien Invasion.
8
9Original file from Quake 2 v3.21: quake2-2.31/client/console.c
10Copyright (C) 1997-2001 Id Software, Inc.
11
12This program is free software; you can redistribute it and/or
13modify it under the terms of the GNU General Public License
14as published by the Free Software Foundation; either version 2
15of the License, or (at your option) any later version.
16
17This program is distributed in the hope that it will be useful,
18but WITHOUT ANY WARRANTY; without even the implied warranty of
19MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20
21See the GNU General Public License for more details.
22
23You should have received a copy of the GNU General Public License
24along with this program; if not, write to the Free Software
25Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26
27*/
28
29#include "cl_console.h"
30#include "client.h"
31#include "cgame/cl_game.h"
32#include "input/cl_keys.h"
33#include "renderer/r_draw.h"
34#include "../shared/utf8.h"
35
36#define ColorIndex(c)(((c) - '0') & 0x07) (((c) - '0') & 0x07)
37
38/* set ABGR color values */
39static const uint32_t g_color_table[] =
40{
41 0xFF000000,
42 0xFF0000FF,
43 0xFF00FF00,
44 0xFF00FFFF,
45 0xFFFF0000,
46 0xFFFFFF00,
47 0xFFFF00FF,
48 0xFFFFFFFF
49};
50
51#define CONSOLE_CHAR_ALIGN4 4
52#define NUM_CON_TIMES8 8
53#define CON_TEXTSIZE32768 32768
54#define CONSOLE_CURSOR_CHAR11 11
55#define CONSOLE_HISTORY_FILENAME"history" "history"
56
57typedef struct {
58 bool initialized;
59
60 short text[CON_TEXTSIZE32768];
61 int currentLine; /**< line where next message will be printed */
62 int pos; /**< offset in current line for next print */
63 int displayLine; /**< bottom of console displays this line */
64
65 int lineWidth; /**< characters across screen */
66 int totalLines; /**< total lines in console scrollback */
67
68 int visLines;
69} console_t;
70
71static console_t con;
72static cvar_t *con_notifytime;
73static cvar_t *con_history;
74static cvar_t *con_background;
75const int con_fontHeight = 12;
76const int con_fontWidth = 10;
77const int con_fontShift = 3;
78
79static void Con_Clear (void)
80{
81 unsigned int i;
82 const size_t size = lengthof(con.text)(sizeof(con.text) / sizeof(*(con.text)));
83
84 for (i = 0; i < size; i++)
85 con.text[i] = (CON_COLOR_WHITE7 << 8) | ' ';
86}
87
88/**
89 * @param text The character buffer to draw - color encoded
90 * @param x The x coordinate on the screen
91 * @param y The y coordinate on the screen
92 * @param width Characters to draw
93 */
94static void Con_DrawText (const short *text, int x, int y, size_t width)
95{
96 unsigned int xPos;
97 for (xPos = 0; xPos < width; xPos++) {
4
Loop condition is true. Entering loop body
98 const int currentColor = (text[xPos] >> 8) & 7;
5
The left operand of '>>' is a garbage value
99 R_DrawChar(x + ((xPos + 1) << con_fontShift), y, text[xPos], g_color_table[currentColor]);
100 }
101}
102
103/**
104 * @param txt The character buffer to draw
105 * @param x The x coordinate on the screen
106 * @param y The y coordinate on the screen
107 * @param width Characters to draw
108 */
109void Con_DrawString (const char *txt, int x, int y, unsigned int width)
110{
111 short buf[512], *pos;
112 const size_t size = lengthof(buf)(sizeof(buf) / sizeof(*(buf)));
113 char c;
114 int color;
115
116 if (width > size || strlen(txt) > size)
1
Taking false branch
117 Sys_Error("Overflow in Con_DrawString");
118
119 color = CON_COLOR_WHITE7;
120 pos = buf;
121
122 while ((c = *txt) != 0) {
2
Loop condition is false. Execution continues on line 134
123 if (Q_IsColorString(txt)((txt) && *(txt) == '^' && *((txt) + 1) &&
isalnum(*((txt) + 1)))
) {
124 color = ColorIndex(*(txt + 1))(((*(txt + 1)) - '0') & 0x07);
125 txt += 2;
126 continue;
127 }
128
129 *pos = (color << 8) | c;
130
131 txt++;
132 pos++;
133 }
134 Con_DrawText(buf, x, y, width);
3
Calling 'Con_DrawText'
135}
136
137static void Key_ClearTyping (void)
138{
139 keyLines[editLine][1] = 0; /* clear any typing */
140 keyLinePos = 1;
141}
142
143void Con_ToggleConsole_f (void)
144{
145 Key_ClearTyping();
146
147 if (cls.keyDest == key_console) {
148 Key_SetDest(key_game);
149 } else {
150 Key_SetDest(key_console);
151 }
152}
153
154static void Con_ToggleChat_f (void)
155{
156 Key_ClearTyping();
157
158 if (cls.keyDest == key_console) {
159 if (cls.state == ca_active)
160 Key_SetDest(key_game);
161 } else
162 Key_SetDest(key_console);
163}
164
165/**
166 * @brief Clears the console buffer
167 */
168static void Con_Clear_f (void)
169{
170 Con_Clear();
171}
172
173/**
174 * @brief Scrolls the console
175 * @param[in] scroll Lines to scroll
176 */
177void Con_Scroll (int scroll)
178{
179 con.displayLine += scroll;
180 if (con.displayLine > con.currentLine)
181 con.displayLine = con.currentLine;
182 else if (con.displayLine < 0)
183 con.displayLine = 0;
184}
185
186/**
187 * @brief If the line width has changed, reformat the buffer.
188 */
189void Con_CheckResize (void)
190{
191 int i, j, oldWidth, oldTotalLines, numLines, numChars;
192 short tbuf[CON_TEXTSIZE32768];
193 const int width = (viddef.context.width >> con_fontShift);
194
195 if (width < 1 || width == con.lineWidth)
196 return;
197
198 oldWidth = con.lineWidth;
199 con.lineWidth = width;
200 oldTotalLines = con.totalLines;
201 con.totalLines = CON_TEXTSIZE32768 / con.lineWidth;
202 numLines = oldTotalLines;
203
204 if (con.totalLines < numLines)
205 numLines = con.totalLines;
206
207 numChars = oldWidth;
208
209 if (con.lineWidth < numChars)
210 numChars = con.lineWidth;
211
212 memcpy(tbuf, con.text, sizeof(tbuf));
213 Con_Clear();
214
215 for (i = 0; i < numLines; i++) {
216 for (j = 0; j < numChars; j++) {
217 con.text[(con.totalLines - 1 - i) * con.lineWidth + j] = tbuf[((con.currentLine - i + oldTotalLines) % oldTotalLines) * oldWidth + j];
218 }
219 }
220
221 con.currentLine = con.totalLines - 1;
222 con.displayLine = con.currentLine;
223}
224
225/**
226 * @brief Load the console history
227 * @sa Con_SaveConsoleHistory
228 */
229void Con_LoadConsoleHistory (void)
230{
231 qFILE f;
232 char line[MAXCMDLINE256];
233
234 if (!con_history->integer)
235 return;
236
237 OBJZERO(f)(memset(&((f)), (0), sizeof((f))));
238
239 FS_OpenFile(CONSOLE_HISTORY_FILENAME"history", &f, FILE_READ);
240 if (!f.f)
241 return;
242
243 /* we have to skip the initial line char and the string end char */
244 while (fgets(line, MAXCMDLINE256 - 2, f.f)) {
245 if (line[strlen(line) - 1] == '\n')
246 line[strlen(line) - 1] = 0;
247 Q_strncpyz(&keyLines[editLine][1], line, MAXCMDLINE - 1)Q_strncpyzDebug( &keyLines[editLine][1], line, 256 - 1, "src/client/cl_console.cpp"
, 247 )
;
248 editLine = (editLine + 1) % MAXKEYLINES32;
249 historyLine = editLine;
250 keyLines[editLine][1] = 0;
251 }
252
253 FS_CloseFile(&f);
254}
255
256/**
257 * @brief Stores the console history
258 * @sa Con_LoadConsoleHistory
259 */
260void Con_SaveConsoleHistory (void)
261{
262 int i;
263 qFILE f;
264 const char *lastLine = NULL__null;
265
266 /* maybe con_history is not initialized here (early Sys_Error) */
267 if (!con_history || !con_history->integer)
268 return;
269
270 FS_OpenFile(CONSOLE_HISTORY_FILENAME"history", &f, FILE_WRITE);
271 if (!f.f) {
272 Com_Printf("Can not open " CONSOLE_HISTORY_FILENAME"history" " for writing\n");
273 return;
274 }
275
276 for (i = 0; i < historyLine; i++) {
277 if (lastLine && !strncmp(lastLine, &(keyLines[i][1]), MAXCMDLINE256 - 1))
278 continue;
279
280 lastLine = &(keyLines[i][1]);
281 if (*lastLine) {
282 FS_Write(lastLine, strlen(lastLine), &f);
283 FS_Write("\n", 1, &f);
284 }
285 }
286 FS_CloseFile(&f);
287}
288
289void Con_Init (void)
290{
291 Com_Printf("\n----- console initialization -------\n");
292
293 /* register our commands and cvars */
294 con_notifytime = Cvar_Get("con_notifytime", "10", CVAR_ARCHIVE1, "How many seconds console messages should be shown before they fade away");
295 con_history = Cvar_Get("con_history", "1", CVAR_ARCHIVE1, "Permanent console history");
296 con_background = Cvar_Get("con_background", "1", CVAR_ARCHIVE1, "Console is rendered with background image");
297
298 Cmd_AddCommand("toggleconsole", Con_ToggleConsole_f, N_("Show/hide ufoconsole.")"Show/hide ufoconsole.");
299 Cmd_AddCommand("togglechat", Con_ToggleChat_f);
300 Cmd_AddCommand("clear", Con_Clear_f, "Clear console text");
301
302 /* load console history if con_history is true */
303 Con_LoadConsoleHistory();
304
305 OBJZERO(con)(memset(&((con)), (0), sizeof((con))));
306 con.lineWidth = VID_NORM_WIDTH1024 / con_fontWidth;
307 con.totalLines = lengthof(con.text)(sizeof(con.text) / sizeof(*(con.text))) / con.lineWidth;
308 con.initialized = true;
309
310 Com_Printf("Console initialized.\n");
311}
312
313
314static void Con_Linefeed (void)
315{
316 int i;
317
318 con.pos = 0;
319 if (con.displayLine == con.currentLine)
320 con.displayLine++;
321 con.currentLine++;
322
323 for (i = 0; i < con.lineWidth; i++)
324 con.text[(con.currentLine % con.totalLines) * con.lineWidth + i] = (CON_COLOR_WHITE7 << 8) | ' ';
325}
326
327/**
328 * @brief Handles cursor positioning, line wrapping, etc
329 * All console printing must go through this in order to be logged to disk
330 * If no console is visible, the text will appear at the top of the game window
331 * @sa Sys_ConsoleOutput
332 */
333void Con_Print (const char *txt)
334{
335 int y;
336 int c, l;
337 static bool cr;
338 int color;
339
340 if (!con.initialized)
341 return;
342
343 color = CON_COLOR_WHITE7;
344
345 while ((c = *txt) != 0) {
346 const int charLength = UTF8_char_len(c);
347 if (Q_IsColorString(txt)((txt) && *(txt) == '^' && *((txt) + 1) &&
isalnum(*((txt) + 1)))
) {
348 color = ColorIndex(*(txt + 1))(((*(txt + 1)) - '0') & 0x07);
349 txt += 2;
350 continue;
351 }
352
353 /* count word length */
354 for (l = 0; l < con.lineWidth; l++)
355 if (txt[l] <= ' ')
356 break;
357
358 /* word wrap */
359 if (l != con.lineWidth && (con.pos + l > con.lineWidth))
360 con.pos = 0;
361
362 txt += charLength;
363
364 if (cr) {
365 con.currentLine--;
366 cr = false;
367 }
368
369 if (!con.pos) {
370 Con_Linefeed();
371 }
372
373 if (charLength > 1)
374 c = '.';
375
376 switch (c) {
377 case '\n':
378 con.pos = 0;
379 color = CON_COLOR_WHITE7;
380 break;
381
382 case '\r':
383 con.pos = 0;
384 color = CON_COLOR_WHITE7;
385 cr = true;
386 break;
387
388 default: /* display character and advance */
389 y = con.currentLine % con.totalLines;
390 con.text[y * con.lineWidth + con.pos] = (color << 8) | c;
391 con.pos++;
392 if (con.pos >= con.lineWidth)
393 con.pos = 0;
394 break;
395 }
396 }
397}
398
399/*
400==============================================================================
401DRAWING
402==============================================================================
403*/
404
405/**
406 * @brief Hide the gameconsole if active
407 */
408void Con_Close (void)
409{
410 if (cls.keyDest == key_console)
411 Key_SetDest(key_game);
412}
413
414/**
415 * @brief The input line scrolls horizontally if typing goes beyond the right edge
416 */
417static void Con_DrawInput (void)
418{
419 int y;
420 unsigned int i;
421 short editlinecopy[MAXCMDLINE256], *text;
422 const size_t size = lengthof(editlinecopy)(sizeof(editlinecopy) / sizeof(*(editlinecopy)));
423
424 if (cls.keyDest != key_console && cls.state == ca_active)
425 return; /* don't draw anything (always draw if not active) */
426
427 y = 0;
428 for (i = 0; i < size; i++) {
429 editlinecopy[i] = (CON_COLOR_WHITE7 << 8) | keyLines[editLine][i];
430 if (keyLines[editLine][i] == '\0')
431 break;
432 y++;
433 }
434 text = editlinecopy;
435
436 /* add the cursor frame */
437 if ((int)(CL_Milliseconds() >> 8) & 1) {
438 text[keyLinePos] = (CON_COLOR_WHITE7 << 8) | CONSOLE_CURSOR_CHAR11;
439 if (keyLinePos == y)
440 y++;
441 }
442
443 /* fill out remainder with spaces */
444 for (i = y; i < size; i++)
445 text[i] = (CON_COLOR_WHITE7 << 8) | ' ';
446
447 /* prestep if horizontally scrolling */
448 if (keyLinePos >= con.lineWidth)
449 text += 1 + keyLinePos - con.lineWidth;
450
451 /* draw it */
452 y = con.visLines - con_fontHeight;
453
454 Con_DrawText(text, 0, y - CONSOLE_CHAR_ALIGN4, con.lineWidth);
455}
456
457/**
458 * @brief Draws the console with the solid background
459 */
460void Con_DrawConsole (float frac)
461{
462 int i, x, y;
463 int rows, row;
464 unsigned int lines;
465 short *text;
466 char consoleMessage[128];
467
468 lines = viddef.context.height * frac;
469 if (lines == 0)
470 return;
471
472 if (lines > viddef.context.height)
473 lines = viddef.context.height;
474
475 /* draw the background */
476 if (con_background->integer)
477 R_DrawStretchImage(0, viddef.virtualHeight * (frac - 1) , viddef.virtualWidth, viddef.virtualHeight, R_FindImage("pics/background/conback", it_pic));
478
479 Com_sprintf(consoleMessage, sizeof(consoleMessage), "Hit esc to close - v%s", UFO_VERSION"2.5-dev");
480 {
481 const int len = strlen(consoleMessage);
482 const int versionX = viddef.context.width - (len * con_fontWidth) - CONSOLE_CHAR_ALIGN4;
483 const int versionY = lines - (con_fontHeight + CONSOLE_CHAR_ALIGN4);
484 const uint32_t color = g_color_table[CON_COLOR_WHITE7];
485
486 for (x = 0; x < len; x++)
487 R_DrawChar(versionX + x * con_fontWidth, versionY, consoleMessage[x], color);
488 }
489
490 /* draw the text */
491 con.visLines = lines;
492
493 rows = (lines - con_fontHeight * 2) >> con_fontShift; /* rows of text to draw */
494
495 y = lines - con_fontHeight * 3;
496
497 /* draw from the bottom up */
498 if (con.displayLine != con.currentLine) {
499 const uint32_t color = g_color_table[CON_COLOR_GREEN2];
500 /* draw arrows to show the buffer is backscrolled */
501 for (x = 0; x < con.lineWidth; x += 4)
502 R_DrawChar((x + 1) << con_fontShift, y, '^', color);
503
504 y -= con_fontHeight;
505 rows--;
506 }
507
508 row = con.displayLine;
509 for (i = 0; i < rows; i++, y -= con_fontHeight, row--) {
510 if (row < 0)
511 break;
512 if (con.currentLine - row >= con.totalLines)
513 break; /* past scrollback wrap point */
514
515 text = con.text + (row % con.totalLines) * con.lineWidth;
516
517 Con_DrawText(text, 0, y, con.lineWidth);
518 }
519
520 /* draw the input prompt, user text, and cursor if desired */
521 Con_DrawInput();
522}