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/. */
6 
7 /*
8  * This code was copied from xpcom/ds/nsTextFormatter r1.3
9  *           Memory model and Frozen linkage changes only.
10  *                           -- Prasad <prasad@medhas.org>
11  */
12 
13 #ifndef nsTextFormatter_h___
14 #define nsTextFormatter_h___
15 
16 /*
17  ** API for PR printf like routines. Supports the following formats
18  **	%d - decimal
19  **	%u - unsigned decimal
20  **	%x - unsigned hex
21  **	%X - unsigned uppercase hex
22  **	%o - unsigned octal
23  **	%hd, %hu, %hx, %hX, %ho - 16-bit versions of above
24  **	%ld, %lu, %lx, %lX, %lo - 32-bit versions of above
25  **	%lld, %llu, %llx, %llX, %llo - 64 bit versions of above
26  **	%s - utf8 string
27  **	%S - char16_t string
28  **	%c - character
29  **	%p - pointer (deals with machine dependent pointer size)
30  **	%f - float
31  **	%g - float
32  */
33 #include <stdio.h>
34 #include <stdarg.h>
35 #include "nscore.h"
36 #include "nsString.h"
37 #include "mozilla/Span.h"
38 #include "mozilla/TypeTraits.h"
39 
40 #ifdef XPCOM_GLUE
41 #error \
42     "nsTextFormatter is not available in the standalone glue due to NSPR dependencies."
43 #endif
44 
45 class nsTextFormatter {
46  public:
47   /*
48    * sprintf into a fixed size buffer. Guarantees that the buffer is null
49    * terminated. Returns the length of the written output, NOT including the
50    * null terminator, or (uint32_t)-1 if an error occurs.
51    */
52   template <typename... T>
snprintf(char16_t * aOut,uint32_t aOutLen,const char16_t * aFmt,T...aArgs)53   static uint32_t snprintf(char16_t* aOut, uint32_t aOutLen,
54                            const char16_t* aFmt, T... aArgs) {
55     BoxedValue values[] = {BoxedValue(aArgs)...};
56     return vsnprintf(aOut, aOutLen, aFmt,
57                      mozilla::MakeSpan(values, sizeof...(aArgs)));
58   }
59 
60   /*
61    * sprintf into an existing nsAString, overwriting any contents it already
62    * has. Infallible.
63    */
64   template <typename... T>
ssprintf(nsAString & aOut,const char16_t * aFmt,T...aArgs)65   static void ssprintf(nsAString& aOut, const char16_t* aFmt, T... aArgs) {
66     BoxedValue values[] = {BoxedValue(aArgs)...};
67     vssprintf(aOut, aFmt, mozilla::MakeSpan(values, sizeof...(aArgs)));
68   }
69 
70  private:
71   enum ArgumentKind {
72     INT,
73     UINT,
74     POINTER,
75     DOUBLE,
76     STRING,
77     STRING16,
78     INTPOINTER,
79   };
80 
81   union ValueUnion {
82     int64_t mInt;
83     uint64_t mUInt;
84     void const* mPtr;
85     double mDouble;
86     char const* mString;
87     char16_t const* mString16;
88     int* mIntPtr;
89   };
90 
91   struct BoxedValue {
92     ArgumentKind mKind;
93     ValueUnion mValue;
94 
BoxedValueBoxedValue95     explicit BoxedValue(int aArg) : mKind(INT) { mValue.mInt = aArg; }
96 
BoxedValueBoxedValue97     explicit BoxedValue(unsigned int aArg) : mKind(UINT) {
98       mValue.mUInt = aArg;
99     }
100 
BoxedValueBoxedValue101     explicit BoxedValue(long aArg) : mKind(INT) { mValue.mInt = aArg; }
102 
BoxedValueBoxedValue103     explicit BoxedValue(unsigned long aArg) : mKind(UINT) {
104       mValue.mUInt = aArg;
105     }
106 
BoxedValueBoxedValue107     explicit BoxedValue(long long aArg) : mKind(INT) { mValue.mInt = aArg; }
108 
BoxedValueBoxedValue109     explicit BoxedValue(unsigned long long aArg) : mKind(UINT) {
110       mValue.mUInt = aArg;
111     }
112 
BoxedValueBoxedValue113     explicit BoxedValue(const void* aArg) : mKind(POINTER) {
114       mValue.mPtr = aArg;
115     }
116 
BoxedValueBoxedValue117     explicit BoxedValue(double aArg) : mKind(DOUBLE) { mValue.mDouble = aArg; }
118 
BoxedValueBoxedValue119     explicit BoxedValue(const char* aArg) : mKind(STRING) {
120       mValue.mString = aArg;
121     }
122 
BoxedValueBoxedValue123     explicit BoxedValue(const char16_t* aArg) : mKind(STRING16) {
124       mValue.mString16 = aArg;
125     }
126 
127 #if defined(MOZ_USE_CHAR16_WRAPPER)
BoxedValueBoxedValue128     explicit BoxedValue(const char16ptr_t aArg) : mKind(STRING16) {
129       mValue.mString16 = aArg;
130     }
131 
132 #endif
133 
BoxedValueBoxedValue134     explicit BoxedValue(int* aArg) : mKind(INTPOINTER) {
135       mValue.mIntPtr = aArg;
136     }
137 
IntCompatibleBoxedValue138     bool IntCompatible() const { return mKind == INT || mKind == UINT; }
139 
PointerCompatibleBoxedValue140     bool PointerCompatible() const {
141       return mKind == POINTER || mKind == STRING || mKind == STRING16 ||
142              mKind == INTPOINTER;
143     }
144   };
145 
146   struct SprintfStateStr;
147 
148   static int fill2(SprintfStateStr* aState, const char16_t* aSrc, int aSrcLen,
149                    int aWidth, int aFlags);
150   static int fill_n(SprintfStateStr* aState, const char16_t* aSrc, int aSrcLen,
151                     int aWidth, int aPrec, int aFlags);
152   static int cvt_ll(SprintfStateStr* aState, uint64_t aNum, int aWidth,
153                     int aPrec, int aRadix, int aFlags, const char16_t* aHexStr);
154   static int cvt_f(SprintfStateStr* aState, double aDouble, int aWidth,
155                    int aPrec, const char16_t aType, int aFlags);
156   static int cvt_S(SprintfStateStr* aState, const char16_t* aStr, int aWidth,
157                    int aPrec, int aFlags);
158   static int cvt_s(SprintfStateStr* aState, const char* aStr, int aWidth,
159                    int aPrec, int aFlags);
160   static int dosprintf(SprintfStateStr* aState, const char16_t* aFmt,
161                        mozilla::Span<BoxedValue> aValues);
162   static int StringStuff(SprintfStateStr* aState, const char16_t* aStr,
163                          uint32_t aLen);
164   static int LimitStuff(SprintfStateStr* aState, const char16_t* aStr,
165                         uint32_t aLen);
166   static uint32_t vsnprintf(char16_t* aOut, uint32_t aOutLen,
167                             const char16_t* aFmt,
168                             mozilla::Span<BoxedValue> aValues);
169   static void vssprintf(nsAString& aOut, const char16_t* aFmt,
170                         mozilla::Span<BoxedValue> aValues);
171 };
172 
173 #endif /* nsTextFormatter_h___ */
174