Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
debug_cmd.cpp
Go to the documentation of this file.
1/*
2** Command & Conquer Generals Zero Hour(tm)
3** Copyright 2025 Electronic Arts Inc.
4**
5** This program is free software: you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation, either version 3 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
20// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/debug_cmd.cpp $
21// $Author: mhoffe $
22// $Revision: #1 $
23// $DateTime: 2003/07/03 11:55:26 $
24//
25// ©2003 Electronic Arts
26//
27// Debug command group 'debug'
29#include "_pch.h"
30#include <process.h>
31
32bool DebugCmdInterfaceDebug::Execute(class Debug& dbg, const char *cmd,
33 CommandMode cmdmode, unsigned argn,
34 const char * const * argv)
35{
36 // just for convenience...
37 bool normalMode=cmdmode==CommandMode::Normal;
38
39 if (!strcmp(cmd,"help"))
40 {
41 if (!normalMode)
42 return true;
43
44 if (!argn)
45 {
46 dbg << "debug group help:\n"
47 " list, io, alwaysflush, timestamp, exit, clear, add, view\n";
48 return true;
49 }
50 else if (!strcmp(argv[0],"list"))
51 {
52 dbg << "list (g|l|d|a|c) [ <pattern> ]\n"
53 "\n"
54 "Shows some or all items of a specific type.\n"
55 "\n"
56 "The following items are supported:\n"
57 "- g: command groups\n"
58 "- l: log groups (only those encountered yet)\n"
59 "- d: log groups with descriptions (only those that have descriptions)\n"
60 "- a: asserts/crashes (only those hit yet)\n"
61 "- c: checks (only those failed yet)\n"
62 "\n"
63 "If a pattern is specified only items matching\n"
64 "that pattern are shown. A pattern can contain\n"
65 "any character, letter, or a wildcard '*'.\n"
66 "\n"
67 "Please note that assert, crashes, and check items have\n"
68 "their line number appended to the current file name,\n"
69 "e.g. debug.cpp(13).\n";
70 return true;
71 }
72 else if (!strcmp(argv[0],"io"))
73 {
74 dbg << "io <I/O Class> <cmd> { <param> }]\n"
75 "\n"
76 "Issues a I/O class command. I/O class commands are used\n"
77 "for determining where all log output should be sent. \n"
78 "Please check the list of \ref debug_ioclasses for a list\n"
79 "of existing I/O classes.\n"
80 "\n"
81 "Each existing I/O class must accept at least the\n"
82 "following two commands: 'add' and 'remove'. Usually\n"
83 "after a class has been added it reacts to the 'help'\n"
84 "command as well.\n"
85 "\n"
86 "If the command is entered without any parameters a list\n"
87 "of active I/O classes is shown. Typing 'io ?' retrieves\n"
88 "a list of possible I/O classes.\n";
89 return true;
90 }
91 else if (!strcmp(argv[0],"alwaysflush"))
92 {
93 dbg << "alwaysflush [ (+|-) ]\n\n"
94 "Enables/disables flushing after each new entry in\n"
95 "the log file (default: off).\n";
96 return true;
97 }
98 else if (!strcmp(argv[0],"timestamp"))
99 {
100 dbg << "timestamp [ (+|-) ]\n\n"
101 "Enables/disables timestamping each log entry\n"
102 "(default: off).\n";
103 return true;
104 }
105 else if (!strcmp(argv[0],"exit"))
106 {
107 dbg << "exit\n\nExits program immediately.\n";
108 return true;
109 }
110 else if (!strcmp(argv[0],"clear"))
111 {
112 dbg << "clear (l|a|c)\n\n"
113 "Clears the given inclusion/exclusion list\n"
114 "(l=logs, a=asserts/crashes, c=checks).\n";
115 return true;
116 }
117 else if (!strcmp(argv[0],"add"))
118 {
119 dbg << "add (l|a|c) (+|-) <pattern>\n"
120 "\n"
121 "Adds a pattern to the given list (l=logs, \n"
122 "a=asserts/crashes, c=checks). By default all\n"
123 "asserts, crashes, and checks are active, all logs\n"
124 "inactive. Each item is then checked \n"
125 "against all pattern in the respective\n"
126 "list. If a match is found the active/inactive\n"
127 "state is modified accordingly (+ for active,\n"
128 "- for inactive). The final state is always\n"
129 "the last match.";
130 return true;
131 }
132 else if (!strcmp(argv[0],"view"))
133 {
134 dbg << "view [ (l|a|c) ]\n\n"
135 "Shows the active pattern for the given list\n"
136 "(l=logs, a=asserts/crashes, c=checks).\n";
137 return true;
138 }
139 return false;
140 }
141 if (!strcmp(cmd,"list"))
142 {
143 const char *pattern=argn>=2?argv[1]:"*";
144
145 switch(argn?*argv[0]:0)
146 {
147 case 'g':
148 {
149 if (normalMode)
150 dbg << "Command groups:\n";
151 for (Debug::CmdInterfaceListEntry *cur=dbg.firstCmdGroup;cur;cur=cur->next)
152 if (Debug::SimpleMatch(cur->group,pattern))
153 dbg << cur->group << "\n";
154 }
155 break;
156 case 'l':
157 case 'd':
158 {
159 if (normalMode)
160 dbg << "Logs:\n";
161 for (Debug::KnownLogGroupList *cur=dbg.firstLogGroup;cur;cur=cur->next)
162 if (Debug::SimpleMatch(cur->nameGroup,pattern)&&
163 (*argv[0]=='l'||cur->descr))
164 {
165 dbg << cur->nameGroup;
166 if (cur->descr)
167 dbg << " (" << cur->descr << ")";
168 dbg << "\n";
169 }
170 }
171 break;
172 case 'a':
173 case 'c':
174 {
175 if (normalMode)
176 dbg << (*argv[0]=='a'?"Asserts/Crashes:\n":"Checks:\n");
177 unsigned mask=*argv[0]=='a'?Debug::FrameTypeAssert:Debug::FrameTypeCheck;
178 for (unsigned k=0;k<Debug::FRAME_HASH_SIZE;k++)
179 {
180 for (Debug::FrameHashEntry *cur=dbg.frameHash[k];cur;cur=cur->next)
181 {
182 if (!(cur->frameType&mask))
183 continue;
184
185 char help[256];
186 wsprintf(help,"%s(%i)",cur->fileOrGroup,cur->line);
187 if (Debug::SimpleMatch(help,pattern))
188 {
189 dbg << help << " (" << cur->hits << " hits)";
190 if (cur->status==Debug::Skip)
191 dbg << " [off]";
192 dbg << "\n";
193 }
194 }
195 }
196 }
197 break;
198 default:
199 dbg << "Unknown item type, see help.";
200 }
201
202 return true;
203 }
204 if (!strcmp(cmd,"io"))
205 {
206 // cmd: io
207 if (!argn||!strcmp(argv[0],"?"))
208 {
209 // show active/all I/O classes
210 if (normalMode)
211 dbg << (argn?"Possible:\n":"Active:\n");
212
213 bool hadItem=false;
214 for (Debug::IOFactoryListEntry *cur=dbg.firstIOFactory;cur;cur=cur->next)
215 {
216 if (!argn&&!cur->io)
217 continue;
218
219 hadItem=true;
220 dbg << cur->ioID << " (" << cur->descr << ")\n";
221 }
222 if (normalMode&&!hadItem)
223 dbg << "(none)\n";
224 }
225 else
226 {
227 // regular I/O command
228
229 // find I/O class
230 for (Debug::IOFactoryListEntry *cur=dbg.firstIOFactory;cur;cur=cur->next)
231 if (!strcmp(argv[0],cur->ioID))
232 break;
233 if (!cur)
234 {
235 dbg << "Unknown I/O class " << argv[0];
236 return true; // still return true because we knew the command
237 }
238
239 if (argn>1)
240 {
241 // 'add' command?
242 if (!strcmp(argv[1],"add"))
243 {
244 if (cur->io)
245 {
246 dbg << "I/O class already added";
247 return true;
248 }
249 cur->io=cur->factory();
250 if (!cur->io)
251 {
252 dbg << "I/O class factory failed";
253 return true;
254 }
255 }
256 // 'remove' command?
257 if (!strcmp(argv[1],"remove"))
258 {
259 if (cur->io)
260 {
261 cur->io->Delete();
262 cur->io=NULL;
263 }
264 return true;
265 }
266 }
267
268 // now pass along I/O command
269 if (!cur->io)
270 {
271 dbg << "Add I/O class first";
272 return true;
273 }
274
275 cur->io->Execute(dbg,argn>1?argv[1]:NULL,!normalMode,argn>1?argn-2:0,argv+2);
276 }
277 return true;
278 }
279 if (!strcmp(cmd,"alwaysflush"))
280 {
281 if (argn)
282 {
283 if (*argv[0]=='+')
284 dbg.alwaysFlush=true;
285 if (*argv[0]=='-')
286 dbg.alwaysFlush=false;
287 }
288 if (normalMode)
289 dbg << "Always flush: " << (dbg.alwaysFlush?"on":"off");
290 else
291 dbg << (dbg.alwaysFlush?"1":"0");
292
293 return true;
294 }
295 if (!strcmp(cmd,"timestamp"))
296 {
297 if (argn)
298 {
299 if (*argv[0]=='+')
300 dbg.timeStamp=true;
301 if (*argv[0]=='-')
302 dbg.timeStamp=false;
303 }
304 if (normalMode)
305 dbg << "Timestamp: " << (dbg.timeStamp?"on":"off");
306 else
307 dbg << (dbg.timeStamp?"1":"0");
308
309 return true;
310 }
311 if (!strcmp(cmd,"exit"))
312 {
313 exit(1);
314 return true;
315 }
316 if (!strcmp(cmd,"clear")||
317 !strcmp(cmd,"add")||
318 !strcmp(cmd,"view"))
319 {
320 unsigned mask=0;
321 if (argn)
322 {
323 for (const char *p=argv[0];*p;p++)
324 {
325 switch(*p)
326 {
327 case 'l': mask|=Debug::FrameTypeLog; break;
328 case 'a': mask|=Debug::FrameTypeAssert; break;
329 case 'c': mask|=Debug::FrameTypeCheck; break;
330 }
331 }
332 }
333 if (!mask)
334 mask=0xffffffff;
335
336 bool modified=false;
337 if (!strcmp(cmd,"clear"))
338 {
339 // remove some (or all) pattern
340 const char *pattern=argn<2?"*":argv[1];
341 for (Debug::PatternListEntry **entryPtr=&dbg.firstPatternEntry;*entryPtr;)
342 {
343 if ( (((*entryPtr)->frameTypes&mask)!=0)
344 && Debug::SimpleMatch((*entryPtr)->pattern,pattern) )
345 {
346 // remove this entry
347 modified=true;
348 Debug::PatternListEntry *cur=*entryPtr;
349 *entryPtr=cur->next;
350 DebugFreeMemory(cur->pattern);
351 DebugFreeMemory(cur);
352 }
353 else
354 entryPtr=&((*entryPtr)->next);
355 }
356
357 // must fixup lastPatternEntry now
358 if (dbg.firstPatternEntry)
359 {
360 for (Debug::PatternListEntry *cur=dbg.firstPatternEntry;cur->next;cur=cur->next);
361 dbg.lastPatternEntry=cur;
362 }
363 else
364 dbg.lastPatternEntry=NULL;
365 }
366 if (!strcmp(cmd,"add"))
367 {
368 // add a pattern
369 if (argn<3)
370 dbg << "Please specify mode and pattern";
371 else
372 {
373 dbg.AddPatternEntry(mask,*argv[1]=='+',argv[2]);
374 modified=true;
375 }
376 }
377 if (!strcmp(cmd,"view"))
378 {
379 // show list of defined patterns
380 for (Debug::PatternListEntry *cur=dbg.firstPatternEntry;cur;cur=cur->next)
381 {
382 if (!(cur->frameTypes&mask))
383 continue;
384
385 if (cur->frameTypes&Debug::FrameTypeLog) dbg << "l";
386 if (cur->frameTypes&Debug::FrameTypeAssert) dbg << "a";
387 if (cur->frameTypes&Debug::FrameTypeCheck) dbg << "c";
388
389 dbg << (cur->isActive?" + ":" - ") << cur->pattern << "\n";
390 }
391 }
392
393 if (modified)
394 {
395 // pattern list was modified, set all frame entries statuses to Unknown
396 for (unsigned k=0;k<Debug::FRAME_HASH_SIZE;k++)
397 for (Debug::FrameHashEntry *cur=dbg.frameHash[k];cur;cur=cur->next)
398 cur->status=Debug::Unknown;
399 }
400 return true;
401 }
402
403 // unknown command
404 return false;
405}
#define NULL
Definition BaseType.h:92
virtual bool Execute(class Debug &dbg, const char *cmd, CommandMode cmdmode, unsigned argn, const char *const *argv)
Execute the given command.
Definition debug_cmd.cpp:32
CommandMode
possible command modes
Definition debug_cmd.h:67
@ Normal
normal command mode
Definition debug_cmd.h:69
Debug module main class (singleton).
Definition debug_debug.h:45
static bool SimpleMatch(const char *str, const char *pattern)
void DebugFreeMemory(void *ptr)