1*2b54f0dbSXin Li #include <stdarg.h>
2*2b54f0dbSXin Li #include <string.h>
3*2b54f0dbSXin Li #include <stdlib.h>
4*2b54f0dbSXin Li #include <stdio.h>
5*2b54f0dbSXin Li #ifdef _WIN32
6*2b54f0dbSXin Li #include <windows.h>
7*2b54f0dbSXin Li #else
8*2b54f0dbSXin Li #include <unistd.h>
9*2b54f0dbSXin Li #endif
10*2b54f0dbSXin Li #ifdef __ANDROID__
11*2b54f0dbSXin Li #include <android/log.h>
12*2b54f0dbSXin Li #endif
13*2b54f0dbSXin Li #ifdef __hexagon__
14*2b54f0dbSXin Li #include <qurt_printf.h>
15*2b54f0dbSXin Li #endif
16*2b54f0dbSXin Li
17*2b54f0dbSXin Li #ifndef CLOG_LOG_TO_STDIO
18*2b54f0dbSXin Li #ifdef __ANDROID__
19*2b54f0dbSXin Li #define CLOG_LOG_TO_STDIO 0
20*2b54f0dbSXin Li #else
21*2b54f0dbSXin Li #define CLOG_LOG_TO_STDIO 1
22*2b54f0dbSXin Li #endif
23*2b54f0dbSXin Li #endif
24*2b54f0dbSXin Li
25*2b54f0dbSXin Li #include <clog.h>
26*2b54f0dbSXin Li
27*2b54f0dbSXin Li
28*2b54f0dbSXin Li /* Messages up to this size are formatted entirely on-stack, and don't allocate heap memory */
29*2b54f0dbSXin Li #define CLOG_STACK_BUFFER_SIZE 1024
30*2b54f0dbSXin Li
31*2b54f0dbSXin Li #define CLOG_FATAL_PREFIX "Fatal error: "
32*2b54f0dbSXin Li #define CLOG_FATAL_PREFIX_LENGTH 13
33*2b54f0dbSXin Li #define CLOG_FATAL_PREFIX_FORMAT "Fatal error in %s: "
34*2b54f0dbSXin Li #define CLOG_ERROR_PREFIX "Error: "
35*2b54f0dbSXin Li #define CLOG_ERROR_PREFIX_LENGTH 7
36*2b54f0dbSXin Li #define CLOG_ERROR_PREFIX_FORMAT "Error in %s: "
37*2b54f0dbSXin Li #define CLOG_WARNING_PREFIX "Warning: "
38*2b54f0dbSXin Li #define CLOG_WARNING_PREFIX_LENGTH 9
39*2b54f0dbSXin Li #define CLOG_WARNING_PREFIX_FORMAT "Warning in %s: "
40*2b54f0dbSXin Li #define CLOG_INFO_PREFIX "Note: "
41*2b54f0dbSXin Li #define CLOG_INFO_PREFIX_LENGTH 6
42*2b54f0dbSXin Li #define CLOG_INFO_PREFIX_FORMAT "Note (%s): "
43*2b54f0dbSXin Li #define CLOG_DEBUG_PREFIX "Debug: "
44*2b54f0dbSXin Li #define CLOG_DEBUG_PREFIX_LENGTH 7
45*2b54f0dbSXin Li #define CLOG_DEBUG_PREFIX_FORMAT "Debug (%s): "
46*2b54f0dbSXin Li #define CLOG_SUFFIX_LENGTH 1
47*2b54f0dbSXin Li
clog_vlog_fatal(const char * module,const char * format,va_list args)48*2b54f0dbSXin Li void clog_vlog_fatal(const char* module, const char* format, va_list args) {
49*2b54f0dbSXin Li #if defined(__ANDROID__) && !CLOG_LOG_TO_STDIO
50*2b54f0dbSXin Li __android_log_vprint(ANDROID_LOG_FATAL, module, format, args);
51*2b54f0dbSXin Li #else
52*2b54f0dbSXin Li char stack_buffer[CLOG_STACK_BUFFER_SIZE];
53*2b54f0dbSXin Li char* heap_buffer = NULL;
54*2b54f0dbSXin Li char* out_buffer = &stack_buffer[0];
55*2b54f0dbSXin Li
56*2b54f0dbSXin Li /* The first call to vsnprintf will clobber args, thus need a copy in case a second vsnprintf call is needed */
57*2b54f0dbSXin Li va_list args_copy;
58*2b54f0dbSXin Li va_copy(args_copy, args);
59*2b54f0dbSXin Li
60*2b54f0dbSXin Li int prefix_chars = CLOG_FATAL_PREFIX_LENGTH;
61*2b54f0dbSXin Li if (module == NULL) {
62*2b54f0dbSXin Li memcpy(stack_buffer, CLOG_FATAL_PREFIX, CLOG_FATAL_PREFIX_LENGTH);
63*2b54f0dbSXin Li } else {
64*2b54f0dbSXin Li prefix_chars = snprintf(stack_buffer, CLOG_STACK_BUFFER_SIZE, CLOG_FATAL_PREFIX_FORMAT, module);
65*2b54f0dbSXin Li if (prefix_chars < 0) {
66*2b54f0dbSXin Li /* Format error in prefix (possible if prefix is modified): skip prefix and continue as if nothing happened. */
67*2b54f0dbSXin Li prefix_chars = 0;
68*2b54f0dbSXin Li }
69*2b54f0dbSXin Li }
70*2b54f0dbSXin Li
71*2b54f0dbSXin Li int format_chars;
72*2b54f0dbSXin Li if (prefix_chars + CLOG_SUFFIX_LENGTH >= CLOG_STACK_BUFFER_SIZE) {
73*2b54f0dbSXin Li /*
74*2b54f0dbSXin Li * Prefix + suffix alone would overflow the on-stack buffer, thus need to use on-heap buffer.
75*2b54f0dbSXin Li * Do not even try to format the string into on-stack buffer.
76*2b54f0dbSXin Li */
77*2b54f0dbSXin Li format_chars = vsnprintf(NULL, 0, format, args);
78*2b54f0dbSXin Li } else {
79*2b54f0dbSXin Li format_chars =
80*2b54f0dbSXin Li vsnprintf(
81*2b54f0dbSXin Li &stack_buffer[prefix_chars],
82*2b54f0dbSXin Li CLOG_STACK_BUFFER_SIZE - prefix_chars - CLOG_SUFFIX_LENGTH,
83*2b54f0dbSXin Li format,
84*2b54f0dbSXin Li args);
85*2b54f0dbSXin Li }
86*2b54f0dbSXin Li if (format_chars < 0) {
87*2b54f0dbSXin Li /* Format error in the message: silently ignore this particular message. */
88*2b54f0dbSXin Li goto cleanup;
89*2b54f0dbSXin Li }
90*2b54f0dbSXin Li if (prefix_chars + format_chars + CLOG_SUFFIX_LENGTH > CLOG_STACK_BUFFER_SIZE) {
91*2b54f0dbSXin Li /* Allocate a buffer on heap, and vsnprintf to this buffer */
92*2b54f0dbSXin Li heap_buffer = malloc(prefix_chars + format_chars + CLOG_SUFFIX_LENGTH);
93*2b54f0dbSXin Li if (heap_buffer == NULL) {
94*2b54f0dbSXin Li goto cleanup;
95*2b54f0dbSXin Li }
96*2b54f0dbSXin Li
97*2b54f0dbSXin Li if (prefix_chars > CLOG_STACK_BUFFER_SIZE) {
98*2b54f0dbSXin Li /* Prefix didn't fit into on-stack buffer, re-format it again to on-heap buffer */
99*2b54f0dbSXin Li snprintf(heap_buffer, prefix_chars + 1 /* for '\0'-terminator */, CLOG_FATAL_PREFIX_FORMAT, module);
100*2b54f0dbSXin Li } else {
101*2b54f0dbSXin Li /* Copy pre-formatted prefix from on-stack buffer to on-heap buffer */
102*2b54f0dbSXin Li memcpy(heap_buffer, stack_buffer, prefix_chars);
103*2b54f0dbSXin Li }
104*2b54f0dbSXin Li vsnprintf(heap_buffer + prefix_chars, format_chars + CLOG_SUFFIX_LENGTH, format, args_copy);
105*2b54f0dbSXin Li out_buffer = heap_buffer;
106*2b54f0dbSXin Li }
107*2b54f0dbSXin Li out_buffer[prefix_chars + format_chars] = '\n';
108*2b54f0dbSXin Li #if defined(_WIN32)
109*2b54f0dbSXin Li DWORD bytes_written;
110*2b54f0dbSXin Li WriteFile(
111*2b54f0dbSXin Li GetStdHandle(STD_ERROR_HANDLE),
112*2b54f0dbSXin Li out_buffer, prefix_chars + format_chars + CLOG_SUFFIX_LENGTH,
113*2b54f0dbSXin Li &bytes_written, NULL);
114*2b54f0dbSXin Li #elif defined(__hexagon__)
115*2b54f0dbSXin Li qurt_printf("%s", out_buffer);
116*2b54f0dbSXin Li #else
117*2b54f0dbSXin Li write(STDERR_FILENO, out_buffer, prefix_chars + format_chars + CLOG_SUFFIX_LENGTH);
118*2b54f0dbSXin Li #endif
119*2b54f0dbSXin Li
120*2b54f0dbSXin Li cleanup:
121*2b54f0dbSXin Li free(heap_buffer);
122*2b54f0dbSXin Li va_end(args_copy);
123*2b54f0dbSXin Li #endif
124*2b54f0dbSXin Li }
125*2b54f0dbSXin Li
clog_vlog_error(const char * module,const char * format,va_list args)126*2b54f0dbSXin Li void clog_vlog_error(const char* module, const char* format, va_list args) {
127*2b54f0dbSXin Li #if defined(__ANDROID__) && !CLOG_LOG_TO_STDIO
128*2b54f0dbSXin Li __android_log_vprint(ANDROID_LOG_ERROR, module, format, args);
129*2b54f0dbSXin Li #else
130*2b54f0dbSXin Li char stack_buffer[CLOG_STACK_BUFFER_SIZE];
131*2b54f0dbSXin Li char* heap_buffer = NULL;
132*2b54f0dbSXin Li char* out_buffer = &stack_buffer[0];
133*2b54f0dbSXin Li
134*2b54f0dbSXin Li /* The first call to vsnprintf will clobber args, thus need a copy in case a second vsnprintf call is needed */
135*2b54f0dbSXin Li va_list args_copy;
136*2b54f0dbSXin Li va_copy(args_copy, args);
137*2b54f0dbSXin Li
138*2b54f0dbSXin Li int prefix_chars = CLOG_ERROR_PREFIX_LENGTH;
139*2b54f0dbSXin Li if (module == NULL) {
140*2b54f0dbSXin Li memcpy(stack_buffer, CLOG_ERROR_PREFIX, CLOG_ERROR_PREFIX_LENGTH);
141*2b54f0dbSXin Li } else {
142*2b54f0dbSXin Li prefix_chars = snprintf(stack_buffer, CLOG_STACK_BUFFER_SIZE, CLOG_ERROR_PREFIX_FORMAT, module);
143*2b54f0dbSXin Li if (prefix_chars < 0) {
144*2b54f0dbSXin Li /* Format error in prefix (possible if prefix is modified): skip prefix and continue as if nothing happened. */
145*2b54f0dbSXin Li prefix_chars = 0;
146*2b54f0dbSXin Li }
147*2b54f0dbSXin Li }
148*2b54f0dbSXin Li
149*2b54f0dbSXin Li int format_chars;
150*2b54f0dbSXin Li if (prefix_chars + CLOG_SUFFIX_LENGTH >= CLOG_STACK_BUFFER_SIZE) {
151*2b54f0dbSXin Li /*
152*2b54f0dbSXin Li * Prefix + suffix alone would overflow the on-stack buffer, thus need to use on-heap buffer.
153*2b54f0dbSXin Li * Do not even try to format the string into on-stack buffer.
154*2b54f0dbSXin Li */
155*2b54f0dbSXin Li format_chars = vsnprintf(NULL, 0, format, args);
156*2b54f0dbSXin Li } else {
157*2b54f0dbSXin Li format_chars =
158*2b54f0dbSXin Li vsnprintf(
159*2b54f0dbSXin Li &stack_buffer[prefix_chars],
160*2b54f0dbSXin Li CLOG_STACK_BUFFER_SIZE - prefix_chars - CLOG_SUFFIX_LENGTH,
161*2b54f0dbSXin Li format,
162*2b54f0dbSXin Li args);
163*2b54f0dbSXin Li }
164*2b54f0dbSXin Li if (format_chars < 0) {
165*2b54f0dbSXin Li /* Format error in the message: silently ignore this particular message. */
166*2b54f0dbSXin Li goto cleanup;
167*2b54f0dbSXin Li }
168*2b54f0dbSXin Li if (prefix_chars + format_chars + CLOG_SUFFIX_LENGTH > CLOG_STACK_BUFFER_SIZE) {
169*2b54f0dbSXin Li /* Allocate a buffer on heap, and vsnprintf to this buffer */
170*2b54f0dbSXin Li heap_buffer = malloc(prefix_chars + format_chars + CLOG_SUFFIX_LENGTH);
171*2b54f0dbSXin Li if (heap_buffer == NULL) {
172*2b54f0dbSXin Li goto cleanup;
173*2b54f0dbSXin Li }
174*2b54f0dbSXin Li
175*2b54f0dbSXin Li if (prefix_chars > CLOG_STACK_BUFFER_SIZE) {
176*2b54f0dbSXin Li /* Prefix didn't fit into on-stack buffer, re-format it again to on-heap buffer */
177*2b54f0dbSXin Li snprintf(heap_buffer, prefix_chars + 1 /* for '\0'-terminator */, CLOG_ERROR_PREFIX_FORMAT, module);
178*2b54f0dbSXin Li } else {
179*2b54f0dbSXin Li /* Copy pre-formatted prefix from on-stack buffer to on-heap buffer */
180*2b54f0dbSXin Li memcpy(heap_buffer, stack_buffer, prefix_chars);
181*2b54f0dbSXin Li }
182*2b54f0dbSXin Li vsnprintf(heap_buffer + prefix_chars, format_chars + CLOG_SUFFIX_LENGTH, format, args_copy);
183*2b54f0dbSXin Li out_buffer = heap_buffer;
184*2b54f0dbSXin Li }
185*2b54f0dbSXin Li out_buffer[prefix_chars + format_chars] = '\n';
186*2b54f0dbSXin Li #if defined(_WIN32)
187*2b54f0dbSXin Li DWORD bytes_written;
188*2b54f0dbSXin Li WriteFile(
189*2b54f0dbSXin Li GetStdHandle(STD_ERROR_HANDLE),
190*2b54f0dbSXin Li out_buffer, prefix_chars + format_chars + CLOG_SUFFIX_LENGTH,
191*2b54f0dbSXin Li &bytes_written, NULL);
192*2b54f0dbSXin Li #elif defined(__hexagon__)
193*2b54f0dbSXin Li qurt_printf("%s", out_buffer);
194*2b54f0dbSXin Li #else
195*2b54f0dbSXin Li write(STDERR_FILENO, out_buffer, prefix_chars + format_chars + CLOG_SUFFIX_LENGTH);
196*2b54f0dbSXin Li #endif
197*2b54f0dbSXin Li
198*2b54f0dbSXin Li cleanup:
199*2b54f0dbSXin Li free(heap_buffer);
200*2b54f0dbSXin Li va_end(args_copy);
201*2b54f0dbSXin Li #endif
202*2b54f0dbSXin Li }
203*2b54f0dbSXin Li
clog_vlog_warning(const char * module,const char * format,va_list args)204*2b54f0dbSXin Li void clog_vlog_warning(const char* module, const char* format, va_list args) {
205*2b54f0dbSXin Li #if defined(__ANDROID__) && !CLOG_LOG_TO_STDIO
206*2b54f0dbSXin Li __android_log_vprint(ANDROID_LOG_WARN, module, format, args);
207*2b54f0dbSXin Li #else
208*2b54f0dbSXin Li char stack_buffer[CLOG_STACK_BUFFER_SIZE];
209*2b54f0dbSXin Li char* heap_buffer = NULL;
210*2b54f0dbSXin Li char* out_buffer = &stack_buffer[0];
211*2b54f0dbSXin Li
212*2b54f0dbSXin Li /* The first call to vsnprintf will clobber args, thus need a copy in case a second vsnprintf call is needed */
213*2b54f0dbSXin Li va_list args_copy;
214*2b54f0dbSXin Li va_copy(args_copy, args);
215*2b54f0dbSXin Li
216*2b54f0dbSXin Li int prefix_chars = CLOG_WARNING_PREFIX_LENGTH;
217*2b54f0dbSXin Li if (module == NULL) {
218*2b54f0dbSXin Li memcpy(stack_buffer, CLOG_WARNING_PREFIX, CLOG_WARNING_PREFIX_LENGTH);
219*2b54f0dbSXin Li } else {
220*2b54f0dbSXin Li prefix_chars = snprintf(stack_buffer, CLOG_STACK_BUFFER_SIZE, CLOG_WARNING_PREFIX_FORMAT, module);
221*2b54f0dbSXin Li if (prefix_chars < 0) {
222*2b54f0dbSXin Li /* Format error in prefix (possible if prefix is modified): skip prefix and continue as if nothing happened. */
223*2b54f0dbSXin Li prefix_chars = 0;
224*2b54f0dbSXin Li }
225*2b54f0dbSXin Li }
226*2b54f0dbSXin Li
227*2b54f0dbSXin Li int format_chars;
228*2b54f0dbSXin Li if (prefix_chars + CLOG_SUFFIX_LENGTH >= CLOG_STACK_BUFFER_SIZE) {
229*2b54f0dbSXin Li /*
230*2b54f0dbSXin Li * Prefix + suffix alone would overflow the on-stack buffer, thus need to use on-heap buffer.
231*2b54f0dbSXin Li * Do not even try to format the string into on-stack buffer.
232*2b54f0dbSXin Li */
233*2b54f0dbSXin Li format_chars = vsnprintf(NULL, 0, format, args);
234*2b54f0dbSXin Li } else {
235*2b54f0dbSXin Li format_chars =
236*2b54f0dbSXin Li vsnprintf(
237*2b54f0dbSXin Li &stack_buffer[prefix_chars],
238*2b54f0dbSXin Li CLOG_STACK_BUFFER_SIZE - prefix_chars - CLOG_SUFFIX_LENGTH,
239*2b54f0dbSXin Li format,
240*2b54f0dbSXin Li args);
241*2b54f0dbSXin Li }
242*2b54f0dbSXin Li if (format_chars < 0) {
243*2b54f0dbSXin Li /* Format error in the message: silently ignore this particular message. */
244*2b54f0dbSXin Li goto cleanup;
245*2b54f0dbSXin Li }
246*2b54f0dbSXin Li if (prefix_chars + format_chars + CLOG_SUFFIX_LENGTH > CLOG_STACK_BUFFER_SIZE) {
247*2b54f0dbSXin Li /* Allocate a buffer on heap, and vsnprintf to this buffer */
248*2b54f0dbSXin Li heap_buffer = malloc(prefix_chars + format_chars + CLOG_SUFFIX_LENGTH);
249*2b54f0dbSXin Li if (heap_buffer == NULL) {
250*2b54f0dbSXin Li goto cleanup;
251*2b54f0dbSXin Li }
252*2b54f0dbSXin Li
253*2b54f0dbSXin Li if (prefix_chars > CLOG_STACK_BUFFER_SIZE) {
254*2b54f0dbSXin Li /* Prefix didn't fit into on-stack buffer, re-format it again to on-heap buffer */
255*2b54f0dbSXin Li snprintf(heap_buffer, prefix_chars + 1 /* for '\0'-terminator */, CLOG_WARNING_PREFIX_FORMAT, module);
256*2b54f0dbSXin Li } else {
257*2b54f0dbSXin Li /* Copy pre-formatted prefix from on-stack buffer to on-heap buffer */
258*2b54f0dbSXin Li memcpy(heap_buffer, stack_buffer, prefix_chars);
259*2b54f0dbSXin Li }
260*2b54f0dbSXin Li vsnprintf(heap_buffer + prefix_chars, format_chars + CLOG_SUFFIX_LENGTH, format, args_copy);
261*2b54f0dbSXin Li out_buffer = heap_buffer;
262*2b54f0dbSXin Li }
263*2b54f0dbSXin Li out_buffer[prefix_chars + format_chars] = '\n';
264*2b54f0dbSXin Li #if defined(_WIN32)
265*2b54f0dbSXin Li DWORD bytes_written;
266*2b54f0dbSXin Li WriteFile(
267*2b54f0dbSXin Li GetStdHandle(STD_ERROR_HANDLE),
268*2b54f0dbSXin Li out_buffer, prefix_chars + format_chars + CLOG_SUFFIX_LENGTH,
269*2b54f0dbSXin Li &bytes_written, NULL);
270*2b54f0dbSXin Li #elif defined(__hexagon__)
271*2b54f0dbSXin Li qurt_printf("%s", out_buffer);
272*2b54f0dbSXin Li #else
273*2b54f0dbSXin Li write(STDERR_FILENO, out_buffer, prefix_chars + format_chars + CLOG_SUFFIX_LENGTH);
274*2b54f0dbSXin Li #endif
275*2b54f0dbSXin Li
276*2b54f0dbSXin Li cleanup:
277*2b54f0dbSXin Li free(heap_buffer);
278*2b54f0dbSXin Li va_end(args_copy);
279*2b54f0dbSXin Li #endif
280*2b54f0dbSXin Li }
281*2b54f0dbSXin Li
clog_vlog_info(const char * module,const char * format,va_list args)282*2b54f0dbSXin Li void clog_vlog_info(const char* module, const char* format, va_list args) {
283*2b54f0dbSXin Li #if defined(__ANDROID__) && !CLOG_LOG_TO_STDIO
284*2b54f0dbSXin Li __android_log_vprint(ANDROID_LOG_INFO, module, format, args);
285*2b54f0dbSXin Li #else
286*2b54f0dbSXin Li char stack_buffer[CLOG_STACK_BUFFER_SIZE];
287*2b54f0dbSXin Li char* heap_buffer = NULL;
288*2b54f0dbSXin Li char* out_buffer = &stack_buffer[0];
289*2b54f0dbSXin Li
290*2b54f0dbSXin Li /* The first call to vsnprintf will clobber args, thus need a copy in case a second vsnprintf call is needed */
291*2b54f0dbSXin Li va_list args_copy;
292*2b54f0dbSXin Li va_copy(args_copy, args);
293*2b54f0dbSXin Li
294*2b54f0dbSXin Li int prefix_chars = CLOG_INFO_PREFIX_LENGTH;
295*2b54f0dbSXin Li if (module == NULL) {
296*2b54f0dbSXin Li memcpy(stack_buffer, CLOG_INFO_PREFIX, CLOG_INFO_PREFIX_LENGTH);
297*2b54f0dbSXin Li } else {
298*2b54f0dbSXin Li prefix_chars = snprintf(stack_buffer, CLOG_STACK_BUFFER_SIZE, CLOG_INFO_PREFIX_FORMAT, module);
299*2b54f0dbSXin Li if (prefix_chars < 0) {
300*2b54f0dbSXin Li /* Format error in prefix (possible if prefix is modified): skip prefix and continue as if nothing happened. */
301*2b54f0dbSXin Li prefix_chars = 0;
302*2b54f0dbSXin Li }
303*2b54f0dbSXin Li }
304*2b54f0dbSXin Li
305*2b54f0dbSXin Li int format_chars;
306*2b54f0dbSXin Li if (prefix_chars + CLOG_SUFFIX_LENGTH >= CLOG_STACK_BUFFER_SIZE) {
307*2b54f0dbSXin Li /*
308*2b54f0dbSXin Li * Prefix + suffix alone would overflow the on-stack buffer, thus need to use on-heap buffer.
309*2b54f0dbSXin Li * Do not even try to format the string into on-stack buffer.
310*2b54f0dbSXin Li */
311*2b54f0dbSXin Li format_chars = vsnprintf(NULL, 0, format, args);
312*2b54f0dbSXin Li } else {
313*2b54f0dbSXin Li format_chars =
314*2b54f0dbSXin Li vsnprintf(
315*2b54f0dbSXin Li &stack_buffer[prefix_chars],
316*2b54f0dbSXin Li CLOG_STACK_BUFFER_SIZE - prefix_chars - CLOG_SUFFIX_LENGTH,
317*2b54f0dbSXin Li format,
318*2b54f0dbSXin Li args);
319*2b54f0dbSXin Li }
320*2b54f0dbSXin Li if (format_chars < 0) {
321*2b54f0dbSXin Li /* Format error in the message: silently ignore this particular message. */
322*2b54f0dbSXin Li goto cleanup;
323*2b54f0dbSXin Li }
324*2b54f0dbSXin Li if (prefix_chars + format_chars + CLOG_SUFFIX_LENGTH > CLOG_STACK_BUFFER_SIZE) {
325*2b54f0dbSXin Li /* Allocate a buffer on heap, and vsnprintf to this buffer */
326*2b54f0dbSXin Li heap_buffer = malloc(prefix_chars + format_chars + CLOG_SUFFIX_LENGTH);
327*2b54f0dbSXin Li if (heap_buffer == NULL) {
328*2b54f0dbSXin Li goto cleanup;
329*2b54f0dbSXin Li }
330*2b54f0dbSXin Li
331*2b54f0dbSXin Li if (prefix_chars > CLOG_STACK_BUFFER_SIZE) {
332*2b54f0dbSXin Li /* Prefix didn't fit into on-stack buffer, re-format it again to on-heap buffer */
333*2b54f0dbSXin Li snprintf(heap_buffer, prefix_chars + 1 /* for '\0'-terminator */, CLOG_INFO_PREFIX_FORMAT, module);
334*2b54f0dbSXin Li } else {
335*2b54f0dbSXin Li /* Copy pre-formatted prefix from on-stack buffer to on-heap buffer */
336*2b54f0dbSXin Li memcpy(heap_buffer, stack_buffer, prefix_chars);
337*2b54f0dbSXin Li }
338*2b54f0dbSXin Li vsnprintf(heap_buffer + prefix_chars, format_chars + CLOG_SUFFIX_LENGTH, format, args_copy);
339*2b54f0dbSXin Li out_buffer = heap_buffer;
340*2b54f0dbSXin Li }
341*2b54f0dbSXin Li out_buffer[prefix_chars + format_chars] = '\n';
342*2b54f0dbSXin Li #if defined(_WIN32)
343*2b54f0dbSXin Li DWORD bytes_written;
344*2b54f0dbSXin Li WriteFile(
345*2b54f0dbSXin Li GetStdHandle(STD_OUTPUT_HANDLE),
346*2b54f0dbSXin Li out_buffer, prefix_chars + format_chars + CLOG_SUFFIX_LENGTH,
347*2b54f0dbSXin Li &bytes_written, NULL);
348*2b54f0dbSXin Li #elif defined(__hexagon__)
349*2b54f0dbSXin Li qurt_printf("%s", out_buffer);
350*2b54f0dbSXin Li #else
351*2b54f0dbSXin Li write(STDOUT_FILENO, out_buffer, prefix_chars + format_chars + CLOG_SUFFIX_LENGTH);
352*2b54f0dbSXin Li #endif
353*2b54f0dbSXin Li
354*2b54f0dbSXin Li cleanup:
355*2b54f0dbSXin Li free(heap_buffer);
356*2b54f0dbSXin Li va_end(args_copy);
357*2b54f0dbSXin Li #endif
358*2b54f0dbSXin Li }
359*2b54f0dbSXin Li
clog_vlog_debug(const char * module,const char * format,va_list args)360*2b54f0dbSXin Li void clog_vlog_debug(const char* module, const char* format, va_list args) {
361*2b54f0dbSXin Li #if defined(__ANDROID__) && !CLOG_LOG_TO_STDIO
362*2b54f0dbSXin Li __android_log_vprint(ANDROID_LOG_DEBUG, module, format, args);
363*2b54f0dbSXin Li #else
364*2b54f0dbSXin Li char stack_buffer[CLOG_STACK_BUFFER_SIZE];
365*2b54f0dbSXin Li char* heap_buffer = NULL;
366*2b54f0dbSXin Li char* out_buffer = &stack_buffer[0];
367*2b54f0dbSXin Li
368*2b54f0dbSXin Li /* The first call to vsnprintf will clobber args, thus need a copy in case a second vsnprintf call is needed */
369*2b54f0dbSXin Li va_list args_copy;
370*2b54f0dbSXin Li va_copy(args_copy, args);
371*2b54f0dbSXin Li
372*2b54f0dbSXin Li int prefix_chars = CLOG_DEBUG_PREFIX_LENGTH;
373*2b54f0dbSXin Li if (module == NULL) {
374*2b54f0dbSXin Li memcpy(stack_buffer, CLOG_DEBUG_PREFIX, CLOG_DEBUG_PREFIX_LENGTH);
375*2b54f0dbSXin Li } else {
376*2b54f0dbSXin Li prefix_chars = snprintf(stack_buffer, CLOG_STACK_BUFFER_SIZE, CLOG_DEBUG_PREFIX_FORMAT, module);
377*2b54f0dbSXin Li if (prefix_chars < 0) {
378*2b54f0dbSXin Li /* Format error in prefix (possible if prefix is modified): skip prefix and continue as if nothing happened. */
379*2b54f0dbSXin Li prefix_chars = 0;
380*2b54f0dbSXin Li }
381*2b54f0dbSXin Li }
382*2b54f0dbSXin Li
383*2b54f0dbSXin Li int format_chars;
384*2b54f0dbSXin Li if (prefix_chars + CLOG_SUFFIX_LENGTH >= CLOG_STACK_BUFFER_SIZE) {
385*2b54f0dbSXin Li /*
386*2b54f0dbSXin Li * Prefix + suffix alone would overflow the on-stack buffer, thus need to use on-heap buffer.
387*2b54f0dbSXin Li * Do not even try to format the string into on-stack buffer.
388*2b54f0dbSXin Li */
389*2b54f0dbSXin Li format_chars = vsnprintf(NULL, 0, format, args);
390*2b54f0dbSXin Li } else {
391*2b54f0dbSXin Li format_chars =
392*2b54f0dbSXin Li vsnprintf(
393*2b54f0dbSXin Li &stack_buffer[prefix_chars],
394*2b54f0dbSXin Li CLOG_STACK_BUFFER_SIZE - prefix_chars - CLOG_SUFFIX_LENGTH,
395*2b54f0dbSXin Li format,
396*2b54f0dbSXin Li args);
397*2b54f0dbSXin Li }
398*2b54f0dbSXin Li if (format_chars < 0) {
399*2b54f0dbSXin Li /* Format error in the message: silently ignore this particular message. */
400*2b54f0dbSXin Li goto cleanup;
401*2b54f0dbSXin Li }
402*2b54f0dbSXin Li if (prefix_chars + format_chars + CLOG_SUFFIX_LENGTH > CLOG_STACK_BUFFER_SIZE) {
403*2b54f0dbSXin Li /* Allocate a buffer on heap, and vsnprintf to this buffer */
404*2b54f0dbSXin Li heap_buffer = malloc(prefix_chars + format_chars + CLOG_SUFFIX_LENGTH);
405*2b54f0dbSXin Li if (heap_buffer == NULL) {
406*2b54f0dbSXin Li goto cleanup;
407*2b54f0dbSXin Li }
408*2b54f0dbSXin Li
409*2b54f0dbSXin Li if (prefix_chars > CLOG_STACK_BUFFER_SIZE) {
410*2b54f0dbSXin Li /* Prefix didn't fit into on-stack buffer, re-format it again to on-heap buffer */
411*2b54f0dbSXin Li snprintf(heap_buffer, prefix_chars + 1 /* for '\0'-terminator */, CLOG_DEBUG_PREFIX_FORMAT, module);
412*2b54f0dbSXin Li } else {
413*2b54f0dbSXin Li /* Copy pre-formatted prefix from on-stack buffer to on-heap buffer */
414*2b54f0dbSXin Li memcpy(heap_buffer, stack_buffer, prefix_chars);
415*2b54f0dbSXin Li }
416*2b54f0dbSXin Li vsnprintf(heap_buffer + prefix_chars, format_chars + CLOG_SUFFIX_LENGTH, format, args_copy);
417*2b54f0dbSXin Li out_buffer = heap_buffer;
418*2b54f0dbSXin Li }
419*2b54f0dbSXin Li out_buffer[prefix_chars + format_chars] = '\n';
420*2b54f0dbSXin Li #if defined(_WIN32)
421*2b54f0dbSXin Li DWORD bytes_written;
422*2b54f0dbSXin Li WriteFile(
423*2b54f0dbSXin Li GetStdHandle(STD_OUTPUT_HANDLE),
424*2b54f0dbSXin Li out_buffer, prefix_chars + format_chars + CLOG_SUFFIX_LENGTH,
425*2b54f0dbSXin Li &bytes_written, NULL);
426*2b54f0dbSXin Li #elif defined(__hexagon__)
427*2b54f0dbSXin Li qurt_printf("%s", out_buffer);
428*2b54f0dbSXin Li #else
429*2b54f0dbSXin Li write(STDOUT_FILENO, out_buffer, prefix_chars + format_chars + CLOG_SUFFIX_LENGTH);
430*2b54f0dbSXin Li #endif
431*2b54f0dbSXin Li
432*2b54f0dbSXin Li cleanup:
433*2b54f0dbSXin Li free(heap_buffer);
434*2b54f0dbSXin Li va_end(args_copy);
435*2b54f0dbSXin Li #endif
436*2b54f0dbSXin Li }
437