Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | |
michael@0 | 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | #include "primpl.h" |
michael@0 | 8 | #include "prenv.h" |
michael@0 | 9 | #include "prprf.h" |
michael@0 | 10 | #include <string.h> |
michael@0 | 11 | #ifdef ANDROID |
michael@0 | 12 | #include <android/log.h> |
michael@0 | 13 | #endif |
michael@0 | 14 | |
michael@0 | 15 | /* |
michael@0 | 16 | * Lock used to lock the log. |
michael@0 | 17 | * |
michael@0 | 18 | * We can't define _PR_LOCK_LOG simply as PR_Lock because PR_Lock may |
michael@0 | 19 | * contain assertions. We have to avoid assertions in _PR_LOCK_LOG |
michael@0 | 20 | * because PR_ASSERT calls PR_LogPrint, which in turn calls _PR_LOCK_LOG. |
michael@0 | 21 | * This can lead to infinite recursion. |
michael@0 | 22 | */ |
michael@0 | 23 | static PRLock *_pr_logLock; |
michael@0 | 24 | #if defined(_PR_PTHREADS) || defined(_PR_BTHREADS) |
michael@0 | 25 | #define _PR_LOCK_LOG() PR_Lock(_pr_logLock); |
michael@0 | 26 | #define _PR_UNLOCK_LOG() PR_Unlock(_pr_logLock); |
michael@0 | 27 | #elif defined(_PR_GLOBAL_THREADS_ONLY) |
michael@0 | 28 | #define _PR_LOCK_LOG() { _PR_LOCK_LOCK(_pr_logLock) |
michael@0 | 29 | #define _PR_UNLOCK_LOG() _PR_LOCK_UNLOCK(_pr_logLock); } |
michael@0 | 30 | #else |
michael@0 | 31 | |
michael@0 | 32 | #define _PR_LOCK_LOG() \ |
michael@0 | 33 | { \ |
michael@0 | 34 | PRIntn _is; \ |
michael@0 | 35 | PRThread *_me = _PR_MD_CURRENT_THREAD(); \ |
michael@0 | 36 | if (!_PR_IS_NATIVE_THREAD(_me)) \ |
michael@0 | 37 | _PR_INTSOFF(_is); \ |
michael@0 | 38 | _PR_LOCK_LOCK(_pr_logLock) |
michael@0 | 39 | |
michael@0 | 40 | #define _PR_UNLOCK_LOG() \ |
michael@0 | 41 | _PR_LOCK_UNLOCK(_pr_logLock); \ |
michael@0 | 42 | PR_ASSERT(_me == _PR_MD_CURRENT_THREAD()); \ |
michael@0 | 43 | if (!_PR_IS_NATIVE_THREAD(_me)) \ |
michael@0 | 44 | _PR_INTSON(_is); \ |
michael@0 | 45 | } |
michael@0 | 46 | |
michael@0 | 47 | #endif |
michael@0 | 48 | |
michael@0 | 49 | #if defined(XP_PC) |
michael@0 | 50 | #define strcasecmp stricmp |
michael@0 | 51 | #endif |
michael@0 | 52 | |
michael@0 | 53 | /* |
michael@0 | 54 | * On NT, we can't define _PUT_LOG as PR_Write or _PR_MD_WRITE, |
michael@0 | 55 | * because every asynchronous file io operation leads to a fiber context |
michael@0 | 56 | * switch. So we define _PUT_LOG as fputs (from stdio.h). A side |
michael@0 | 57 | * benefit is that fputs handles the LF->CRLF translation. This |
michael@0 | 58 | * code can also be used on other platforms with file stream io. |
michael@0 | 59 | */ |
michael@0 | 60 | #if defined(WIN32) || defined(XP_OS2) |
michael@0 | 61 | #define _PR_USE_STDIO_FOR_LOGGING |
michael@0 | 62 | #endif |
michael@0 | 63 | |
michael@0 | 64 | /* |
michael@0 | 65 | ** Coerce Win32 log output to use OutputDebugString() when |
michael@0 | 66 | ** NSPR_LOG_FILE is set to "WinDebug". |
michael@0 | 67 | */ |
michael@0 | 68 | #if defined(XP_PC) |
michael@0 | 69 | #define WIN32_DEBUG_FILE (FILE*)-2 |
michael@0 | 70 | #endif |
michael@0 | 71 | |
michael@0 | 72 | #ifdef WINCE |
michael@0 | 73 | static void OutputDebugStringA(const char* msg) { |
michael@0 | 74 | int len = MultiByteToWideChar(CP_ACP, 0, msg, -1, 0, 0); |
michael@0 | 75 | WCHAR *wMsg = (WCHAR *)PR_Malloc(len * sizeof(WCHAR)); |
michael@0 | 76 | MultiByteToWideChar(CP_ACP, 0, msg, -1, wMsg, len); |
michael@0 | 77 | OutputDebugStringW(wMsg); |
michael@0 | 78 | PR_Free(wMsg); |
michael@0 | 79 | } |
michael@0 | 80 | #endif |
michael@0 | 81 | |
michael@0 | 82 | /* Macros used to reduce #ifdef pollution */ |
michael@0 | 83 | |
michael@0 | 84 | #if defined(_PR_USE_STDIO_FOR_LOGGING) && defined(XP_PC) |
michael@0 | 85 | #define _PUT_LOG(fd, buf, nb) \ |
michael@0 | 86 | PR_BEGIN_MACRO \ |
michael@0 | 87 | if (logFile == WIN32_DEBUG_FILE) { \ |
michael@0 | 88 | char savebyte = buf[nb]; \ |
michael@0 | 89 | buf[nb] = '\0'; \ |
michael@0 | 90 | OutputDebugStringA(buf); \ |
michael@0 | 91 | buf[nb] = savebyte; \ |
michael@0 | 92 | } else { \ |
michael@0 | 93 | fwrite(buf, 1, nb, fd); \ |
michael@0 | 94 | fflush(fd); \ |
michael@0 | 95 | } \ |
michael@0 | 96 | PR_END_MACRO |
michael@0 | 97 | #elif defined(_PR_USE_STDIO_FOR_LOGGING) |
michael@0 | 98 | #define _PUT_LOG(fd, buf, nb) {fwrite(buf, 1, nb, fd); fflush(fd);} |
michael@0 | 99 | #elif defined(ANDROID) |
michael@0 | 100 | #define _PUT_LOG(fd, buf, nb) \ |
michael@0 | 101 | PR_BEGIN_MACRO \ |
michael@0 | 102 | if (fd == _pr_stderr) { \ |
michael@0 | 103 | char savebyte = buf[nb]; \ |
michael@0 | 104 | buf[nb] = '\0'; \ |
michael@0 | 105 | __android_log_write(ANDROID_LOG_INFO, "PRLog", buf); \ |
michael@0 | 106 | buf[nb] = savebyte; \ |
michael@0 | 107 | } else { \ |
michael@0 | 108 | PR_Write(fd, buf, nb); \ |
michael@0 | 109 | } \ |
michael@0 | 110 | PR_END_MACRO |
michael@0 | 111 | #elif defined(_PR_PTHREADS) |
michael@0 | 112 | #define _PUT_LOG(fd, buf, nb) PR_Write(fd, buf, nb) |
michael@0 | 113 | #else |
michael@0 | 114 | #define _PUT_LOG(fd, buf, nb) _PR_MD_WRITE(fd, buf, nb) |
michael@0 | 115 | #endif |
michael@0 | 116 | |
michael@0 | 117 | /************************************************************************/ |
michael@0 | 118 | |
michael@0 | 119 | static PRLogModuleInfo *logModules; |
michael@0 | 120 | |
michael@0 | 121 | static char *logBuf = NULL; |
michael@0 | 122 | static char *logp; |
michael@0 | 123 | static char *logEndp; |
michael@0 | 124 | #ifdef _PR_USE_STDIO_FOR_LOGGING |
michael@0 | 125 | static FILE *logFile = NULL; |
michael@0 | 126 | #else |
michael@0 | 127 | static PRFileDesc *logFile = 0; |
michael@0 | 128 | #endif |
michael@0 | 129 | static PRBool outputTimeStamp = PR_FALSE; |
michael@0 | 130 | static PRBool appendToLog = PR_FALSE; |
michael@0 | 131 | |
michael@0 | 132 | #define LINE_BUF_SIZE 512 |
michael@0 | 133 | #define DEFAULT_BUF_SIZE 16384 |
michael@0 | 134 | |
michael@0 | 135 | #ifdef _PR_NEED_STRCASECMP |
michael@0 | 136 | |
michael@0 | 137 | /* |
michael@0 | 138 | * strcasecmp is defined in /usr/ucblib/libucb.a on some platforms |
michael@0 | 139 | * such as NCR and Unixware. Linking with both libc and libucb |
michael@0 | 140 | * may cause some problem, so I just provide our own implementation |
michael@0 | 141 | * of strcasecmp here. |
michael@0 | 142 | */ |
michael@0 | 143 | |
michael@0 | 144 | static const unsigned char uc[] = |
michael@0 | 145 | { |
michael@0 | 146 | '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', |
michael@0 | 147 | '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017', |
michael@0 | 148 | '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027', |
michael@0 | 149 | '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037', |
michael@0 | 150 | ' ', '!', '"', '#', '$', '%', '&', '\'', |
michael@0 | 151 | '(', ')', '*', '+', ',', '-', '.', '/', |
michael@0 | 152 | '0', '1', '2', '3', '4', '5', '6', '7', |
michael@0 | 153 | '8', '9', ':', ';', '<', '=', '>', '?', |
michael@0 | 154 | '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', |
michael@0 | 155 | 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', |
michael@0 | 156 | 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', |
michael@0 | 157 | 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', |
michael@0 | 158 | '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', |
michael@0 | 159 | 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', |
michael@0 | 160 | 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', |
michael@0 | 161 | 'X', 'Y', 'Z', '{', '|', '}', '~', '\177' |
michael@0 | 162 | }; |
michael@0 | 163 | |
michael@0 | 164 | PRIntn strcasecmp(const char *a, const char *b) |
michael@0 | 165 | { |
michael@0 | 166 | const unsigned char *ua = (const unsigned char *)a; |
michael@0 | 167 | const unsigned char *ub = (const unsigned char *)b; |
michael@0 | 168 | |
michael@0 | 169 | if( ((const char *)0 == a) || (const char *)0 == b ) |
michael@0 | 170 | return (PRIntn)(a-b); |
michael@0 | 171 | |
michael@0 | 172 | while( (uc[*ua] == uc[*ub]) && ('\0' != *a) ) |
michael@0 | 173 | { |
michael@0 | 174 | a++; |
michael@0 | 175 | ua++; |
michael@0 | 176 | ub++; |
michael@0 | 177 | } |
michael@0 | 178 | |
michael@0 | 179 | return (PRIntn)(uc[*ua] - uc[*ub]); |
michael@0 | 180 | } |
michael@0 | 181 | |
michael@0 | 182 | #endif /* _PR_NEED_STRCASECMP */ |
michael@0 | 183 | |
michael@0 | 184 | void _PR_InitLog(void) |
michael@0 | 185 | { |
michael@0 | 186 | char *ev; |
michael@0 | 187 | |
michael@0 | 188 | _pr_logLock = PR_NewLock(); |
michael@0 | 189 | |
michael@0 | 190 | ev = PR_GetEnv("NSPR_LOG_MODULES"); |
michael@0 | 191 | if (ev && ev[0]) { |
michael@0 | 192 | char module[64]; /* Security-Critical: If you change this |
michael@0 | 193 | * size, you must also change the sscanf |
michael@0 | 194 | * format string to be size-1. |
michael@0 | 195 | */ |
michael@0 | 196 | PRBool isSync = PR_FALSE; |
michael@0 | 197 | PRIntn evlen = strlen(ev), pos = 0; |
michael@0 | 198 | PRInt32 bufSize = DEFAULT_BUF_SIZE; |
michael@0 | 199 | while (pos < evlen) { |
michael@0 | 200 | PRIntn level = 1, count = 0, delta = 0; |
michael@0 | 201 | count = sscanf(&ev[pos], "%63[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-]%n:%d%n", |
michael@0 | 202 | module, &delta, &level, &delta); |
michael@0 | 203 | pos += delta; |
michael@0 | 204 | if (count == 0) break; |
michael@0 | 205 | |
michael@0 | 206 | /* |
michael@0 | 207 | ** If count == 2, then we got module and level. If count |
michael@0 | 208 | ** == 1, then level defaults to 1 (module enabled). |
michael@0 | 209 | */ |
michael@0 | 210 | if (strcasecmp(module, "sync") == 0) { |
michael@0 | 211 | isSync = PR_TRUE; |
michael@0 | 212 | } else if (strcasecmp(module, "bufsize") == 0) { |
michael@0 | 213 | if (level >= LINE_BUF_SIZE) { |
michael@0 | 214 | bufSize = level; |
michael@0 | 215 | } |
michael@0 | 216 | } else if (strcasecmp(module, "timestamp") == 0) { |
michael@0 | 217 | outputTimeStamp = PR_TRUE; |
michael@0 | 218 | } else if (strcasecmp(module, "append") == 0) { |
michael@0 | 219 | appendToLog = PR_TRUE; |
michael@0 | 220 | } else { |
michael@0 | 221 | PRLogModuleInfo *lm = logModules; |
michael@0 | 222 | PRBool skip_modcheck = |
michael@0 | 223 | (0 == strcasecmp (module, "all")) ? PR_TRUE : PR_FALSE; |
michael@0 | 224 | |
michael@0 | 225 | while (lm != NULL) { |
michael@0 | 226 | if (skip_modcheck) lm -> level = (PRLogModuleLevel)level; |
michael@0 | 227 | else if (strcasecmp(module, lm->name) == 0) { |
michael@0 | 228 | lm->level = (PRLogModuleLevel)level; |
michael@0 | 229 | break; |
michael@0 | 230 | } |
michael@0 | 231 | lm = lm->next; |
michael@0 | 232 | } |
michael@0 | 233 | } |
michael@0 | 234 | /*found:*/ |
michael@0 | 235 | count = sscanf(&ev[pos], " , %n", &delta); |
michael@0 | 236 | pos += delta; |
michael@0 | 237 | if (count == EOF) break; |
michael@0 | 238 | } |
michael@0 | 239 | PR_SetLogBuffering(isSync ? 0 : bufSize); |
michael@0 | 240 | |
michael@0 | 241 | #ifdef XP_UNIX |
michael@0 | 242 | if ((getuid() != geteuid()) || (getgid() != getegid())) { |
michael@0 | 243 | return; |
michael@0 | 244 | } |
michael@0 | 245 | #endif /* XP_UNIX */ |
michael@0 | 246 | |
michael@0 | 247 | ev = PR_GetEnv("NSPR_LOG_FILE"); |
michael@0 | 248 | if (ev && ev[0]) { |
michael@0 | 249 | if (!PR_SetLogFile(ev)) { |
michael@0 | 250 | #ifdef XP_PC |
michael@0 | 251 | char* str = PR_smprintf("Unable to create nspr log file '%s'\n", ev); |
michael@0 | 252 | if (str) { |
michael@0 | 253 | OutputDebugStringA(str); |
michael@0 | 254 | PR_smprintf_free(str); |
michael@0 | 255 | } |
michael@0 | 256 | #else |
michael@0 | 257 | fprintf(stderr, "Unable to create nspr log file '%s'\n", ev); |
michael@0 | 258 | #endif |
michael@0 | 259 | } |
michael@0 | 260 | } else { |
michael@0 | 261 | #ifdef _PR_USE_STDIO_FOR_LOGGING |
michael@0 | 262 | logFile = stderr; |
michael@0 | 263 | #else |
michael@0 | 264 | logFile = _pr_stderr; |
michael@0 | 265 | #endif |
michael@0 | 266 | } |
michael@0 | 267 | } |
michael@0 | 268 | } |
michael@0 | 269 | |
michael@0 | 270 | void _PR_LogCleanup(void) |
michael@0 | 271 | { |
michael@0 | 272 | PRLogModuleInfo *lm = logModules; |
michael@0 | 273 | |
michael@0 | 274 | PR_LogFlush(); |
michael@0 | 275 | |
michael@0 | 276 | #ifdef _PR_USE_STDIO_FOR_LOGGING |
michael@0 | 277 | if (logFile |
michael@0 | 278 | && logFile != stdout |
michael@0 | 279 | && logFile != stderr |
michael@0 | 280 | #ifdef XP_PC |
michael@0 | 281 | && logFile != WIN32_DEBUG_FILE |
michael@0 | 282 | #endif |
michael@0 | 283 | ) { |
michael@0 | 284 | fclose(logFile); |
michael@0 | 285 | } |
michael@0 | 286 | #else |
michael@0 | 287 | if (logFile && logFile != _pr_stdout && logFile != _pr_stderr) { |
michael@0 | 288 | PR_Close(logFile); |
michael@0 | 289 | } |
michael@0 | 290 | #endif |
michael@0 | 291 | logFile = NULL; |
michael@0 | 292 | |
michael@0 | 293 | if (logBuf) |
michael@0 | 294 | PR_DELETE(logBuf); |
michael@0 | 295 | |
michael@0 | 296 | while (lm != NULL) { |
michael@0 | 297 | PRLogModuleInfo *next = lm->next; |
michael@0 | 298 | free((/*const*/ char *)lm->name); |
michael@0 | 299 | PR_Free(lm); |
michael@0 | 300 | lm = next; |
michael@0 | 301 | } |
michael@0 | 302 | logModules = NULL; |
michael@0 | 303 | |
michael@0 | 304 | if (_pr_logLock) { |
michael@0 | 305 | PR_DestroyLock(_pr_logLock); |
michael@0 | 306 | _pr_logLock = NULL; |
michael@0 | 307 | } |
michael@0 | 308 | } |
michael@0 | 309 | |
michael@0 | 310 | static void _PR_SetLogModuleLevel( PRLogModuleInfo *lm ) |
michael@0 | 311 | { |
michael@0 | 312 | char *ev; |
michael@0 | 313 | |
michael@0 | 314 | ev = PR_GetEnv("NSPR_LOG_MODULES"); |
michael@0 | 315 | if (ev && ev[0]) { |
michael@0 | 316 | char module[64]; /* Security-Critical: If you change this |
michael@0 | 317 | * size, you must also change the sscanf |
michael@0 | 318 | * format string to be size-1. |
michael@0 | 319 | */ |
michael@0 | 320 | PRIntn evlen = strlen(ev), pos = 0; |
michael@0 | 321 | while (pos < evlen) { |
michael@0 | 322 | PRIntn level = 1, count = 0, delta = 0; |
michael@0 | 323 | |
michael@0 | 324 | count = sscanf(&ev[pos], "%63[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-]%n:%d%n", |
michael@0 | 325 | module, &delta, &level, &delta); |
michael@0 | 326 | pos += delta; |
michael@0 | 327 | if (count == 0) break; |
michael@0 | 328 | |
michael@0 | 329 | /* |
michael@0 | 330 | ** If count == 2, then we got module and level. If count |
michael@0 | 331 | ** == 1, then level defaults to 1 (module enabled). |
michael@0 | 332 | */ |
michael@0 | 333 | if (lm != NULL) |
michael@0 | 334 | { |
michael@0 | 335 | if ((strcasecmp(module, "all") == 0) |
michael@0 | 336 | || (strcasecmp(module, lm->name) == 0)) |
michael@0 | 337 | { |
michael@0 | 338 | lm->level = (PRLogModuleLevel)level; |
michael@0 | 339 | } |
michael@0 | 340 | } |
michael@0 | 341 | count = sscanf(&ev[pos], " , %n", &delta); |
michael@0 | 342 | pos += delta; |
michael@0 | 343 | if (count == EOF) break; |
michael@0 | 344 | } |
michael@0 | 345 | } |
michael@0 | 346 | } /* end _PR_SetLogModuleLevel() */ |
michael@0 | 347 | |
michael@0 | 348 | PR_IMPLEMENT(PRLogModuleInfo*) PR_NewLogModule(const char *name) |
michael@0 | 349 | { |
michael@0 | 350 | PRLogModuleInfo *lm; |
michael@0 | 351 | |
michael@0 | 352 | if (!_pr_initialized) _PR_ImplicitInitialization(); |
michael@0 | 353 | |
michael@0 | 354 | lm = PR_NEWZAP(PRLogModuleInfo); |
michael@0 | 355 | if (lm) { |
michael@0 | 356 | lm->name = strdup(name); |
michael@0 | 357 | lm->level = PR_LOG_NONE; |
michael@0 | 358 | lm->next = logModules; |
michael@0 | 359 | logModules = lm; |
michael@0 | 360 | _PR_SetLogModuleLevel(lm); |
michael@0 | 361 | } |
michael@0 | 362 | return lm; |
michael@0 | 363 | } |
michael@0 | 364 | |
michael@0 | 365 | PR_IMPLEMENT(PRBool) PR_SetLogFile(const char *file) |
michael@0 | 366 | { |
michael@0 | 367 | #ifdef _PR_USE_STDIO_FOR_LOGGING |
michael@0 | 368 | FILE *newLogFile; |
michael@0 | 369 | |
michael@0 | 370 | #ifdef XP_PC |
michael@0 | 371 | if ( strcmp( file, "WinDebug") == 0) |
michael@0 | 372 | { |
michael@0 | 373 | newLogFile = WIN32_DEBUG_FILE; |
michael@0 | 374 | } |
michael@0 | 375 | else |
michael@0 | 376 | #endif |
michael@0 | 377 | { |
michael@0 | 378 | const char *mode = appendToLog ? "a" : "w"; |
michael@0 | 379 | newLogFile = fopen(file, mode); |
michael@0 | 380 | if (!newLogFile) |
michael@0 | 381 | return PR_FALSE; |
michael@0 | 382 | |
michael@0 | 383 | #ifndef WINCE /* _IONBF does not exist in the Windows Mobile 6 SDK. */ |
michael@0 | 384 | /* We do buffering ourselves. */ |
michael@0 | 385 | setvbuf(newLogFile, NULL, _IONBF, 0); |
michael@0 | 386 | #endif |
michael@0 | 387 | } |
michael@0 | 388 | if (logFile |
michael@0 | 389 | && logFile != stdout |
michael@0 | 390 | && logFile != stderr |
michael@0 | 391 | #ifdef XP_PC |
michael@0 | 392 | && logFile != WIN32_DEBUG_FILE |
michael@0 | 393 | #endif |
michael@0 | 394 | ) { |
michael@0 | 395 | fclose(logFile); |
michael@0 | 396 | } |
michael@0 | 397 | logFile = newLogFile; |
michael@0 | 398 | return PR_TRUE; |
michael@0 | 399 | #else |
michael@0 | 400 | PRFileDesc *newLogFile; |
michael@0 | 401 | PRIntn flags = PR_WRONLY|PR_CREATE_FILE; |
michael@0 | 402 | if (appendToLog) { |
michael@0 | 403 | flags |= PR_APPEND; |
michael@0 | 404 | } else { |
michael@0 | 405 | flags |= PR_TRUNCATE; |
michael@0 | 406 | } |
michael@0 | 407 | |
michael@0 | 408 | newLogFile = PR_Open(file, flags, 0666); |
michael@0 | 409 | if (newLogFile) { |
michael@0 | 410 | if (logFile && logFile != _pr_stdout && logFile != _pr_stderr) { |
michael@0 | 411 | PR_Close(logFile); |
michael@0 | 412 | } |
michael@0 | 413 | logFile = newLogFile; |
michael@0 | 414 | } |
michael@0 | 415 | return (PRBool) (newLogFile != 0); |
michael@0 | 416 | #endif /* _PR_USE_STDIO_FOR_LOGGING */ |
michael@0 | 417 | } |
michael@0 | 418 | |
michael@0 | 419 | PR_IMPLEMENT(void) PR_SetLogBuffering(PRIntn buffer_size) |
michael@0 | 420 | { |
michael@0 | 421 | PR_LogFlush(); |
michael@0 | 422 | |
michael@0 | 423 | if (logBuf) |
michael@0 | 424 | PR_DELETE(logBuf); |
michael@0 | 425 | |
michael@0 | 426 | if (buffer_size >= LINE_BUF_SIZE) { |
michael@0 | 427 | logp = logBuf = (char*) PR_MALLOC(buffer_size); |
michael@0 | 428 | logEndp = logp + buffer_size; |
michael@0 | 429 | } |
michael@0 | 430 | } |
michael@0 | 431 | |
michael@0 | 432 | PR_IMPLEMENT(void) PR_LogPrint(const char *fmt, ...) |
michael@0 | 433 | { |
michael@0 | 434 | va_list ap; |
michael@0 | 435 | char line[LINE_BUF_SIZE]; |
michael@0 | 436 | char *line_long = NULL; |
michael@0 | 437 | PRUint32 nb_tid = 0, nb; |
michael@0 | 438 | PRThread *me; |
michael@0 | 439 | PRExplodedTime now; |
michael@0 | 440 | |
michael@0 | 441 | if (!_pr_initialized) _PR_ImplicitInitialization(); |
michael@0 | 442 | |
michael@0 | 443 | if (!logFile) { |
michael@0 | 444 | return; |
michael@0 | 445 | } |
michael@0 | 446 | |
michael@0 | 447 | if (outputTimeStamp) { |
michael@0 | 448 | PR_ExplodeTime(PR_Now(), PR_GMTParameters, &now); |
michael@0 | 449 | nb_tid = PR_snprintf(line, sizeof(line)-1, |
michael@0 | 450 | "%04d-%02d-%02d %02d:%02d:%02d.%06d UTC - ", |
michael@0 | 451 | now.tm_year, now.tm_month + 1, now.tm_mday, |
michael@0 | 452 | now.tm_hour, now.tm_min, now.tm_sec, |
michael@0 | 453 | now.tm_usec); |
michael@0 | 454 | } |
michael@0 | 455 | |
michael@0 | 456 | me = PR_GetCurrentThread(); |
michael@0 | 457 | nb_tid += PR_snprintf(line+nb_tid, sizeof(line)-nb_tid-1, "%ld[%p]: ", |
michael@0 | 458 | #if defined(_PR_BTHREADS) |
michael@0 | 459 | me, me); |
michael@0 | 460 | #else |
michael@0 | 461 | me ? me->id : 0L, me); |
michael@0 | 462 | #endif |
michael@0 | 463 | |
michael@0 | 464 | va_start(ap, fmt); |
michael@0 | 465 | nb = nb_tid + PR_vsnprintf(line+nb_tid, sizeof(line)-nb_tid-1, fmt, ap); |
michael@0 | 466 | va_end(ap); |
michael@0 | 467 | |
michael@0 | 468 | /* |
michael@0 | 469 | * Check if we might have run out of buffer space (in case we have a |
michael@0 | 470 | * long line), and malloc a buffer just this once. |
michael@0 | 471 | */ |
michael@0 | 472 | if (nb == sizeof(line)-2) { |
michael@0 | 473 | va_start(ap, fmt); |
michael@0 | 474 | line_long = PR_vsmprintf(fmt, ap); |
michael@0 | 475 | va_end(ap); |
michael@0 | 476 | /* If this failed, we'll fall back to writing the truncated line. */ |
michael@0 | 477 | } |
michael@0 | 478 | |
michael@0 | 479 | if (line_long) { |
michael@0 | 480 | nb = strlen(line_long); |
michael@0 | 481 | _PR_LOCK_LOG(); |
michael@0 | 482 | if (logBuf != 0) { |
michael@0 | 483 | _PUT_LOG(logFile, logBuf, logp - logBuf); |
michael@0 | 484 | logp = logBuf; |
michael@0 | 485 | } |
michael@0 | 486 | /* |
michael@0 | 487 | * Write out the thread id (with an optional timestamp) and the |
michael@0 | 488 | * malloc'ed buffer. |
michael@0 | 489 | */ |
michael@0 | 490 | _PUT_LOG(logFile, line, nb_tid); |
michael@0 | 491 | _PUT_LOG(logFile, line_long, nb); |
michael@0 | 492 | /* Ensure there is a trailing newline. */ |
michael@0 | 493 | if (!nb || (line_long[nb-1] != '\n')) { |
michael@0 | 494 | char eol[2]; |
michael@0 | 495 | eol[0] = '\n'; |
michael@0 | 496 | eol[1] = '\0'; |
michael@0 | 497 | _PUT_LOG(logFile, eol, 1); |
michael@0 | 498 | } |
michael@0 | 499 | _PR_UNLOCK_LOG(); |
michael@0 | 500 | PR_smprintf_free(line_long); |
michael@0 | 501 | } else { |
michael@0 | 502 | /* Ensure there is a trailing newline. */ |
michael@0 | 503 | if (nb && (line[nb-1] != '\n')) { |
michael@0 | 504 | line[nb++] = '\n'; |
michael@0 | 505 | line[nb] = '\0'; |
michael@0 | 506 | } |
michael@0 | 507 | _PR_LOCK_LOG(); |
michael@0 | 508 | if (logBuf == 0) { |
michael@0 | 509 | _PUT_LOG(logFile, line, nb); |
michael@0 | 510 | } else { |
michael@0 | 511 | /* If nb can't fit into logBuf, write out logBuf first. */ |
michael@0 | 512 | if (logp + nb > logEndp) { |
michael@0 | 513 | _PUT_LOG(logFile, logBuf, logp - logBuf); |
michael@0 | 514 | logp = logBuf; |
michael@0 | 515 | } |
michael@0 | 516 | /* nb is guaranteed to fit into logBuf. */ |
michael@0 | 517 | memcpy(logp, line, nb); |
michael@0 | 518 | logp += nb; |
michael@0 | 519 | } |
michael@0 | 520 | _PR_UNLOCK_LOG(); |
michael@0 | 521 | } |
michael@0 | 522 | PR_LogFlush(); |
michael@0 | 523 | } |
michael@0 | 524 | |
michael@0 | 525 | PR_IMPLEMENT(void) PR_LogFlush(void) |
michael@0 | 526 | { |
michael@0 | 527 | if (logBuf && logFile) { |
michael@0 | 528 | _PR_LOCK_LOG(); |
michael@0 | 529 | if (logp > logBuf) { |
michael@0 | 530 | _PUT_LOG(logFile, logBuf, logp - logBuf); |
michael@0 | 531 | logp = logBuf; |
michael@0 | 532 | } |
michael@0 | 533 | _PR_UNLOCK_LOG(); |
michael@0 | 534 | } |
michael@0 | 535 | } |
michael@0 | 536 | |
michael@0 | 537 | PR_IMPLEMENT(void) PR_Abort(void) |
michael@0 | 538 | { |
michael@0 | 539 | PR_LogPrint("Aborting"); |
michael@0 | 540 | abort(); |
michael@0 | 541 | } |
michael@0 | 542 | |
michael@0 | 543 | PR_IMPLEMENT(void) PR_Assert(const char *s, const char *file, PRIntn ln) |
michael@0 | 544 | { |
michael@0 | 545 | PR_LogPrint("Assertion failure: %s, at %s:%d\n", s, file, ln); |
michael@0 | 546 | fprintf(stderr, "Assertion failure: %s, at %s:%d\n", s, file, ln); |
michael@0 | 547 | fflush(stderr); |
michael@0 | 548 | #ifdef WIN32 |
michael@0 | 549 | DebugBreak(); |
michael@0 | 550 | #endif |
michael@0 | 551 | #ifdef XP_OS2 |
michael@0 | 552 | asm("int $3"); |
michael@0 | 553 | #endif |
michael@0 | 554 | abort(); |
michael@0 | 555 | } |