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
|
#ifndef NEWSBOAT_STRPRINTF_H_
#define NEWSBOAT_STRPRINTF_H_
#include <cstdint>
#include <string>
#include <tuple>
#include <vector>
namespace newsboat {
namespace strprintf {
namespace detail {
template<typename T, typename... Args>
std::string fmt_impl(const std::string& format, const T& argument,
Args... args);
}
std::pair<std::string, std::string> split_format(
const std::string& printf_format);
std::string fmt(const std::string& format);
template<typename... Args>
std::string fmt(const std::string& format, const char* argument, Args... args)
{
return detail::fmt_impl(format, argument, args...);
}
template<typename... Args>
std::string fmt(const std::string& format, const int32_t argument, Args... args)
{
return detail::fmt_impl(format, argument, args...);
}
template<typename... Args>
std::string fmt(const std::string& format, const std::uint32_t argument,
Args... args)
{
return detail::fmt_impl(format, argument, args...);
}
template<typename... Args>
std::string fmt(const std::string& format, const int64_t argument, Args... args)
{
return detail::fmt_impl(format, argument, args...);
}
template<typename... Args>
std::string fmt(const std::string& format, const uint64_t argument,
Args... args)
{
return detail::fmt_impl(format, argument, args...);
}
template<typename... Args>
std::string fmt(const std::string& format, const void* argument, Args... args)
{
return detail::fmt_impl(format, argument, args...);
}
template<typename... Args>
std::string fmt(const std::string& format, const std::nullptr_t argument,
Args... args)
{
return detail::fmt_impl(format, argument, args...);
}
template<typename... Args>
std::string fmt(const std::string& format, const float argument, Args... args)
{
// Variadic functions (like snprintf) do not accept `float`, so let's
// convert that.
return detail::fmt_impl(format, static_cast<double>(argument), args...);
}
template<typename... Args>
std::string fmt(const std::string& format, const double argument, Args... args)
{
return detail::fmt_impl(format, argument, args...);
}
template<typename... Args>
std::string fmt(const std::string& format,
const std::string& argument,
Args... args)
{
return fmt(format, argument.c_str(), args...);
}
template<typename... Args>
std::string fmt(const std::string& format,
const std::string* argument,
Args... args)
{
return fmt(format, argument->c_str(), args...);
}
namespace detail {
template<typename T, typename... Args>
std::string fmt_impl(const std::string& format, const T& argument, Args... args)
{
std::string local_format, remaining_format;
std::tie(local_format, remaining_format) = split_format(format);
char buffer[1024];
std::string result;
unsigned int len = 1 +
snprintf(buffer,
sizeof(buffer),
local_format.c_str(),
argument);
// snprintf returns the length of the formatted string. If it's
// longer than the buffer size, we have to enlarge the buffer in
// order to get the whole result.
//
// `<=` is correct since we've added 1 to `len`, above. We have to
// do it because `buffer` has to fit not only the string but the
// terminating null byte as well.
if (len <= sizeof(buffer)) {
result = buffer;
} else {
std::vector<char> buf(len);
snprintf(
buf.data(), len, local_format.c_str(), argument);
result = buf.data();
}
return result + fmt(remaining_format, args...);
}
}
};
} // namespace newsboat
#endif /* NEWSBOAT_STRPRINTF_H_ */
|