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 #include "nsCRTGlue.h"
8 #include "nsXPCOM.h"
9 #include "nsDebug.h"
10 #include "prtime.h"
11
12 #include <stdlib.h>
13 #include <string.h>
14 #include <stdio.h>
15 #include <stdarg.h>
16
17 #include "mozilla/Sprintf.h"
18
19 #ifdef XP_WIN
20 # include <io.h>
21 # include <windows.h>
22 # include "mozilla/LateWriteChecks.h"
23 # include "mozilla/UniquePtr.h"
24 #endif
25
26 #ifdef ANDROID
27 # include <android/log.h>
28 #endif
29
30 using namespace mozilla;
31
NS_strspnp(const char * aDelims,const char * aStr)32 const char* NS_strspnp(const char* aDelims, const char* aStr) {
33 const char* d;
34 do {
35 for (d = aDelims; *d != '\0'; ++d) {
36 if (*aStr == *d) {
37 ++aStr;
38 break;
39 }
40 }
41 } while (*d);
42
43 return aStr;
44 }
45
NS_strtok(const char * aDelims,char ** aStr)46 char* NS_strtok(const char* aDelims, char** aStr) {
47 if (!*aStr) {
48 return nullptr;
49 }
50
51 char* ret = (char*)NS_strspnp(aDelims, *aStr);
52
53 if (!*ret) {
54 *aStr = ret;
55 return nullptr;
56 }
57
58 char* i = ret;
59 do {
60 for (const char* d = aDelims; *d != '\0'; ++d) {
61 if (*i == *d) {
62 *i = '\0';
63 *aStr = ++i;
64 return ret;
65 }
66 }
67 ++i;
68 } while (*i);
69
70 *aStr = nullptr;
71 return ret;
72 }
73
NS_strlen(const char16_t * aString)74 uint32_t NS_strlen(const char16_t* aString) {
75 MOZ_ASSERT(aString);
76 const char16_t* end;
77
78 for (end = aString; *end; ++end) {
79 // empty loop
80 }
81
82 return end - aString;
83 }
84
NS_strcmp(const char16_t * aStrA,const char16_t * aStrB)85 int NS_strcmp(const char16_t* aStrA, const char16_t* aStrB) {
86 while (*aStrB) {
87 int r = *aStrA - *aStrB;
88 if (r) {
89 return r;
90 }
91
92 ++aStrA;
93 ++aStrB;
94 }
95
96 return *aStrA != '\0';
97 }
98
NS_strncmp(const char16_t * aStrA,const char16_t * aStrB,size_t aLen)99 int NS_strncmp(const char16_t* aStrA, const char16_t* aStrB, size_t aLen) {
100 while (aLen && *aStrB) {
101 int r = *aStrA - *aStrB;
102 if (r) {
103 return r;
104 }
105
106 ++aStrA;
107 ++aStrB;
108 --aLen;
109 }
110
111 return aLen ? *aStrA != '\0' : 0;
112 }
113
NS_xstrdup(const char16_t * aString)114 char16_t* NS_xstrdup(const char16_t* aString) {
115 uint32_t len = NS_strlen(aString);
116 return NS_xstrndup(aString, len);
117 }
118
119 template <typename CharT>
NS_xstrndup(const CharT * aString,uint32_t aLen)120 CharT* NS_xstrndup(const CharT* aString, uint32_t aLen) {
121 auto newBuf = (CharT*)moz_xmalloc((aLen + 1) * sizeof(CharT));
122 memcpy(newBuf, aString, aLen * sizeof(CharT));
123 newBuf[aLen] = '\0';
124 return newBuf;
125 }
126
127 template char16_t* NS_xstrndup<char16_t>(const char16_t* aString,
128 uint32_t aLen);
129 template char* NS_xstrndup<char>(const char* aString, uint32_t aLen);
130
NS_xstrdup(const char * aString)131 char* NS_xstrdup(const char* aString) {
132 uint32_t len = strlen(aString);
133 char* str = (char*)moz_xmalloc(len + 1);
134 memcpy(str, aString, len);
135 str[len] = '\0';
136 return str;
137 }
138
139 // clang-format off
140
141 // This table maps uppercase characters to lower case characters;
142 // characters that are neither upper nor lower case are unaffected.
143 const unsigned char nsLowerUpperUtils::kUpper2Lower[256] = {
144 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
145 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
146 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
147 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
148 64,
149
150 // upper band mapped to lower [A-Z] => [a-z]
151 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,
152 112,113,114,115,116,117,118,119,120,121,122,
153
154 91, 92, 93, 94, 95,
155 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,
156 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
157 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
158 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
159 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
160 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
161 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
162 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
163 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
164 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
165 };
166
167 const unsigned char nsLowerUpperUtils::kLower2Upper[256] = {
168 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
169 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
170 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
171 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
172 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
173 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
174 96,
175
176 // lower band mapped to upper [a-z] => [A-Z]
177 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
178 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
179
180 123,124,125,126,127,
181 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
182 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
183 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
184 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
185 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
186 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
187 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
188 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
189 };
190
191 // clang-format on
192
NS_IsUpper(char aChar)193 bool NS_IsUpper(char aChar) {
194 return aChar != (char)nsLowerUpperUtils::kUpper2Lower[(unsigned char)aChar];
195 }
196
NS_IsLower(char aChar)197 bool NS_IsLower(char aChar) {
198 return aChar != (char)nsLowerUpperUtils::kLower2Upper[(unsigned char)aChar];
199 }
200
201 #ifndef XPCOM_GLUE_AVOID_NSPR
202
NS_MakeRandomString(char * aBuf,int32_t aBufLen)203 void NS_MakeRandomString(char* aBuf, int32_t aBufLen) {
204 # define TABLE_SIZE 36
205 static const char table[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
206 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
207 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
208 '1', '2', '3', '4', '5', '6', '7', '8', '9'};
209
210 // turn PR_Now() into milliseconds since epoch
211 // and salt rand with that.
212 static unsigned int seed = 0;
213 if (seed == 0) {
214 double fpTime = double(PR_Now());
215 seed =
216 (unsigned int)(fpTime * 1e-6 + 0.5); // use 1e-6, granularity of
217 // PR_Now() on the mac is seconds
218 srand(seed);
219 }
220
221 int32_t i;
222 for (i = 0; i < aBufLen; ++i) {
223 *aBuf++ = table[rand() % TABLE_SIZE];
224 }
225 *aBuf = 0;
226 }
227
228 #endif
229
230 #ifdef HAVE_VA_COPY
231 # define VARARGS_ASSIGN(foo, bar) VA_COPY(foo, bar)
232 #elif defined(HAVE_VA_LIST_AS_ARRAY)
233 # define VARARGS_ASSIGN(foo, bar) foo[0] = bar[0]
234 #else
235 # define VARARGS_ASSIGN(foo, bar) (foo) = (bar)
236 #endif
237
238 #if defined(XP_WIN)
vprintf_stderr(const char * aFmt,va_list aArgs)239 void vprintf_stderr(const char* aFmt, va_list aArgs) {
240 if (IsDebuggerPresent()) {
241 int lengthNeeded = _vscprintf(aFmt, aArgs);
242 if (lengthNeeded) {
243 lengthNeeded++;
244 auto buf = MakeUnique<char[]>(lengthNeeded);
245 if (buf) {
246 va_list argsCpy;
247 VARARGS_ASSIGN(argsCpy, aArgs);
248 vsnprintf(buf.get(), lengthNeeded, aFmt, argsCpy);
249 buf[lengthNeeded - 1] = '\0';
250 va_end(argsCpy);
251 OutputDebugStringA(buf.get());
252 }
253 }
254 }
255
256 // stderr is unbuffered by default so we open a new FILE (which is buffered)
257 // so that calls to printf_stderr are not as likely to get mixed together.
258 int fd = _fileno(stderr);
259 if (fd == -2) {
260 return;
261 }
262
263 FILE* fp = _fdopen(_dup(fd), "a");
264 if (!fp) {
265 return;
266 }
267
268 vfprintf(fp, aFmt, aArgs);
269
270 AutoSuspendLateWriteChecks suspend;
271 fclose(fp);
272 }
273
274 #elif defined(ANDROID)
vprintf_stderr(const char * aFmt,va_list aArgs)275 void vprintf_stderr(const char* aFmt, va_list aArgs) {
276 __android_log_vprint(ANDROID_LOG_INFO, "Gecko", aFmt, aArgs);
277 }
278 #else
vprintf_stderr(const char * aFmt,va_list aArgs)279 void vprintf_stderr(const char* aFmt, va_list aArgs) {
280 vfprintf(stderr, aFmt, aArgs);
281 }
282 #endif
283
printf_stderr(const char * aFmt,...)284 void printf_stderr(const char* aFmt, ...) {
285 va_list args;
286 va_start(args, aFmt);
287 vprintf_stderr(aFmt, args);
288 va_end(args);
289 }
290
fprintf_stderr(FILE * aFile,const char * aFmt,...)291 void fprintf_stderr(FILE* aFile, const char* aFmt, ...) {
292 va_list args;
293 va_start(args, aFmt);
294 if (aFile == stderr) {
295 vprintf_stderr(aFmt, args);
296 } else {
297 vfprintf(aFile, aFmt, args);
298 }
299 va_end(args);
300 }
301
print_stderr(std::stringstream & aStr)302 void print_stderr(std::stringstream& aStr) {
303 #if defined(ANDROID)
304 // On Android logcat output is truncated to 1024 chars per line, and
305 // we usually use std::stringstream to build up giant multi-line gobs
306 // of output. So to avoid the truncation we find the newlines and
307 // print the lines individually.
308 std::string line;
309 while (std::getline(aStr, line)) {
310 printf_stderr("%s\n", line.c_str());
311 }
312 #else
313 printf_stderr("%s", aStr.str().c_str());
314 #endif
315 }
316
fprint_stderr(FILE * aFile,std::stringstream & aStr)317 void fprint_stderr(FILE* aFile, std::stringstream& aStr) {
318 if (aFile == stderr) {
319 print_stderr(aStr);
320 } else {
321 fprintf_stderr(aFile, "%s", aStr.str().c_str());
322 }
323 }
324