OpenMoHAA 0.82.0
Loading...
Searching...
No Matches
gsDebug.c
1
3#include "gsCommon.h"
4#include "gsDebug.h"
5//#include <stdio.h>
6//#include <stdarg.h>
7
8
9// THIS FILE ONLY INCLUDED WHEN USING GAMESPY DEBUG FUNCTIONS
10// (don't put this above the header includes or VC will whine
11#ifdef GSI_COMMON_DEBUG
12
13#if defined(_NITRO)
14#include "../../common/nitro/screen.h"
15#define printf Printf
16#define vprintf VPrintf
17#endif
18
21// Static debug data
22static struct GSIDebugInstance gGSIDebugInstance; // simple singleton "class"
23
24// Line prefixes, e.g. "[ cat][type][ lev] text"
25char* gGSIDebugCatStrings[GSIDebugCat_Count] =
26{
27 " APP", " GP ", "PEER", " QR2", " SB", " V2", " AD", " NN", "HTTP", "CDKY", " CMN"
28};
29char* gGSIDebugTypeStrings[GSIDebugType_Count] =
30{
31 " NET", "FILE", " MEM", "STAT", "MISC"
32};
33char* gGSIDebugLevelStrings[GSIDebugLevel_Count] =
34{
35 "*ERR", "****", "----", " ", " ", " ", " ->"
36};
37char* gGSIDebugLevelDescriptionStrings[8] =
38{
39 "None", "<None+1>", "<Normal>", "<Debug>", "<Verbose>", "<Verbose+1>", "<Verbose+2>", "<Hardcore>"
40};
41
44// utility to convert bit flag back to base (e.g. 1<<2 returns 2)
45static gsi_u32 gsiDebugLog2(gsi_u32 theInt)
46{
47 gsi_u32 total = 0;
48 while (theInt > 1)
49 {
50 theInt = theInt >> 1;
51 total++;
52 }
53 return total;
54}
55
56
57// default supplied debug function, will receive debug text
58// this is platform specific
59static void gsiDebugCallback(GSIDebugCategory category, GSIDebugType type,
60 GSIDebugLevel level, const char * format, va_list params)
61{
62 #if defined(_PSP)
63 // Output line prefix
64 vprintf(format, params);
65 //gsDebugTTyPrint(string);
66 #elif defined(_PS2)
67 // Output line prefix
68 vprintf(format, params);
69
70 #elif defined(_PS3)
71 // Output line prefix
72 vprintf(format, params);
73
74 #elif defined(_WIN32)
75 static char string[256];
76 vsprintf(string, format, params);
77 OutputDebugStringA(string);
78
79 #elif defined(_LINUX) || defined(_MACOSX)
80 //static char string[256];
81 //vsprintf(string, format, params);
82 vprintf(format, params);
83 #elif defined(_NITRO)
84 VPrintf(format, params);
85 #elif defined(_REVOLUTION)
86 static char string[256];
87 vsprintf(string, format, params);
88 OSReport(string);
89 #else
90 va_list argptr;
91 static char string[256];
92 va_start(argptr, format);
93 vsprintf(string, format, argptr);
94 va_end(argptr);
95 gsDebugTTyPrint(string);
96 #endif
97
98 GSI_UNUSED(category);
99 GSI_UNUSED(type);
100 GSI_UNUSED(level);
101}
102
103
104
105
106
109// process debug output
110void gsDebugVaList(GSIDebugCategory theCat, GSIDebugType theType,
111 GSIDebugLevel theLevel, const char* theTokenStr,
112 va_list theParamList)
113{
114 // Retrieve the current debug level
115 GSIDebugLevel aCurLevel;
116
117 // Verify Parameters
118 assert(theCat <= GSIDebugCat_Count);
119 assert(theType <= GSIDebugType_Count);
120 assert(theLevel <= (1<<GSIDebugLevel_Count));
121 assert(theTokenStr);
122
123 // Make thread safe
124 if (gGSIDebugInstance.mInitialized == 0)
125 {
126 // Warning: Slight race condition risk here the first time
127 // gsDebug functions are used.
128 // The risk is minimal since you usually set
129 // debug levels and targets at program startup
130 gGSIDebugInstance.mInitialized = 1;
131 gsiInitializeCriticalSection(&gGSIDebugInstance.mDebugCrit);
132 }
133
134 gsiEnterCriticalSection(&gGSIDebugInstance.mDebugCrit);
135
136 // Are we currently logging this type and level?
137 aCurLevel = gGSIDebugInstance.mGSIDebugLevel[theCat][theType];
138 if (aCurLevel & theLevel) // check the flag
139 {
140#if !defined(_NITRO)
141 // Output line prefix
142 if (gGSIDebugInstance.mGSIDebugFile)
143 {
144 fprintf(gGSIDebugInstance.mGSIDebugFile, "[%s][%s][%s] ",
145 gGSIDebugCatStrings[theCat],
146 gGSIDebugTypeStrings[theType],
147 gGSIDebugLevelStrings[gsiDebugLog2(theLevel)]);
148
149 // Output to file
150 vfprintf(gGSIDebugInstance.mGSIDebugFile, theTokenStr,
151 theParamList);
152 }
153#endif
154 // Output to developer function if provided
155 if (gGSIDebugInstance.mDebugCallback != NULL)
156 {
157 (*gGSIDebugInstance.mDebugCallback)(theCat, theType, theLevel,
158 theTokenStr, theParamList);
159 }
160 else
161 {
162 gsiDebugCallback(theCat, theType, theLevel,
163 theTokenStr, theParamList);
164 }
165 }
166
167 gsiLeaveCriticalSection(&gGSIDebugInstance.mDebugCrit);
168}
169
170
173// process debug output
174void gsDebugFormat(GSIDebugCategory theCat, GSIDebugType theType,
175 GSIDebugLevel theLevel, const char* theTokenStr,
176 ...)
177{
178 va_list aParameterList;
179
180 // Verify Parameters
181 assert(theCat <= GSIDebugCat_Count);
182 assert(theType <= GSIDebugType_Count);
183 assert(theLevel <= (1<<GSIDebugLevel_Count));
184 assert(theTokenStr);
185
186 // Find start of var arg list
187 va_start(aParameterList, theTokenStr);
188
189 // Pass to VA version
190 gsDebugVaList(theCat, theType, theLevel, theTokenStr, aParameterList);
191}
192
193
196// Converts binary buffer to memory view form:
197// 0000 0000 0000 0000 0000 0000 0000 0000 ................
198static void HexEncode16(const char* theInStream, char* theOutStream,
199 unsigned int theInLen)
200{
201 const int aRowWidth = 64; // width of the output
202 const char aReplaceChar = '.'; // Replace non print characters
203 const int aTextOffSet = 41; // text comes after hex bytes
204 char* aTextOutStream = (theOutStream+aTextOffSet); // set the write ptr
205 const unsigned int aWriteBit = theInLen & 1; // write on odd or even bytes?
206
207 assert(theInLen <= 16);
208
209 // Set buffer to ' '
210 memset(theOutStream, ' ', aRowWidth);
211
212 // Convert characters one at a time
213 while(theInLen--)
214 {
215 // Read the next byte
216 unsigned char aChar = (unsigned char)(*theInStream++);
217
218 // Write one byte in hex form
219 sprintf(theOutStream, "%02X", aChar);
220
221 // Write the printable character
222 if (isgraph(aChar))
223 *(aTextOutStream++) = (char)aChar;
224 else
225 *(aTextOutStream++) = aReplaceChar;
226
227 // Move to next hex byte
228 theOutStream += 2;
229
230 // Insert a space every other byte
231 if ((theInLen & 1) == aWriteBit)
232 *theOutStream++ = ' ';
233 }
234
235 // Remove NULL terminator from last sprintf
236 *theOutStream = ' ';
237
238 // NULL terminate the full string
239 *(aTextOutStream) = '\0';
240}
241
242
245// Write binary data as B64 bytes (40 bytes per line)
246void gsDebugBinary(GSIDebugCategory theCat, GSIDebugType theType,
247 GSIDebugLevel theLevel, const char* theBuffer, gsi_i32 theLength)
248{
249 int aBytesLeft = theLength;
250 const char* aReadPos = theBuffer;
251 char aHexStr[80];
252
253 // convert and display in 40 byte segments
254 while(aBytesLeft > 0)
255 {
256 gsi_i32 aBytesToRead = min(aBytesLeft, 16);
257
258 HexEncode16(aReadPos, aHexStr, (unsigned int)aBytesToRead);
259 gsDebugFormat(theCat, theType, theLevel, " %s\r\n", aHexStr);
260
261 aReadPos += aBytesToRead;
262 aBytesLeft -= aBytesToRead;
263 };
264}
265
266
269void gsSetDebugLevel(GSIDebugCategory theCat, GSIDebugType theType,
270 GSIDebugLevel theLevel)
271{
272 // Verify Parameters
273 assert(theCat <= GSIDebugCat_Count);
274 assert(theType <= GSIDebugType_Count);
275
276 // Set for all categories?
277 if (theCat == GSIDebugCat_Count)
278 {
279 int i=0;
280 for (; i<GSIDebugCat_Count; i++)
281 gsSetDebugLevel((GSIDebugCategory)i, theType, theLevel);
282
283 gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc,
284 GSIDebugLevel_Debug,
285 "Debug level set to %s for all categories (SDKs)\r\n",
286 gGSIDebugLevelDescriptionStrings[gsiDebugLog2(theLevel)]);
287
288 return;
289 }
290
291 // Set for all types?
292 if (theType == GSIDebugType_Count)
293 {
294 int i=0;
295 for (; i<GSIDebugType_Count; i++)
296 gsSetDebugLevel(theCat, (GSIDebugType)i, theLevel);
297
298 gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc,
299 GSIDebugLevel_Debug,
300 "Debug level set to %s for all types\r\n",
301 gGSIDebugLevelDescriptionStrings[gsiDebugLog2(theLevel)]);
302 return;
303 }
304
305 // Is the new level different from the old?
306 if (gGSIDebugInstance.mGSIDebugLevel[theCat][theType] != theLevel)
307 {
308 // Notify of the change
309 gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc,
310 GSIDebugLevel_Comment,
311 "Changing debug level: [%s][%s][%02X]\r\n",
312 gGSIDebugCatStrings[theCat],
313 gGSIDebugTypeStrings[theType],
314 theLevel );
315 gGSIDebugInstance.mGSIDebugLevel[theCat][theType] = theLevel;
316 }
317}
318
319#if !defined(_NITRO)
320
323// Set the debug output file to an already open file
324// Set to "stdout" for console output
325void gsSetDebugFile(FILE* theFile)
326{
327 if (theFile != gGSIDebugInstance.mGSIDebugFile)
328 {
329 // If the old file is valid, notify it of the closing
330 if (gGSIDebugInstance.mGSIDebugFile != NULL)
331 {
332 gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc,
333 GSIDebugLevel_Comment, "Debug disabled in this file\r\n");
334 }
335
336 // If the new file is valid, notify it of the opening
337 {
338 gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc,
339 GSIDebugLevel_Comment, "Debug enabled in this file\r\n");
340 }
341
342 gGSIDebugInstance.mGSIDebugFile = theFile;
343 }
344}
345
346
349// Opens and sets the debug output file
350FILE* gsOpenDebugFile(const char* theFileName)
351{
352 // The new file
353 FILE* aFile = NULL;
354
355 // Verify parameters
356 assert(theFileName != NULL);
357
358 // Open the new file (clear contents)
359 aFile = fopen(theFileName, "w+");
360 if (aFile != NULL)
361 gsSetDebugFile(aFile);
362
363 return aFile;
364}
365
366
369// Retrieve the current debug file (if any)
370FILE* gsGetDebugFile()
371{
372 return gGSIDebugInstance.mGSIDebugFile;
373}
374
375#endif
376
379// Set the developer callback
380void gsSetDebugCallback(GSIDebugCallback theCallback)
381{
382 gGSIDebugInstance.mDebugCallback = theCallback;
383}
384
385
388#endif // GSI_COMMON_DEBUG