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