1// tPrint.h 
2// 
3// Formatted print functions that improve upon the standard printf family of functions. The functions found here 
4// support custom type handlers for things like vectors, matrices, and quaternions. They have more robust support for 
5// different type sizes and can print integral types in a variety of bases. Redirection via a callback as well as 
6// visibility channels are also supported. 
7// 
8// Copyright (c) 2004-2006, 2015, 2017, 2019, 2020 Tristan Grimmer. 
9// Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby 
10// granted, provided that the above copyright notice and this permission notice appear in all copies. 
11// 
12// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL 
13// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 
14// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 
15// AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 
16// PERFORMANCE OF THIS SOFTWARE. 
17 
18#pragma once 
19#include <Foundation/tString.h> 
20#include <Foundation/tFixInt.h> 
21#include <Math/tLinearAlgebra.h> 
22 
23 
24namespace tSystem 
25
26 // If more than 64 channels are needed, instead of using a uint64, something like a tBitField<128> would be a 
27 // drop-in replacement. Initialization of values could use the aggregate construction syntax. Something like: 
28 // typedef tBitField<128> Channel; 
29 // const Channel Channel_Core = { 0x0000000000000000ull, 0x0000000000000002ull }; 
30 typedef uint64 tChannel
31 const tChannel tChannel_None = 0x0000000000000000ull
32 
33 const tChannel tChannel_Default = 0x0000000000000001ull
34 const tChannel tChannel_Core = 0x0000000000000002ull
35 const tChannel tChannel_Gameplay = 0x0000000000000004ull
36 const tChannel tChannel_Physics = 0x0000000000000008ull
37 const tChannel tChannel_Sound = 0x0000000000000010ull
38 const tChannel tChannel_Rendering = 0x0000000000000020ull
39 const tChannel tChannel_AI = 0x0000000000000040ull
40 const tChannel tChannel_Input = 0x0000000000000080ull
41 
42 const tChannel tChannel_User0 = 0x0000000000000100ull
43 const tChannel tChannel_User1 = 0x0000000000000200ull
44 const tChannel tChannel_User2 = 0x0000000000000400ull
45 const tChannel tChannel_User3 = 0x0000000000000800ull
46 const tChannel tChannel_User4 = 0x0000000000001000ull
47 const tChannel tChannel_User5 = 0x0000000000002000ull
48 const tChannel tChannel_User6 = 0x0000000000004000ull
49 const tChannel tChannel_User7 = 0x0000000000008000ull
50 
51 const tChannel tChannel_TestResult = 0x0000000000010000ull
52 const tChannel tChannel_All = 0xFFFFFFFFFFFFFFFFull
53 const tChannel tChannel_Systems = tChannel_Default | tChannel_Core
54 tChannel_Gameplay | tChannel_Physics
55 tChannel_Sound | tChannel_Rendering
56 tChannel_AI | tChannel_Input
57 const tChannel tChannel_Users = tChannel_User0 | tChannel_User1
58 tChannel_User2 | tChannel_User3
59 tChannel_User4 | tChannel_User5
60 tChannel_User6 | tChannel_User7
61 const tChannel tChannel_Tristan = tChannel_User0
62 
63 // To only see specific channels, simply call this with your machine name and the bitwise or of the channels you 
64 // wish to see (on your machine). If this is not called you will see the Systems channels. For many programmers 
65 // the right choice is something like: Channel_Systems | Channel_ProgrammerName. Do not call a function to retrieve 
66 // the machineName dynamically or you will turn on the supplied channels for everyone. Instead, the intention is 
67 // there will be multiple tRegister calls. One for each dev that wants specific channels on. 
68 void tRegister(const char* machineName, tChannel channelsToSee); 
69 void tRegister(uint32 machineNameHash, tChannel channelsToSee); 
70 
71 // If you wish top turn on or off channels regardless of computer name, just call this with the channels you want. 
72 // Any channel not specified will no longer be displayed. 
73 void tSetChannels(tChannel channelsToSee); 
74 
75 // After all print formatting, a simple stream output function is called, possibly multiple times, for the Print, 
76 // tPrintf, and tvPrintf functions. By default those functions output to stdout. By setting the OutputCallback 
77 // function below, all output normally destined for stdout may be redirected to wherever you like. Calling with 
78 // nullptr resets to no redirection of stdout output. The 'text' supplied to the callback has 'numChars' 
79 // non-zero characters. The 'numChars+1'th character of 'text' IS guaranteed to be a '\0' if you want to treat 
80 // the text as a null-terminated string. 
81 typedef void RedirectCallback(const char* text, int numChars); 
82 void tSetStdoutRedirectCallback(RedirectCallback = nullptr); 
83 
84 // Windows only. Sets supplementary output to include any attached debugger. Defaults to true. Only output 
85 // normally destined to stdout will also be sent to the debugger. If a StdoutRedirectCallback is set, it will 
86 // still be called regardless of what you call SetSupplementaryDebuggerOutput with. 
87 void tSetSupplementaryDebuggerOutput(bool enable = true); 
88 
89 // This is a non-formatting print. Just prints the string you give it to the supplied FileHandle. If the supplied 
90 // FileHandle is set to 0 then stdout is used. When stdout is the destination this function performs filtering on 
91 // the characters that are printed. On some platforms there are unprintable stdout characters that this function 
92 // will skip. If FileHandle is 0 and an OutputCallback is specified the callback is called without any filtering. 
93 // Returns the actual number of characters printed which, therefore, may be less than the string length. No 
94 // filtering is done if FileHandle is non-zero. Note that this return value is NOT used by other functions in this 
95 // header like tPrintf due to the filtering. Not that this function ignores output channels. 
96 int tPrint(const char* string, tFileHandle); 
97 
98 // Same as above but will only print to stdout if the channel is active. Essentially it calls the above print to 
99 // output to stdout if the channel is active. 
100 int tPrint(const char* string, tChannel channels = tChannel_Default); 
101 
102 // Note also that the default ANSI %f precision is 6. Tacent uses 4 by default, but you can globally change it 
103 // with this. 
104 void tSetDefaultPrecision(int precision); 
105 int tGetDefaultPrecision(); 
106}; 
107 
108 
109// The following print functions return the number of characters written to either stdout or to the supplied buffer. 
110// Format specification strings take the form below, with [] indicating an optional field. 
111// 
112// %[flags][width][.precision][:typeSizeElements][!typeSizeBytes][|typeSizeBits]type 
113// 
114// The format string is a superset of the ANSI standard for printf. It adds more types (vectors and matrices), 
115// consistent typesize fields and support for extra flags, including an alternative presentation flag. See 
116// http://www.cplusplus.com/reference/cstdio/printf/ for the standard types supported. 
117// 
118// [flags] 
119// Must be one or more of: - + SPACE 0 # _ ' 
120// 
121// Standard: hyphen (-) means left justify. Plus (+) means show sign for numeric types. # means force decimal 
122// point for e, E, f, g, and G. It also means prefix with 0, 0x, or 0X for o, x, and X. 
123// Enhanced: Underscore (_) or single-quote (') chooses a more readable decorative or alternative printing method. 
124// Integral Types: 
125// For built-in integral types, an _ inserts an underscore every 4 characters starting from the 
126// right. Handy for making binary values readable. For Tacent integer types like tint128 and 
127// tuint256, the spacing is every 8 characters. 
128// For any integral type, a ' will place a comma every 3 digits starting from thr right. Makes 
129// big integers readable. eg. 23,456,789. This is not really an enhancement as of POSIX 2008. 
130// Matrix Types: 
131// A _ will print the 4x4 (or 2x2) matrix in 4 (or 2) separate rows surrounded by square [] 
132// brackets. Uses a default width of 9 and precision of 4, resulting in 1234.5678 for each 
133// element. Default expected matrix size is :16 (a 4x4 matrix). If you pass in a 2x2, you must 
134// specify the typesize. 
135// Vector Types: 
136// A _ causes just the components (space separated) to print. No decoration. By convention (a, b) 
137// is shorthand for the column vector: [ a 
138// b ] 
139// Default expected vector size is :3 (3 elements). If you pass in a 2 or 4 component vector you 
140// must specify the size. 
141// 
142// [width] 
143// A number representing the minimum num chars printed, or a * to indicate read width from the vararg list. 
144// 
145// [precision] 
146// A number representing decimal accuracy when printing floats, or a * to indicate read precision from the vararg list. 
147// 
148// [typeSize] 
149// A number after a colon (:) or a bang (!) or a pipe (|). This is not ANSI (ANSI ones are the odd h, l, ll, I32, I64). 
150// The colon means to interpret the number following as how many 32bit elements there are in the type. For example, :2, 
151// :3, :4 may be used with the vector 'v' type to indicate how many components are present. The bang (!) means 
152// interpret the number as a byte (octet I suppose, but really, what processor now days has a 7-bit byte? 32-bit chars 
153// are much more common). A value after a pipe symbol means the number is interpreted as a number of bits. For example, 
154// |32 or |64 may be used with integer types d, i, o, u, x, X, and b to specify the bit-size of the integer to print. 
155// 
156// [type] 
157// A single letter chosen from the types below: 
158// Integer: b o d i u x X For these types 'i' is same as 'd'. 'o' is octal. 'b' is binary. Handles Tacent 
159// integer types tint128, tint256, as well as all the built-in integral types. 
160// Pointer: p ISO C. Similar to %#010X (32bit systems) and %#018X (on 64bit systems) with the 
161// following two exceptions: 
162// a) The prefix 0x (lower case x) is used with capital ABCDEF (normally these 
163// are forced to match). 
164// b) The prefix is always used, even if the value is 0 (which is not the case 
165// for # in general). 
166// Float: f g Handles floats and doubles. 
167// Vector: v Use with :typesize for 2, 3, and 4 dimensional vectors. Default is 3. Must call 
168// pod(vec) or vec.Pod() for tVectors, or use tVecNb POD type. All other spec 
169// fields are per vector component. Not the whole thing. 
170// Quaternion: q Quaternions. Typesize is ignored. Must call pod for tQuaternions. Normal format is 
171// (w, x, y, z). Alternate _ format is (w, (x, y, z)). 
172// Matrix: m For use with tMatrix4 and tMatrix2 POD types. Matrix is printed on one line using 
173// () brackets. Use decorative _ flag for 4 (or 2) rows. All other spec fields are per 
174// vector component. The typesize is used to determine 2x2 or 4x4 (default). 
175// Character: c A single character. 
176// String: s You must call pod(string) or string.Pod() for tStrings, or use char*. 
177// t Windows only. Allows passing of non-POD tString directly. Warning: You cannot pass 
178// in an tStringItem! You must either cast to an tString or call pod() and use %s. 
179// Percent: % Displays percent sign. 
180// 
181// The functions return the number of characters printed. They do NOT care about channels in that they always report 
182// what would have been printed if the channel was visible. Channels are an output filter only, not something that 
183// changes behaviour depending on what machine you are on. 
184// 
185// Examples: 
186// uint32 a = 0x1234ABCD; 
187// tPrintf("%08X", a); 
188// 
189// uint64 b = 0x1234ABCD5678ABCDLL; 
190// tPrintf("%016|64X or %016!8X or %016:2X", b, b, b); 
191// 
192// tuint256 c = 42; 
193// tPrintf("%064|256X or %064!32X or %064:8X", c, c); 
194 
195int tPrintf(const char* format, ...); // Prints to generic channel. 
196int tvPrintf(const char* format, va_list); // Prints to generic channel. 
197int tPrintf(tSystem::tChannel channels, const char* format, ...); 
198int tvPrintf(tSystem::tChannel channels, const char* format, va_list); 
199 
200// These are a few shortcut functions. Notice that in release, these become inline empty functions. By these, I only 
201// mean the ones below that output to the screen or stdout. 
202int tPrintCore(const char* format, ...); 
203int tPrintGameplay(const char* format, ...); 
204int tPrintPhysics(const char* format, ...); 
205int tPrintSound(const char* format, ...); 
206int tPrintRendering(const char* format, ...); 
207int tPrintAI(const char* format, ...); 
208int tPrintInput(const char* format, ...); 
209int tPrintT(const char* format, ...); 
210 
211// In some cases, possibly before reserving buffer space, you need to know how many characters would be used in an 
212// actual printf call. The next two functions work that out. They are not affected by what channels are turned on. 
213int tcPrintf(const char* format, ...); 
214int tvcPrintf(const char* format, va_list); 
215 
216// Formatted print functions that print into a character buffer. The dest buffer must be big enough. Use tcPrintf or 
217// tvcPrintf to find out how big. The tString versions will do the size calc first and return a ref to the same string 
218// passed in. Use Length to find out number characters printed. 
219int tvsPrintf(char* dest, const char* format, va_list); 
220int tsPrintf(char* dest, const char* format, ...); 
221tString& tvsPrintf(tString& dest, const char* format, va_list); 
222tString& tsPrintf(tString& dest, const char* format, ...); 
223inline tString tvsPrintf(const char* format, va_list args) { tString dest; return tvsPrintf(dest, format, args); } 
224inline tString tsPrintf(const char* format, ...) { va_list marker; va_start(marker, format); return tvsPrintf(format, marker); } 
225 
226// Non-formatted print. Allows simple conversion from arbitrary type to a string formatted in a reasonabe way. 
227inline tString tsPrint(int8 value) { return tsPrintf("%d", value); } 
228inline tString tsPrint(uint8 value) { return tsPrintf("0x%02X", value); } 
229inline tString tsPrint(int16 value) { return tsPrintf("%d", value); } 
230inline tString tsPrint(uint16 value) { return tsPrintf("0x%04X", value); } 
231inline tString tsPrint(int32 value) { return tsPrintf("%d", value); } 
232inline tString tsPrint(uint32 value) { return tsPrintf("0x%08X", value); } 
233inline tString tsPrint(int64 value) { return tsPrintf("%|64d", value); } 
234inline tString tsPrint(uint64 value) { return tsPrintf("0x%016|64X", value); } 
235inline tString tsPrint(tint128 value) { return tsPrintf("%|128d", value); } 
236inline tString tsPrint(tuint128 value) { return tsPrintf("0x%032|128X", value); } 
237inline tString tsPrint(tint256 value) { return tsPrintf("%|256d", value); } 
238inline tString tsPrint(tuint256 value) { return tsPrintf("0x%064|256X", value); } 
239inline tString tsPrint(tint512 value) { return tsPrintf("%|512d", value); } 
240inline tString tsPrint(tuint512 value) { return tsPrintf("0x%0128|512X", value); } 
241inline tString tsPrint(float value) { return tsPrintf("%f", value); } 
242inline tString tsPrint(double value) { return tsPrintf("%f", value); } 
243inline tString tsPrint(bool value) { return value ? "true" : "false"; } 
244inline tString tsPrint(const tMath::tVec2& value) { return tsPrintf("%:2v", value); } 
245inline tString tsPrint(const tMath::tVec3& value) { return tsPrintf("%:3v", value); } 
246inline tString tsPrint(const tMath::tVec4& value) { return tsPrintf("%:4v", value); } 
247inline tString tsPrint(const tMath::tQuat& value) { return tsPrintf("%q", value); } 
248 
249// These overloads are 'safe' in that they guarantee no overrun of the dest buffer. You enter the full number of bytes 
250// in the dest buffer. The dest buffer is guaranteed to be null terminated afterwards, and the number of characters 
251// (not including the terminator) is returned. The dest may contain a truncated version of the formatted string if the 
252// dest buffer is not big enough. Returns the number of non-null characters inserted into the buffer. destSize must 
253// be greater than 0, but if that's all you give it, there's only room for the terminator. Dest sizes <= 1 always 
254// return zero. 
255int tvsPrintf(char* dest, int destSize, const char* format, va_list); 
256int tsPrintf(char* dest, int destSize, const char* format, ...); 
257 
258// Here is the file handle print 
259int tfPrintf(tFileHandle dest, const char* format, ...); 
260int tvfPrintf(tFileHandle dest, const char* format, va_list); 
261 
262// These variants print a timestamp (ttf = tacent timestamp file) before any content is printed. 
263int ttfPrintf(tFileHandle dest, const char* format, ...); 
264int ttvfPrintf(tFileHandle dest, const char* format, va_list); 
265 
266// tFlush may be called with any FileHandle such as stdout or stderr as well as other file handles opened with 
267// tSystem::tOpenFile. 
268void tFlush(tFileHandle); 
269 
270// The tdPrintf variations print to both the destination string or file, as well as printing to whatever channels are 
271// specified. The 'd' is for dual. Useful for things like log files and unit tests that also need to print to stdout. 
272// The dest file or string is always printed to. The channels only affect what is output to stdout and the return 
273// values will match what the plain print-to-string (or file) would have returned. 
274int tdsPrintf(char* dest, const char* format, ...); 
275int tdsPrintf(tSystem::tChannel channels, char* dest, const char* format, ...); 
276tString& tdsPrintf(tString& dest, const char* format, ...); 
277tString& tdsPrintf(tSystem::tChannel channels, tString& dest, const char* format, ...); 
278int tdsPrintf(char* dest, int destSize, const char* format, ...); 
279int tdsPrintf(tSystem::tChannel channels, char* dest, int destSize, const char* format, ...); 
280int tdfPrintf(tFileHandle dest, const char* format, ...); 
281int tdfPrintf(tSystem::tChannel channels, tFileHandle dest, const char* format, ...); 
282 
283 
284// Implementation below this line. 
285 
286 
287#if !defined(CONFIG_PROFILE) && !defined(CONFIG_SHIP) 
288inline int tPrintf(const char* f, ...) 
289
290 va_list l; va_start(l, f); 
291 int n = tvPrintf (f, l); 
292 va_end(l); return n
293
294 
295 
296inline int tPrintf(uint32 c, const char* f, ...) 
297
298 va_list l; va_start(l, f); 
299 int n = tvPrintf (c, f, l); 
300 va_end(l); return n
301
302 
303 
304inline int tPrintCore(const char* f, ...) 
305
306 va_list l; va_start(l, f); 
307 int n = tvPrintf (tSystem::tChannel_Core, f, l); 
308 va_end(l); return n
309
310 
311 
312inline int tPrintGameplay(const char* f, ...) 
313
314 va_list l; va_start(l, f); 
315 int n = tvPrintf (tSystem::tChannel_Gameplay, f, l); 
316 va_end(l); return n
317
318 
319 
320inline int tPrintPhysics(const char* f, ...) 
321
322 va_list l; va_start(l, f); 
323 int n = tvPrintf (tSystem::tChannel_Physics, f, l); 
324 va_end(l); return n
325
326 
327 
328inline int tPrintSound(const char* f, ...) 
329
330 va_list l; va_start(l, f); 
331 int n = tvPrintf (tSystem::tChannel_Sound, f, l); 
332 va_end(l); return n
333
334 
335 
336inline int tPrintRendering(const char* f, ...) 
337
338 va_list l; va_start(l, f); 
339 int n = tvPrintf (tSystem::tChannel_Rendering, f, l); 
340 va_end(l); return n
341
342 
343 
344inline int tPrintAI(const char* f, ...) 
345
346 va_list l; va_start(l, f); 
347 int n = tvPrintf (tSystem::tChannel_AI, f, l); 
348 va_end(l); return n
349
350 
351 
352inline int tPrintInput(const char* f, ...) 
353
354 va_list l; va_start(l, f); 
355 int n = tvPrintf (tSystem::tChannel_Input, f, l); 
356 va_end(l); return n
357
358 
359 
360inline int tPrintT(const char* f, ...) 
361
362 va_list l; va_start(l, f); 
363 int n = tvPrintf (tSystem::tChannel_Tristan, f, l); 
364 va_end(l); return n
365
366 
367 
368#else 
369inline int tPrintf(const char* format, ...) { return 0; } 
370inline int tvPrintf(const char* format, va_list) { return 0; } 
371inline int tPrintf(uint32 channels, const char* format, ...) { return 0; } 
372inline int tvPrintf(uint32 channels, const char* format, va_list) { return 0; } 
373inline int tPrintCore(const char* format, ...) { return 0; } 
374inline int tPrintGameplay(const char* format, ...) { return 0; } 
375inline int tPrintPhysics(const char* format, ...) { return 0; } 
376inline int tPrintSound(const char* format, ...) { return 0; } 
377inline int tPrintRendering(const char* format, ...) { return 0; } 
378inline int tPrintAI(const char* format, ...) { return 0; } 
379inline int tPrintInput(const char* format, ...) { return 0; } 
380inline int tPrintT(const char* format, ...) { return 0; } 
381#endif 
382 
383 
384inline int tdsPrintf(char* dest, const char* format, ...) 
385
386 va_list marker
387 va_start(marker, format); 
388 tvPrintf(format, marker);  
389 return tvsPrintf(dest, format, marker); 
390
391 
392 
393inline int tdsPrintf(tSystem::tChannel channels, char* dest, const char* format, ...) 
394
395 va_list marker
396 va_start(marker, format); 
397 tvPrintf(channels, format, marker);  
398 return tvsPrintf(dest, format, marker); 
399
400 
401 
402inline tString& tdsPrintf(tString& dest, const char* format, ...) 
403
404 va_list marker
405 va_start(marker, format); 
406 tvPrintf(format, marker);  
407 return tvsPrintf(dest, format, marker); 
408
409 
410 
411inline tString& tdsPrintf(tSystem::tChannel channels, tString& dest, const char* format, ...) 
412
413 va_list marker
414 va_start(marker, format); 
415 tvPrintf(channels, format, marker);  
416 return tvsPrintf(dest, format, marker); 
417
418 
419 
420inline int tdsPrintf(char* dest, int destSize, const char* format, ...) 
421
422 va_list marker
423 va_start(marker, format); 
424 tvPrintf(format, marker);  
425 return tvsPrintf(dest, destSize, format, marker); 
426
427 
428 
429inline int tdsPrintf(tSystem::tChannel channels, char* dest, int destSize, const char* format, ...) 
430
431 va_list marker
432 va_start(marker, format); 
433 tvPrintf(channels, format, marker);  
434 return tvsPrintf(dest, destSize, format, marker); 
435
436 
437 
438inline int tdfPrintf(tFileHandle dest, const char* format, ...) 
439
440 va_list marker
441 va_start(marker, format); 
442 tvPrintf(format, marker);  
443 return tvfPrintf(dest, format, marker); 
444
445 
446 
447inline int tdfPrintf(tSystem::tChannel channels, tFileHandle dest, const char* format, ...) 
448
449 va_list marker
450 va_start(marker, format); 
451 tvPrintf(channels, format, marker);  
452 return tvfPrintf(dest, format, marker); 
453
454