1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* Printf-like functions, with canned variants that malloc their result. */
9 #ifndef mozilla_Printf_h
10 #define mozilla_Printf_h
13 ** API for PR printf like routines.
15 ** These exist partly for historical reasons -- initially they were in
16 ** NSPR, then forked in tree and modified in js/ -- but now the prime
17 ** motivation is both closer control over the exact formatting (with
18 ** one exception, see below) and also the ability to control where
19 ** exactly the generated results are sent.
21 ** It might seem that this could all be dispensed with in favor of a
22 ** wrapper around |vsnprintf| -- except that this implementation
23 ** guarantees that the %s format will accept a NULL pointer, whereas
24 ** with standard functions this is undefined.
26 ** This supports the following formats. It implements a subset of the
27 ** standard formats; due to the use of MOZ_FORMAT_PRINTF, it is not
28 ** permissible to extend the standard, aside from relaxing undefined
32 ** %u - unsigned decimal
34 ** %X - unsigned uppercase hex
35 ** %o - unsigned octal
36 ** %hd, %hu, %hx, %hX, %ho - "short" versions of above
37 ** %ld, %lu, %lx, %lX, %lo - "long" versions of above
38 ** %lld, %llu, %llx, %llX, %llo - "long long" versions of above
39 ** %zd, %zo, %zu, %zx, %zX - size_t versions of above
40 ** %Id, %Io, %Iu, %Ix, %IX - size_t versions of above (for Windows compat).
41 ** Note that MSVC 2015 and newer supports the z length modifier so
42 ** users should prefer using %z instead of %I. We are supporting %I in
43 ** addition to %z in case third-party code that uses %I gets routed to
44 ** use this printf implementation.
46 ** %S, %ls - wide string, that is wchar_t*
48 ** %p - pointer (deals with machine dependent pointer size)
49 ** %f - float; note that this is actually formatted using the
50 ** system's native printf, and so the results may vary
51 ** %g - float; note that this is actually formatted using the
52 ** system's native printf, and so the results may vary
55 #include "mozilla/AllocPolicy.h"
56 #include "mozilla/Assertions.h"
57 #include "mozilla/Attributes.h"
58 #include "mozilla/IntegerPrintfMacros.h"
59 #include "mozilla/Types.h"
60 #include "mozilla/UniquePtr.h"
68 * This class may be subclassed to provide a way to get the output of
69 * a printf-like call, as the output is generated.
73 /* The Printf-like interface. */
74 bool MFBT_API
print(const char* format
, ...) MOZ_FORMAT_PRINTF(2, 3);
76 /* The Vprintf-like interface. */
77 bool MFBT_API
vprint(const char* fmt
, va_list) MOZ_FORMAT_PRINTF(2, 0);
79 /* Fast paths for formatting integers as though by %d, %o, %u, or %x.
80 Since octal and hex formatting always treat numbers as unsigned, there
81 are no signed overloads for AppendInt{Oct,Hex}. */
82 bool MFBT_API
appendIntDec(int32_t);
83 bool MFBT_API
appendIntDec(uint32_t);
84 bool MFBT_API
appendIntOct(uint32_t);
85 bool MFBT_API
appendIntHex(uint32_t);
86 bool MFBT_API
appendIntDec(int64_t);
87 bool MFBT_API
appendIntDec(uint64_t);
88 bool MFBT_API
appendIntOct(uint64_t);
89 bool MFBT_API
appendIntHex(uint64_t);
91 inline size_t emitted() { return mEmitted
; }
94 MFBT_API
PrintfTarget();
95 virtual ~PrintfTarget() = default;
97 /* Subclasses override this. It is called when more output is
98 available. It may be called with len==0. This should return
99 true on success, or false on failure. */
100 virtual bool append(const char* sp
, size_t len
) = 0;
103 /* Number of bytes emitted so far. */
106 /* The implementation calls this to emit bytes and update
108 bool emit(const char* sp
, size_t len
) {
110 return append(sp
, len
);
113 bool fill2(const char* src
, int srclen
, int width
, int flags
);
114 bool fill_n(const char* src
, int srclen
, int width
, int prec
, int type
,
116 bool cvt_l(long num
, int width
, int prec
, int radix
, int type
, int flags
,
118 bool cvt_ll(int64_t num
, int width
, int prec
, int radix
, int type
, int flags
,
120 bool cvt_f(double d
, char c
, int width
, int prec
, int flags
);
121 bool cvt_s(const char* s
, int width
, int prec
, int flags
);
126 template <typename AllocPolicy
= mozilla::MallocAllocPolicy
>
127 struct AllocPolicyBasedFreePolicy
{
128 void operator()(const void* ptr
) {
130 policy
.free_(const_cast<void*>(ptr
));
134 } // namespace detail
136 // The type returned by Smprintf and friends.
137 template <typename AllocPolicy
>
138 using SmprintfPolicyPointer
=
139 mozilla::UniquePtr
<char, detail::AllocPolicyBasedFreePolicy
<AllocPolicy
>>;
141 // The default type if no alloc policy is specified.
142 typedef SmprintfPolicyPointer
<mozilla::MallocAllocPolicy
> SmprintfPointer
;
144 // Used in the implementation of Smprintf et al.
145 template <typename AllocPolicy
>
146 class MOZ_STACK_CLASS SprintfState final
: private mozilla::PrintfTarget
,
147 private AllocPolicy
{
149 explicit SprintfState(char* base
)
150 : mMaxlen(base
? strlen(base
) : 0),
152 mCur(base
? base
+ mMaxlen
: 0) {}
154 ~SprintfState() { this->free_(mBase
); }
156 bool vprint(const char* format
, va_list ap_list
) MOZ_FORMAT_PRINTF(2, 0) {
157 // The "" here has a single \0 character, which is what we're
159 return mozilla::PrintfTarget::vprint(format
, ap_list
) && append("", 1);
162 SmprintfPolicyPointer
<AllocPolicy
> release() {
163 SmprintfPolicyPointer
<AllocPolicy
> result(mBase
);
169 bool append(const char* sp
, size_t len
) override
{
175 if (off
+ len
>= mMaxlen
) {
176 /* Grow the buffer */
177 newlen
= mMaxlen
+ ((len
> 32) ? len
: 32);
178 newbase
= this->template maybe_pod_malloc
<char>(newlen
);
180 /* Ran out of memory */
183 memcpy(newbase
, mBase
, mMaxlen
);
191 memcpy(mCur
, sp
, len
);
193 MOZ_ASSERT(size_t(mCur
- mBase
) <= mMaxlen
);
204 ** sprintf into a malloc'd buffer. Return a pointer to the malloc'd
205 ** buffer on success, nullptr on failure. Call AllocPolicy::free_ to release
206 ** the memory returned.
208 template <typename AllocPolicy
= mozilla::MallocAllocPolicy
>
209 MOZ_FORMAT_PRINTF(1, 2)
210 SmprintfPolicyPointer
<AllocPolicy
> Smprintf(const char* fmt
, ...) {
211 SprintfState
<AllocPolicy
> ss(nullptr);
214 bool r
= ss
.vprint(fmt
, ap
);
223 ** "append" sprintf into a malloc'd buffer. "last" is the last value of
224 ** the malloc'd buffer. sprintf will append data to the end of last,
225 ** growing it as necessary using realloc. If last is nullptr, SmprintfAppend
226 ** will allocate the initial string. The return value is the new value of
227 ** last for subsequent calls, or nullptr if there is a malloc failure.
229 template <typename AllocPolicy
= mozilla::MallocAllocPolicy
>
230 MOZ_FORMAT_PRINTF(2, 3)
231 SmprintfPolicyPointer
<AllocPolicy
> SmprintfAppend(
232 SmprintfPolicyPointer
<AllocPolicy
>&& last
, const char* fmt
, ...) {
233 SprintfState
<AllocPolicy
> ss(last
.release());
236 bool r
= ss
.vprint(fmt
, ap
);
245 ** va_list forms of the above.
247 template <typename AllocPolicy
= mozilla::MallocAllocPolicy
>
248 MOZ_FORMAT_PRINTF(1, 0)
249 SmprintfPolicyPointer
<AllocPolicy
> Vsmprintf(const char* fmt
, va_list ap
) {
250 SprintfState
<AllocPolicy
> ss(nullptr);
251 if (!ss
.vprint(fmt
, ap
)) return nullptr;
255 template <typename AllocPolicy
= mozilla::MallocAllocPolicy
>
256 MOZ_FORMAT_PRINTF(2, 0)
257 SmprintfPolicyPointer
<AllocPolicy
> VsmprintfAppend(
258 SmprintfPolicyPointer
<AllocPolicy
>&& last
, const char* fmt
, va_list ap
) {
259 SprintfState
<AllocPolicy
> ss(last
.release());
260 if (!ss
.vprint(fmt
, ap
)) return nullptr;
264 } // namespace mozilla
266 #endif /* mozilla_Printf_h */