1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is the Netscape Portable Runtime (NSPR).
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998-2000
21 * the Initial Developer. All Rights Reserved.
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
42 * This Original Code has been modified by IBM Corporation.
43 * Modifications made by IBM described herein are
44 * Copyright (c) International Business Machines Corporation, 2000.
45 * Modifications to Mozilla code or documentation identified per
48 * Date Modified by Description of modification
49 * 04/10/2000 IBM Corp. Added DebugBreak() definitions for OS/2
58 * Lock used to lock the log.
60 * We can't define _PR_LOCK_LOG simply as PR_Lock because PR_Lock may
61 * contain assertions. We have to avoid assertions in _PR_LOCK_LOG
62 * because PR_ASSERT calls PR_LogPrint, which in turn calls _PR_LOCK_LOG.
63 * This can lead to infinite recursion.
65 static PRLock
*_pr_logLock
;
66 #if defined(_PR_PTHREADS) || defined(_PR_BTHREADS)
67 #define _PR_LOCK_LOG() PR_Lock(_pr_logLock);
68 #define _PR_UNLOCK_LOG() PR_Unlock(_pr_logLock);
69 #elif defined(_PR_GLOBAL_THREADS_ONLY)
70 #define _PR_LOCK_LOG() { _PR_LOCK_LOCK(_pr_logLock)
71 #define _PR_UNLOCK_LOG() _PR_LOCK_UNLOCK(_pr_logLock); }
74 #define _PR_LOCK_LOG() \
77 PRThread *_me = _PR_MD_CURRENT_THREAD(); \
78 if (!_PR_IS_NATIVE_THREAD(_me)) \
80 _PR_LOCK_LOCK(_pr_logLock)
82 #define _PR_UNLOCK_LOG() \
83 _PR_LOCK_UNLOCK(_pr_logLock); \
84 PR_ASSERT(_me == _PR_MD_CURRENT_THREAD()); \
85 if (!_PR_IS_NATIVE_THREAD(_me)) \
92 #define strcasecmp stricmp
93 #define strncasecmp strnicmp
97 * On NT, we can't define _PUT_LOG as PR_Write or _PR_MD_WRITE,
98 * because every asynchronous file io operation leads to a fiber context
99 * switch. So we define _PUT_LOG as fputs (from stdio.h). A side
100 * benefit is that fputs handles the LF->CRLF translation. This
101 * code can also be used on other platforms with file stream io.
103 #if defined(WIN32) || defined(XP_OS2)
104 #define _PR_USE_STDIO_FOR_LOGGING
108 ** Coerce Win32 log output to use OutputDebugString() when
109 ** NSPR_LOG_FILE is set to "WinDebug".
112 #define WIN32_DEBUG_FILE (FILE*)-2
115 /* Macros used to reduce #ifdef pollution */
117 #if defined(_PR_USE_STDIO_FOR_LOGGING) && defined(XP_PC)
118 #define _PUT_LOG(fd, buf, nb) \
120 if (logFile == WIN32_DEBUG_FILE) { \
121 char savebyte = buf[nb]; \
123 OutputDebugString(buf); \
124 buf[nb] = savebyte; \
126 fwrite(buf, 1, nb, fd); \
130 #elif defined(_PR_USE_STDIO_FOR_LOGGING)
131 #define _PUT_LOG(fd, buf, nb) {fwrite(buf, 1, nb, fd); fflush(fd);}
132 #elif defined(_PR_PTHREADS)
133 #define _PUT_LOG(fd, buf, nb) PR_Write(fd, buf, nb)
134 #elif defined(XP_MAC)
135 #define _PUT_LOG(fd, buf, nb) _PR_MD_WRITE_SYNC(fd, buf, nb)
137 #define _PUT_LOG(fd, buf, nb) _PR_MD_WRITE(fd, buf, nb)
140 /************************************************************************/
142 static PRLogModuleInfo
*logModules
;
144 static char *logBuf
= NULL
;
146 static char *logEndp
;
147 #ifdef _PR_USE_STDIO_FOR_LOGGING
148 static FILE *logFile
= NULL
;
150 static PRFileDesc
*logFile
= 0;
153 #define LINE_BUF_SIZE 512
154 #define DEFAULT_BUF_SIZE 16384
156 #ifdef _PR_NEED_STRCASECMP
159 * strcasecmp is defined in /usr/ucblib/libucb.a on some platforms
160 * such as NCR and Unixware. Linking with both libc and libucb
161 * may cause some problem, so I just provide our own implementation
162 * of strcasecmp here.
165 static const unsigned char uc
[] =
167 '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
168 '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
169 '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
170 '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
171 ' ', '!', '"', '#', '$', '%', '&', '\'',
172 '(', ')', '*', '+', ',', '-', '.', '/',
173 '0', '1', '2', '3', '4', '5', '6', '7',
174 '8', '9', ':', ';', '<', '=', '>', '?',
175 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
176 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
177 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
178 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
179 '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
180 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
181 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
182 'X', 'Y', 'Z', '{', '|', '}', '~', '\177'
185 PRIntn
strcasecmp(const char *a
, const char *b
)
187 const unsigned char *ua
= (const unsigned char *)a
;
188 const unsigned char *ub
= (const unsigned char *)b
;
190 if( ((const char *)0 == a
) || (const char *)0 == b
)
191 return (PRIntn
)(a
-b
);
193 while( (uc
[*ua
] == uc
[*ub
]) && ('\0' != *a
) )
200 return (PRIntn
)(uc
[*ua
] - uc
[*ub
]);
203 #endif /* _PR_NEED_STRCASECMP */
205 void _PR_InitLog(void)
209 _pr_logLock
= PR_NewLock();
211 ev
= PR_GetEnv("NSPR_LOG_MODULES");
213 char module
[64]; /* Security-Critical: If you change this
214 * size, you must also change the sscanf
215 * format string to be size-1.
217 PRBool isSync
= PR_FALSE
;
218 PRIntn evlen
= strlen(ev
), pos
= 0;
219 PRInt32 bufSize
= DEFAULT_BUF_SIZE
;
220 while (pos
< evlen
) {
221 PRIntn level
= 1, count
= 0, delta
= 0;
222 count
= sscanf(&ev
[pos
], "%63[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-]%n:%d%n",
223 module
, &delta
, &level
, &delta
);
225 if (count
== 0) break;
228 ** If count == 2, then we got module and level. If count
229 ** == 1, then level defaults to 1 (module enabled).
231 if (strcasecmp(module
, "sync") == 0) {
233 } else if (strcasecmp(module
, "bufsize") == 0) {
234 if (level
>= LINE_BUF_SIZE
) {
238 PRLogModuleInfo
*lm
= logModules
;
239 PRBool skip_modcheck
=
240 (0 == strcasecmp (module
, "all")) ? PR_TRUE
: PR_FALSE
;
243 if (skip_modcheck
) lm
-> level
= (PRLogModuleLevel
)level
;
244 else if (strcasecmp(module
, lm
->name
) == 0) {
245 lm
->level
= (PRLogModuleLevel
)level
;
252 count
= sscanf(&ev
[pos
], " , %n", &delta
);
254 if (count
== EOF
) break;
256 PR_SetLogBuffering(isSync
? 0 : bufSize
);
259 if ((getuid() != geteuid()) || (getgid() != getegid())) {
264 ev
= PR_GetEnv("NSPR_LOG_FILE");
266 if (!PR_SetLogFile(ev
)) {
268 char* str
= PR_smprintf("Unable to create nspr log file '%s'\n", ev
);
270 OutputDebugString(str
);
271 PR_smprintf_free(str
);
274 fprintf(stderr
, "Unable to create nspr log file '%s'\n", ev
);
278 #ifdef _PR_USE_STDIO_FOR_LOGGING
281 logFile
= _pr_stderr
;
287 void _PR_LogCleanup(void)
289 PRLogModuleInfo
*lm
= logModules
;
293 #ifdef _PR_USE_STDIO_FOR_LOGGING
298 && logFile
!= WIN32_DEBUG_FILE
305 if (logFile
&& logFile
!= _pr_stdout
&& logFile
!= _pr_stderr
) {
315 PRLogModuleInfo
*next
= lm
->next
;
316 free((/*const*/ char *)lm
->name
);
323 PR_DestroyLock(_pr_logLock
);
328 static void _PR_SetLogModuleLevel( PRLogModuleInfo
*lm
)
332 ev
= PR_GetEnv("NSPR_LOG_MODULES");
334 char module
[64]; /* Security-Critical: If you change this
335 * size, you must also change the sscanf
336 * format string to be size-1.
338 PRIntn evlen
= strlen(ev
), pos
= 0;
339 while (pos
< evlen
) {
340 PRIntn level
= 1, count
= 0, delta
= 0;
342 count
= sscanf(&ev
[pos
], "%63[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-]%n:%d%n",
343 module
, &delta
, &level
, &delta
);
345 if (count
== 0) break;
348 ** If count == 2, then we got module and level. If count
349 ** == 1, then level defaults to 1 (module enabled).
353 if ((strcasecmp(module
, "all") == 0)
354 || (strcasecmp(module
, lm
->name
) == 0))
356 lm
->level
= (PRLogModuleLevel
)level
;
359 count
= sscanf(&ev
[pos
], " , %n", &delta
);
361 if (count
== EOF
) break;
364 } /* end _PR_SetLogModuleLevel() */
366 PR_IMPLEMENT(PRLogModuleInfo
*) PR_NewLogModule(const char *name
)
370 if (!_pr_initialized
) _PR_ImplicitInitialization();
372 lm
= PR_NEWZAP(PRLogModuleInfo
);
374 lm
->name
= strdup(name
);
375 lm
->level
= PR_LOG_NONE
;
376 lm
->next
= logModules
;
378 _PR_SetLogModuleLevel(lm
);
383 PR_IMPLEMENT(PRBool
) PR_SetLogFile(const char *file
)
385 #ifdef _PR_USE_STDIO_FOR_LOGGING
389 if ( strcmp( file
, "WinDebug") == 0)
391 newLogFile
= WIN32_DEBUG_FILE
;
396 newLogFile
= fopen(file
, "w");
400 /* We do buffering ourselves. */
401 setvbuf(newLogFile
, NULL
, _IONBF
, 0);
407 && logFile
!= WIN32_DEBUG_FILE
412 logFile
= newLogFile
;
415 PRFileDesc
*newLogFile
;
417 newLogFile
= PR_Open(file
, PR_WRONLY
|PR_CREATE_FILE
|PR_TRUNCATE
, 0666);
419 if (logFile
&& logFile
!= _pr_stdout
&& logFile
!= _pr_stderr
) {
422 logFile
= newLogFile
;
424 SetLogFileTypeCreator(file
);
427 return (PRBool
) (newLogFile
!= 0);
428 #endif /* _PR_USE_STDIO_FOR_LOGGING */
431 PR_IMPLEMENT(void) PR_SetLogBuffering(PRIntn buffer_size
)
438 if (buffer_size
>= LINE_BUF_SIZE
) {
439 logp
= logBuf
= (char*) PR_MALLOC(buffer_size
);
440 logEndp
= logp
+ buffer_size
;
444 PR_IMPLEMENT(void) PR_LogPrint(const char *fmt
, ...)
447 char line
[LINE_BUF_SIZE
];
448 char *line_long
= NULL
;
452 if (!_pr_initialized
) _PR_ImplicitInitialization();
458 me
= PR_GetCurrentThread();
459 nb_tid
= PR_snprintf(line
, sizeof(line
)-1, "%ld[%p]: ",
460 #if defined(_PR_DCETHREADS)
461 /* The problem is that for _PR_DCETHREADS, pthread_t is not a
462 * pointer, but a structure; so you can't easily print it...
464 me
? &(me
->id
): 0L, me
);
465 #elif defined(_PR_BTHREADS)
468 me
? me
->id
: 0L, me
);
472 nb
= nb_tid
+ PR_vsnprintf(line
+nb_tid
, sizeof(line
)-nb_tid
-1, fmt
, ap
);
476 * Check if we might have run out of buffer space (in case we have a
477 * long line), and malloc a buffer just this once.
479 if (nb
== sizeof(line
)-2) {
481 line_long
= PR_vsmprintf(fmt
, ap
);
483 /* If this failed, we'll fall back to writing the truncated line. */
487 nb
= strlen(line_long
);
490 _PUT_LOG(logFile
, logBuf
, logp
- logBuf
);
493 /* Write out the thread id and the malloc'ed buffer. */
494 _PUT_LOG(logFile
, line
, nb_tid
);
495 _PUT_LOG(logFile
, line_long
, nb
);
496 /* Ensure there is a trailing newline. */
497 if (!nb
|| (line_long
[nb
-1] != '\n')) {
501 _PUT_LOG(logFile
, eol
, 1);
504 PR_smprintf_free(line_long
);
506 /* Ensure there is a trailing newline. */
507 if (nb
&& (line
[nb
-1] != '\n')) {
513 _PUT_LOG(logFile
, line
, nb
);
515 /* If nb can't fit into logBuf, write out logBuf first. */
516 if (logp
+ nb
> logEndp
) {
517 _PUT_LOG(logFile
, logBuf
, logp
- logBuf
);
520 /* nb is guaranteed to fit into logBuf. */
521 memcpy(logp
, line
, nb
);
529 PR_IMPLEMENT(void) PR_LogFlush(void)
531 if (logBuf
&& logFile
) {
534 _PUT_LOG(logFile
, logBuf
, logp
- logBuf
);
541 PR_IMPLEMENT(void) PR_Abort(void)
543 PR_LogPrint("Aborting");
549 * Added definitions for DebugBreak() for 2 different OS/2 compilers.
550 * Doing the int3 on purpose for Visual Age so that a developer can
551 * step over the instruction if so desired. Not always possible if
552 * trapping due to exception handling IBM-AKR
554 #if defined(XP_OS2_VACPP)
556 static void DebugBreak(void) { _interrupt(3); }
557 #elif defined(XP_OS2_EMX)
558 static void DebugBreak(void) { asm("int $3"); }
560 static void DebugBreak(void) { }
564 PR_IMPLEMENT(void) PR_Assert(const char *s
, const char *file
, PRIntn ln
)
566 PR_LogPrint("Assertion failure: %s, at %s:%d\n", s
, file
, ln
);
567 #if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)
568 fprintf(stderr
, "Assertion failure: %s, at %s:%d\n", s
, file
, ln
);
571 dprintf("Assertion failure: %s, at %s:%d\n", s
, file
, ln
);
573 #if defined(WIN32) || defined(XP_OS2)
582 PR_IMPLEMENT(void) PR_Init_Log(void)