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 |   |
24 | namespace 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 |   |
195 | int tPrintf(const char* format, ...); // Prints to generic channel.  |
196 | int tvPrintf(const char* format, va_list); // Prints to generic channel.  |
197 | int tPrintf(tSystem::tChannel channels, const char* format, ...);  |
198 | int 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.  |
202 | int tPrintCore(const char* format, ...);  |
203 | int tPrintGameplay(const char* format, ...);  |
204 | int tPrintPhysics(const char* format, ...);  |
205 | int tPrintSound(const char* format, ...);  |
206 | int tPrintRendering(const char* format, ...);  |
207 | int tPrintAI(const char* format, ...);  |
208 | int tPrintInput(const char* format, ...);  |
209 | int 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.  |
213 | int tcPrintf(const char* format, ...);  |
214 | int 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.  |
219 | int tvsPrintf(char* dest, const char* format, va_list);  |
220 | int tsPrintf(char* dest, const char* format, ...);  |
221 | tString& tvsPrintf(tString& dest, const char* format, va_list);  |
222 | tString& tsPrintf(tString& dest, const char* format, ...);  |
223 | inline tString tvsPrintf(const char* format, va_list args) { tString dest; return tvsPrintf(dest, format, args); }  |
224 | inline 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.  |
227 | inline tString tsPrint(int8 value) { return tsPrintf("%d" , value); }  |
228 | inline tString tsPrint(uint8 value) { return tsPrintf("0x%02X" , value); }  |
229 | inline tString tsPrint(int16 value) { return tsPrintf("%d" , value); }  |
230 | inline tString tsPrint(uint16 value) { return tsPrintf("0x%04X" , value); }  |
231 | inline tString tsPrint(int32 value) { return tsPrintf("%d" , value); }  |
232 | inline tString tsPrint(uint32 value) { return tsPrintf("0x%08X" , value); }  |
233 | inline tString tsPrint(int64 value) { return tsPrintf("%|64d" , value); }  |
234 | inline tString tsPrint(uint64 value) { return tsPrintf("0x%016|64X" , value); }  |
235 | inline tString tsPrint(tint128 value) { return tsPrintf("%|128d" , value); }  |
236 | inline tString tsPrint(tuint128 value) { return tsPrintf("0x%032|128X" , value); }  |
237 | inline tString tsPrint(tint256 value) { return tsPrintf("%|256d" , value); }  |
238 | inline tString tsPrint(tuint256 value) { return tsPrintf("0x%064|256X" , value); }  |
239 | inline tString tsPrint(tint512 value) { return tsPrintf("%|512d" , value); }  |
240 | inline tString tsPrint(tuint512 value) { return tsPrintf("0x%0128|512X" , value); }  |
241 | inline tString tsPrint(float value) { return tsPrintf("%f" , value); }  |
242 | inline tString tsPrint(double value) { return tsPrintf("%f" , value); }  |
243 | inline tString tsPrint(bool value) { return value ? "true" : "false" ; }  |
244 | inline tString tsPrint(const tMath::tVec2& value) { return tsPrintf("%:2v" , value); }  |
245 | inline tString tsPrint(const tMath::tVec3& value) { return tsPrintf("%:3v" , value); }  |
246 | inline tString tsPrint(const tMath::tVec4& value) { return tsPrintf("%:4v" , value); }  |
247 | inline 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.  |
255 | int tvsPrintf(char* dest, int destSize, const char* format, va_list);  |
256 | int tsPrintf(char* dest, int destSize, const char* format, ...);  |
257 |   |
258 | // Here is the file handle print  |
259 | int tfPrintf(tFileHandle dest, const char* format, ...);  |
260 | int tvfPrintf(tFileHandle dest, const char* format, va_list);  |
261 |   |
262 | // These variants print a timestamp (ttf = tacent timestamp file) before any content is printed.  |
263 | int ttfPrintf(tFileHandle dest, const char* format, ...);  |
264 | int 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.  |
268 | void 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.  |
274 | int tdsPrintf(char* dest, const char* format, ...);  |
275 | int tdsPrintf(tSystem::tChannel channels, char* dest, const char* format, ...);  |
276 | tString& tdsPrintf(tString& dest, const char* format, ...);  |
277 | tString& tdsPrintf(tSystem::tChannel channels, tString& dest, const char* format, ...);  |
278 | int tdsPrintf(char* dest, int destSize, const char* format, ...);  |
279 | int tdsPrintf(tSystem::tChannel channels, char* dest, int destSize, const char* format, ...);  |
280 | int tdfPrintf(tFileHandle dest, const char* format, ...);  |
281 | int 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)  |
288 | inline 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 |   |
296 | inline 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 |   |
304 | inline 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 |   |
312 | inline 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 |   |
320 | inline 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 |   |
328 | inline 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 |   |
336 | inline 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 |   |
344 | inline 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 |   |
352 | inline 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 |   |
360 | inline 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  |
369 | inline int tPrintf(const char* format, ...) { return 0; }  |
370 | inline int tvPrintf(const char* format, va_list) { return 0; }  |
371 | inline int tPrintf(uint32 channels, const char* format, ...) { return 0; }  |
372 | inline int tvPrintf(uint32 channels, const char* format, va_list) { return 0; }  |
373 | inline int tPrintCore(const char* format, ...) { return 0; }  |
374 | inline int tPrintGameplay(const char* format, ...) { return 0; }  |
375 | inline int tPrintPhysics(const char* format, ...) { return 0; }  |
376 | inline int tPrintSound(const char* format, ...) { return 0; }  |
377 | inline int tPrintRendering(const char* format, ...) { return 0; }  |
378 | inline int tPrintAI(const char* format, ...) { return 0; }  |
379 | inline int tPrintInput(const char* format, ...) { return 0; }  |
380 | inline int tPrintT(const char* format, ...) { return 0; }  |
381 | #endif  |
382 |   |
383 |   |
384 | inline 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 |   |
393 | inline 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 |   |
402 | inline 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 |   |
411 | inline 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 |   |
420 | inline 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 |   |
429 | inline 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 |   |
438 | inline 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 |   |
447 | inline 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 | |