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