File: DefaultFormatter.cpp

package info (click to toggle)
spring 103.0%2Bdfsg2-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 43,720 kB
  • ctags: 63,685
  • sloc: cpp: 368,283; ansic: 33,988; python: 12,417; java: 12,203; awk: 5,879; sh: 1,846; xml: 655; perl: 405; php: 211; objc: 194; makefile: 77; sed: 2
file content (182 lines) | stat: -rw-r--r-- 4,783 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */

/**
 * This is the default formatter for the ILog.h logging API.
 * It formats the message and eventually adds a prefix.
 * The prefix will usually consist of the level, section and possibly a
 * timestamp.
 */

#include "LogUtil.h"
#include "Level.h"
#include "Section.h"
#include "System/maindefines.h"
#include "System/SafeCStrings.h"

#include <cstdio>
#include <cstdarg>
#include <cstring>


#ifdef __cplusplus
extern "C" {
#endif

#ifdef _MSC_VER
#define va_copy(dst, src) ((dst) = (src))
#endif

static const int SECTION_SIZE_MIN = 10;
static const int SECTION_SIZE_MAX = 20;


// *******************************************************************************************
// Helpers
static inline void ResizeBuffer(char** buffer, size_t* bufferSize, const bool copy = false)
{
	char* old = *buffer;

	*bufferSize <<= 2; // `2` to increase it faster
	*buffer = new char[*bufferSize];

	if (copy) {
		memcpy(*buffer, old, (*bufferSize) >> 2);
	}

	delete[] old;
}

static inline void PrintfAppend(char** buffer, size_t* bufferSize, const char* fmt, va_list arguments)
{
	// dynamically adjust the buffer size until VSNPRINTF returns fine
	size_t bufferPos = strlen(*buffer);

	do {
		const size_t freeBufferSize = (*bufferSize) - bufferPos;
		char* bufAppendPos = &((*buffer)[bufferPos]);

		// printf will move the internal pointer of va_list.
		// So we need to make a copy, if want to run it again.
		va_list arguments_;
		va_copy(arguments_, arguments); 
		const int writtenChars = VSNPRINTF(bufAppendPos, freeBufferSize, fmt, arguments_);
		va_end(arguments_);

		// since writtenChars excludes the null terminator (if any was written),
		// writtenChars >= freeBufferSize always means buffer was too small
		// NOTE: earlier glibc versions and MSVC will return -1 when buffer is too small
		// const bool bufferTooSmall = writtenChars >= freeBufferSize || writtenChars < 0;

		if (writtenChars >= 0 && writtenChars < freeBufferSize)
			break;

		ResizeBuffer(buffer, bufferSize, true);
	} while (true);
}


// *******************************************************************************************

/*
static void log_formatter_createPrefix_xorgStyle(
	char** buffer,
	size_t* bufferSize,
	const char* section,
	int level
) {
	const char* prepSection = log_util_prepareSection(section);
	const char levelChar = log_util_levelToChar(level);

	SNPRINTF(*buffer, *bufferSize, "(%c%c) %*.*s - ", levelChar, levelChar,
			SECTION_SIZE_MIN, SECTION_SIZE_MAX, prepSection);
}
*/

/*
static void log_formatter_createPrefix_testing(
	char** buffer,
	size_t* bufferSize,
	const char* section,
	int level
) {
	const char* prepSection = log_util_prepareSection(section);
	const char* levelStr = log_util_levelToString(level);

	SNPRINTF(*buffer, *bufferSize, "%s %s: ", levelStr, prepSection);
}
*/

static void log_formatter_createPrefix_default(
	char** buffer,
	size_t* bufferSize,
	const char* section,
	int level
) {
	(*buffer)[0] = '\0';

	if (!LOG_SECTION_IS_DEFAULT(section)) {
		const char* prepSection = log_util_prepareSection(section);
		STRCAT_T(*buffer, *bufferSize, "[");
		STRCAT_T(*buffer, *bufferSize, prepSection);
		STRCAT_T(*buffer, *bufferSize, "] ");
	}
	if (level != LOG_LEVEL_INFO && level != LOG_LEVEL_NOTICE) {
		const char* levelStr = log_util_levelToString(level);
		STRCAT_T(*buffer, *bufferSize, levelStr);
		STRCAT_T(*buffer, *bufferSize, ": ");
	}
}


static inline void log_formatter_createPrefix(
	char** buffer,
	size_t* bufferSize,
	const char* section,
	int level
) {
	//log_formatter_createPrefix_xorgStyle(buffer, bufferSize, section, level);
	//log_formatter_createPrefix_testing(buffer, bufferSize, section, level);
	log_formatter_createPrefix_default(buffer, bufferSize, section, level);

	// check if the buffer was large enough, if not resize it and try again
	if ((strlen(*buffer) + 1) >= *bufferSize) {
		ResizeBuffer(buffer, bufferSize);
		log_formatter_createPrefix(buffer, bufferSize, section, level); // recursive
	}
}

// *******************************************************************************************

/**
 * @name logging_formatter
 * ILog.h formatter implementation.
 */
///@{

/**
 * Formats a log entry into its final string form.
 * @return a string buffer, allocated with new[] -> you have to delete[] it
 */
char* log_formatter_format(const char* section, int level, const char* fmt, va_list arguments)
{
	size_t bufferSize = 256;

	char* mem = new char[bufferSize];
	char** buffer = &mem;

	memset(&mem[0], 0, bufferSize);

	#if 1
	log_formatter_createPrefix(buffer, &bufferSize, section, level);
	PrintfAppend(buffer, &bufferSize, fmt, arguments);
	#endif

	return mem;
}

///@}

#ifdef __cplusplus
} // extern "C"
#endif