summaryrefslogtreecommitdiff
path: root/pr/src/io
diff options
context:
space:
mode:
Diffstat (limited to 'pr/src/io')
-rw-r--r--pr/src/io/Makefile.in8
-rw-r--r--pr/src/io/prdir.c50
-rw-r--r--pr/src/io/prfdcach.c4
-rw-r--r--pr/src/io/prfile.c88
-rw-r--r--pr/src/io/prio.c11
-rw-r--r--pr/src/io/priometh.c12
-rw-r--r--pr/src/io/pripv6.c64
-rw-r--r--pr/src/io/prlayer.c4
-rw-r--r--pr/src/io/prlog.c65
-rw-r--r--pr/src/io/prmapopt.c18
-rw-r--r--pr/src/io/prmwait.c39
-rw-r--r--pr/src/io/prprf.c115
-rw-r--r--pr/src/io/prsocket.c112
-rw-r--r--pr/src/io/prstdio.c38
14 files changed, 407 insertions, 221 deletions
diff --git a/pr/src/io/Makefile.in b/pr/src/io/Makefile.in
index 179656aa..e7316b38 100644
--- a/pr/src/io/Makefile.in
+++ b/pr/src/io/Makefile.in
@@ -81,5 +81,13 @@ DEFINES += -D_NSPR_BUILD_
include $(topsrcdir)/config/rules.mk
+# An OS/2 Optimization bug causes PR_snprintf() to produce wrong result.
+# This suppresses optimization for this single compilation unit.
+ifeq ($(MOZ_OS2_TOOLS),VACPP)
+$(OBJDIR)/prprf.obj: prprf.c
+ @$(MAKE_OBJDIR)
+ $(CC) -Fo$@ -c $(filter-out /O+, $(CFLAGS)) $<
+endif
+
export:: $(TARGETS)
diff --git a/pr/src/io/prdir.c b/pr/src/io/prdir.c
index d0f469e9..8aa66435 100644
--- a/pr/src/io/prdir.c
+++ b/pr/src/io/prdir.c
@@ -18,6 +18,7 @@
* Rights Reserved.
*
* Contributor(s):
+ * Roy Yokoyama <yokoyama@netscape.com>
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
@@ -109,3 +110,52 @@ PRInt32 rv;
return PR_SUCCESS;
}
+#ifdef MOZ_UNICODE
+/*
+ * UTF16 Interface
+ */
+PR_IMPLEMENT(PRDirUTF16*) PR_OpenDirUTF16(const PRUnichar *name)
+{
+ PRDirUTF16 *dir;
+ PRStatus sts;
+
+ dir = PR_NEW(PRDirUTF16);
+ if (dir) {
+ sts = _PR_MD_OPEN_DIR_UTF16(&dir->md,name);
+ if (sts != PR_SUCCESS) {
+ PR_DELETE(dir);
+ return NULL;
+ }
+ } else {
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+ }
+ return dir;
+}
+
+PR_IMPLEMENT(PRDirEntryUTF16*) PR_ReadDirUTF16(PRDirUTF16 *dir, PRDirFlags flags)
+{
+ /*
+ * _MD_READ_DIR_UTF16 return a PRUnichar* to the name; allocation in
+ * machine-dependent code
+ */
+ PRUnichar* name = _PR_MD_READ_DIR_UTF16(&dir->md, flags);
+ dir->d.name = name;
+ return name ? &dir->d : NULL;
+}
+
+PR_IMPLEMENT(PRStatus) PR_CloseDirUTF16(PRDirUTF16 *dir)
+{
+ PRInt32 rv;
+
+ if (dir) {
+ rv = _PR_MD_CLOSE_DIR_UTF16(&dir->md);
+ PR_DELETE(dir);
+ if (rv < 0)
+ return PR_FAILURE;
+ else
+ return PR_SUCCESS;
+ }
+ return PR_SUCCESS;
+}
+
+#endif /* MOZ_UNICODE */
diff --git a/pr/src/io/prfdcach.c b/pr/src/io/prfdcach.c
index 8803a419..82cbf058 100644
--- a/pr/src/io/prfdcach.c
+++ b/pr/src/io/prfdcach.c
@@ -73,7 +73,7 @@ static PRFileDesc **stack2fd = &(((PRFileDesc*)NULL)->higher);
** Get a FileDescriptor from the cache if one exists. If not allocate
** a new one from the heap.
*/
-PRFileDesc *_PR_Getfd()
+PRFileDesc *_PR_Getfd(void)
{
PRFileDesc *fd;
/*
@@ -248,7 +248,7 @@ PR_IMPLEMENT(PRStatus) PR_SetFDCacheSize(PRIntn low, PRIntn high)
return PR_SUCCESS;
} /* PR_SetFDCacheSize */
-void _PR_InitFdCache()
+void _PR_InitFdCache(void)
{
/*
** The fd caching is enabled by default for DEBUG builds,
diff --git a/pr/src/io/prfile.c b/pr/src/io/prfile.c
index e19705c7..25354453 100644
--- a/pr/src/io/prfile.c
+++ b/pr/src/io/prfile.c
@@ -203,7 +203,7 @@ static PRStatus PR_CALLBACK PipeSync(PRFileDesc *fd)
return PR_SUCCESS;
}
-static PRStatus PR_CALLBACK FileInfo(PRFileDesc *fd, PRFileInfo *info)
+static PRStatus PR_CALLBACK FileGetInfo(PRFileDesc *fd, PRFileInfo *info)
{
PRInt32 rv;
@@ -214,7 +214,7 @@ static PRStatus PR_CALLBACK FileInfo(PRFileDesc *fd, PRFileInfo *info)
return PR_SUCCESS;
}
-static PRStatus PR_CALLBACK FileInfo64(PRFileDesc *fd, PRFileInfo64 *info)
+static PRStatus PR_CALLBACK FileGetInfo64(PRFileDesc *fd, PRFileInfo64 *info)
{
#ifdef XP_MAC
#pragma unused( fd, info )
@@ -276,8 +276,8 @@ static PRIOMethods _pr_fileMethods = {
FileSync,
FileSeek,
FileSeek64,
- FileInfo,
- FileInfo64,
+ FileGetInfo,
+ FileGetInfo64,
(PRWritevFN)_PR_InvalidInt,
(PRConnectFN)_PR_InvalidStatus,
(PRAcceptFN)_PR_InvalidDesc,
@@ -422,14 +422,18 @@ PRInt32 PR_GetSysfdTableMax(void)
return rlim.rlim_max;
#elif defined(AIX) || defined(NEXTSTEP) || defined(QNX)
return sysconf(_SC_OPEN_MAX);
-#elif defined(WIN32) || defined(OS2)
+#elif defined(WIN32)
/*
* There is a systemwide limit of 65536 user handles.
- * Not sure on OS/2, but sounds good.
*/
return 16384;
#elif defined (WIN16)
return FOPEN_MAX;
+#elif defined(XP_OS2)
+ ULONG ulReqCount = 0;
+ ULONG ulCurMaxFH = 0;
+ DosSetRelMaxFH(&ulReqCount, &ulCurMaxFH);
+ return ulCurMaxFH;
#elif defined (XP_MAC) || defined(XP_BEOS)
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
return -1;
@@ -464,9 +468,19 @@ PRInt32 PR_SetSysfdTableSize(int table_size)
}
return rlim.rlim_cur;
+#elif defined(XP_OS2)
+ PRInt32 tableMax = PR_GetSysfdTableMax();
+ if (table_size > tableMax) {
+ APIRET rc = NO_ERROR;
+ rc = DosSetMaxFH(table_size);
+ if (rc == NO_ERROR)
+ return table_size;
+ else
+ return -1;
+ }
+ return tableMax;
#elif defined(AIX) || defined(NEXTSTEP) || defined(QNX) \
- || defined(WIN32) || defined(WIN16) || defined(OS2) \
- || defined(XP_BEOS)
+ || defined(WIN32) || defined(WIN16) || defined(XP_BEOS)
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
return -1;
#elif defined (XP_MAC)
@@ -735,7 +749,7 @@ PR_IMPLEMENT(PRStatus) PR_CreatePipe(
(*readPipe)->secret->inheritable = _PR_TRI_TRUE;
(*writePipe)->secret->inheritable = _PR_TRI_TRUE;
return PR_SUCCESS;
-#elif defined(XP_UNIX) || defined(XP_OS2)
+#elif defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)
#ifdef XP_OS2
HFILE pipefd[2];
#else
@@ -765,9 +779,13 @@ PR_IMPLEMENT(PRStatus) PR_CreatePipe(
close(pipefd[1]);
return PR_FAILURE;
}
- _MD_MakeNonblock(*readPipe);
+#ifndef XP_BEOS /* Pipes are nonblocking on BeOS */
+ _PR_MD_MAKE_NONBLOCK(*readPipe);
+#endif
_PR_MD_INIT_FD_INHERITABLE(*readPipe, PR_FALSE);
- _MD_MakeNonblock(*writePipe);
+#ifndef XP_BEOS /* Pipes are nonblocking on BeOS */
+ _PR_MD_MAKE_NONBLOCK(*writePipe);
+#endif
_PR_MD_INIT_FD_INHERITABLE(*writePipe, PR_FALSE);
return PR_SUCCESS;
#else
@@ -775,3 +793,51 @@ PR_IMPLEMENT(PRStatus) PR_CreatePipe(
return PR_FAILURE;
#endif
}
+
+#ifdef MOZ_UNICODE
+/* ================ UTF16 Interfaces ================================ */
+PR_IMPLEMENT(PRFileDesc*) PR_OpenFileUTF16(
+ const PRUnichar *name, PRIntn flags, PRIntn mode)
+{
+ PRInt32 osfd;
+ PRFileDesc *fd = 0;
+#if !defined(XP_UNIX) /* BugZilla: 4090 */
+ PRBool appendMode = ( PR_APPEND & flags )? PR_TRUE : PR_FALSE;
+#endif
+
+ if (!_pr_initialized) _PR_ImplicitInitialization();
+
+ /* Map pr open flags and mode to os specific flags */
+ osfd = _PR_MD_OPEN_FILE_UTF16(name, flags, mode);
+ if (osfd != -1) {
+ fd = PR_AllocFileDesc(osfd, &_pr_fileMethods);
+ if (!fd) {
+ (void) _PR_MD_CLOSE_FILE(osfd);
+ } else {
+#if !defined(XP_UNIX) /* BugZilla: 4090 */
+ fd->secret->appendMode = appendMode;
+#endif
+ _PR_MD_INIT_FD_INHERITABLE(fd, PR_FALSE);
+ }
+ }
+ return fd;
+}
+
+PR_IMPLEMENT(PRStatus) PR_GetFileInfo64UTF16(const PRUnichar *fn, PRFileInfo64 *info)
+{
+#ifdef XP_MAC
+#pragma unused (fn, info)
+#endif
+ PRInt32 rv;
+
+ if (!_pr_initialized) _PR_ImplicitInitialization();
+ rv = _PR_MD_GETFILEINFO64_UTF16(fn, info);
+ if (rv < 0) {
+ return PR_FAILURE;
+ } else {
+ return PR_SUCCESS;
+ }
+}
+
+/* ================ UTF16 Interfaces ================================ */
+#endif /* MOZ_UNICODE */
diff --git a/pr/src/io/prio.c b/pr/src/io/prio.c
index 250d9b6f..66ecd7cc 100644
--- a/pr/src/io/prio.c
+++ b/pr/src/io/prio.c
@@ -164,7 +164,7 @@ PR_IMPLEMENT(PRStatus) PR_SetFDInheritable(
PRFileDesc *fd,
PRBool inheritable)
{
-#if defined(XP_UNIX) || defined(WIN32) || defined(XP_OS2)
+#if defined(XP_UNIX) || defined(WIN32) || defined(XP_OS2) || defined(XP_BEOS)
/*
* Only a non-layered, NSPR file descriptor can be inherited
* by a child process.
@@ -188,3 +188,12 @@ PR_IMPLEMENT(PRStatus) PR_SetFDInheritable(
return PR_FAILURE;
#endif
}
+
+/*
+** This function only has a useful implementation in the debug build of
+** the pthreads version.
+*/
+PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc *debug_out, const char *msg)
+{
+ /* do nothing */
+} /* PT_FPrintStats */
diff --git a/pr/src/io/priometh.c b/pr/src/io/priometh.c
index a2b8e9c8..251d46a9 100644
--- a/pr/src/io/priometh.c
+++ b/pr/src/io/priometh.c
@@ -34,6 +34,8 @@
*/
#include "primpl.h"
+#include <string.h>
+
/*****************************************************************************/
/************************** Invalid I/O method object ************************/
/*****************************************************************************/
@@ -76,21 +78,21 @@ PRIOMethods _pr_faulty_methods = {
(PRReservedFN)_PR_InvalidInt
};
-PRIntn _PR_InvalidInt()
+PRIntn _PR_InvalidInt(void)
{
PR_ASSERT(!"I/O method is invalid");
PR_SetError(PR_INVALID_METHOD_ERROR, 0);
return -1;
} /* _PR_InvalidInt */
-PRInt16 _PR_InvalidInt16()
+PRInt16 _PR_InvalidInt16(void)
{
PR_ASSERT(!"I/O method is invalid");
PR_SetError(PR_INVALID_METHOD_ERROR, 0);
return -1;
} /* _PR_InvalidInt */
-PRInt64 _PR_InvalidInt64()
+PRInt64 _PR_InvalidInt64(void)
{
PRInt64 rv;
LL_I2L(rv, -1);
@@ -103,7 +105,7 @@ PRInt64 _PR_InvalidInt64()
* An invalid method that returns PRStatus
*/
-PRStatus _PR_InvalidStatus()
+PRStatus _PR_InvalidStatus(void)
{
PR_ASSERT(!"I/O method is invalid");
PR_SetError(PR_INVALID_METHOD_ERROR, 0);
@@ -114,7 +116,7 @@ PRStatus _PR_InvalidStatus()
* An invalid method that returns a pointer
*/
-PRFileDesc *_PR_InvalidDesc()
+PRFileDesc *_PR_InvalidDesc(void)
{
PR_ASSERT(!"I/O method is invalid");
PR_SetError(PR_INVALID_METHOD_ERROR, 0);
diff --git a/pr/src/io/pripv6.c b/pr/src/io/pripv6.c
index fd104677..a5c2360f 100644
--- a/pr/src/io/pripv6.c
+++ b/pr/src/io/pripv6.c
@@ -276,51 +276,41 @@ static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketRecvFrom(PRFileDesc *fd, void *buf,
#if defined(_PR_INET6_PROBE)
PRBool _pr_ipv6_is_present;
-PR_EXTERN(PRBool) _pr_test_ipv6_socket();
-#if defined(_PR_HAVE_GETIPNODEBYNAME)
-void *_pr_getipnodebyname_fp;
-void *_pr_getipnodebyaddr_fp;
-void *_pr_freehostent_fp;
+extern PRBool _pr_test_ipv6_socket(void);
+
+#if !defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
+extern PRStatus _pr_find_getipnodebyname(void);
+#endif
+
+#if !defined(_PR_INET6) && defined(_PR_HAVE_GETADDRINFO)
+extern PRStatus _pr_find_getaddrinfo(void);
#endif
+
+static PRBool
+_pr_probe_ipv6_presence(void)
+{
+#if !defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
+ if (_pr_find_getipnodebyname() != PR_SUCCESS)
+ return PR_FALSE;
#endif
+#if !defined(_PR_INET6) && defined(_PR_HAVE_GETADDRINFO)
+ if (_pr_find_getaddrinfo() != PR_SUCCESS)
+ return PR_FALSE;
+#endif
+
+ return _pr_test_ipv6_socket();
+}
+#endif /* _PR_INET6_PROBE */
+
PRStatus _pr_init_ipv6()
{
const PRIOMethods *stubMethods;
#if defined(_PR_INET6_PROBE)
-
-#if !defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
- PRLibrary *lib;
-#if defined(VMS)
-#define GETIPNODEBYNAME getenv("GETIPNODEBYNAME")
-#define GETIPNODEBYADDR getenv("GETIPNODEBYADDR")
-#define FREEHOSTENT getenv("FREEHOSTENT")
-#else
-#define GETIPNODEBYNAME "getipnodebyname"
-#define GETIPNODEBYADDR "getipnodebyaddr"
-#define FREEHOSTENT "freehostent"
-#endif
- _pr_getipnodebyname_fp = PR_FindSymbolAndLibrary(GETIPNODEBYNAME, &lib);
- if (NULL != _pr_getipnodebyname_fp) {
- _pr_freehostent_fp = PR_FindSymbol(lib, FREEHOSTENT);
- if (NULL != _pr_freehostent_fp) {
- _pr_getipnodebyaddr_fp = PR_FindSymbol(lib, GETIPNODEBYADDR);
- if (NULL != _pr_getipnodebyaddr_fp)
- _pr_ipv6_is_present = PR_TRUE;
- else
- _pr_ipv6_is_present = PR_FALSE;
- } else
- _pr_ipv6_is_present = PR_FALSE;
- (void)PR_UnloadLibrary(lib);
- } else
- _pr_ipv6_is_present = PR_FALSE;
- if (PR_TRUE == _pr_ipv6_is_present)
-#endif
-
- _pr_ipv6_is_present = _pr_test_ipv6_socket();
- if (PR_TRUE == _pr_ipv6_is_present)
- return PR_SUCCESS;
+ _pr_ipv6_is_present = _pr_probe_ipv6_presence();
+ if (PR_TRUE == _pr_ipv6_is_present)
+ return PR_SUCCESS;
#endif
_pr_ipv6_to_ipv4_id = PR_GetUniqueIdentity("Ipv6_to_Ipv4 layer");
diff --git a/pr/src/io/prlayer.c b/pr/src/io/prlayer.c
index d74fa8be..d377f546 100644
--- a/pr/src/io/prlayer.c
+++ b/pr/src/io/prlayer.c
@@ -459,7 +459,7 @@ static PRIOMethods pl_methods = {
(PRReservedFN)_PR_InvalidInt
};
-PR_IMPLEMENT(const PRIOMethods*) PR_GetDefaultIOMethods()
+PR_IMPLEMENT(const PRIOMethods*) PR_GetDefaultIOMethods(void)
{
return &pl_methods;
} /* PR_GetDefaultIOMethods */
@@ -736,7 +736,7 @@ PR_IMPLEMENT(PRFileDesc*) PR_GetIdentitiesLayer(PRFileDesc* fd, PRDescIdentity i
return NULL;
} /* PR_GetIdentitiesLayer */
-void _PR_InitLayerCache()
+void _PR_InitLayerCache(void)
{
memset(&identity_cache, 0, sizeof(identity_cache));
identity_cache.ml = PR_NewLock();
diff --git a/pr/src/io/prlog.c b/pr/src/io/prlog.c
index 16f68823..b73543f8 100644
--- a/pr/src/io/prlog.c
+++ b/pr/src/io/prlog.c
@@ -194,13 +194,16 @@ void _PR_InitLog(void)
ev = PR_GetEnv("NSPR_LOG_MODULES");
if (ev && ev[0]) {
- char module[64];
+ char module[64]; /* Security-Critical: If you change this
+ * size, you must also change the sscanf
+ * format string to be size-1.
+ */
PRBool isSync = PR_FALSE;
PRIntn evlen = strlen(ev), pos = 0;
PRInt32 bufSize = DEFAULT_BUF_SIZE;
while (pos < evlen) {
PRIntn level = 1, count = 0, delta = 0;
- count = sscanf(&ev[pos], "%64[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789]%n:%d%n",
+ count = sscanf(&ev[pos], "%63[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789]%n:%d%n",
module, &delta, &level, &delta);
pos += delta;
if (count == 0) break;
@@ -232,7 +235,7 @@ void _PR_InitLog(void)
/*found:*/
count = sscanf(&ev[pos], " , %n", &delta);
pos += delta;
- if (count == -1) break;
+ if (count == EOF) break;
}
PR_SetLogBuffering(isSync ? bufSize : 0);
@@ -266,7 +269,13 @@ void _PR_LogCleanup(void)
PR_LogFlush();
#ifdef _PR_USE_STDIO_FOR_LOGGING
- if (logFile && logFile != stdout && logFile != stderr) {
+ if (logFile
+ && logFile != stdout
+ && logFile != stderr
+#ifdef XP_PC
+ && logFile != WIN32_DEBUG_FILE
+#endif
+ ) {
fclose(logFile);
}
#else
@@ -277,11 +286,16 @@ void _PR_LogCleanup(void)
while (lm != NULL) {
PRLogModuleInfo *next = lm->next;
- PR_Free((/*const*/ char *)lm->name);
+ free((/*const*/ char *)lm->name);
PR_Free(lm);
lm = next;
}
logModules = NULL;
+
+ if (_pr_logLock) {
+ PR_DestroyLock(_pr_logLock);
+ _pr_logLock = NULL;
+ }
}
static void _PR_SetLogModuleLevel( PRLogModuleInfo *lm )
@@ -290,12 +304,15 @@ static void _PR_SetLogModuleLevel( PRLogModuleInfo *lm )
ev = PR_GetEnv("NSPR_LOG_MODULES");
if (ev && ev[0]) {
- char module[64];
+ char module[64]; /* Security-Critical: If you change this
+ * size, you must also change the sscanf
+ * format string to be size-1.
+ */
PRIntn evlen = strlen(ev), pos = 0;
while (pos < evlen) {
PRIntn level = 1, count = 0, delta = 0;
- count = sscanf(&ev[pos], "%64[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789]%n:%d%n",
+ count = sscanf(&ev[pos], "%63[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789]%n:%d%n",
module, &delta, &level, &delta);
pos += delta;
if (count == 0) break;
@@ -314,7 +331,7 @@ static void _PR_SetLogModuleLevel( PRLogModuleInfo *lm )
}
count = sscanf(&ev[pos], " , %n", &delta);
pos += delta;
- if (count == -1) break;
+ if (count == EOF) break;
}
}
} /* end _PR_SetLogModuleLevel() */
@@ -344,24 +361,33 @@ PR_IMPLEMENT(PRBool) PR_SetLogFile(const char *file)
#ifdef XP_PC
if ( strcmp( file, "WinDebug") == 0)
{
- logFile = WIN32_DEBUG_FILE;
- return(PR_TRUE);
+ newLogFile = WIN32_DEBUG_FILE;
}
+ else
#endif
- newLogFile = fopen(file, "w");
- if (newLogFile) {
+ {
+ newLogFile = fopen(file, "w");
+ if (!newLogFile)
+ return PR_FALSE;
+
/* We do buffering ourselves. */
setvbuf(newLogFile, NULL, _IONBF, 0);
- if (logFile && logFile != stdout && logFile != stderr) {
- fclose(logFile);
- }
- logFile = newLogFile;
}
- return (PRBool) (newLogFile != 0);
+ if (logFile
+ && logFile != stdout
+ && logFile != stderr
+#ifdef XP_PC
+ && logFile != WIN32_DEBUG_FILE
+#endif
+ ) {
+ fclose(logFile);
+ }
+ logFile = newLogFile;
+ return PR_TRUE;
#else
PRFileDesc *newLogFile;
- newLogFile = PR_Open(file, PR_WRONLY|PR_CREATE_FILE, 0666);
+ newLogFile = PR_Open(file, PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE, 0666);
if (newLogFile) {
if (logFile && logFile != _pr_stdout && logFile != _pr_stderr) {
PR_Close(logFile);
@@ -482,8 +508,7 @@ PR_IMPLEMENT(void) PR_Abort(void)
#include <builtin.h>
static void DebugBreak(void) { _interrupt(3); }
#elif defined(XP_OS2_EMX)
-/* Force a trap */
-static void DebugBreak(void) { int *pTrap=NULL; *pTrap = 1; }
+static void DebugBreak(void) { asm("int $3"); }
#else
static void DebugBreak(void) { }
#endif
diff --git a/pr/src/io/prmapopt.c b/pr/src/io/prmapopt.c
index f017c36a..2e6d219a 100644
--- a/pr/src/io/prmapopt.c
+++ b/pr/src/io/prmapopt.c
@@ -46,10 +46,20 @@
* includes winsock.h, with _WIN32_WINNT undefined.
*/
-#ifdef WINNT
+#if defined(WINNT) || defined(__MINGW32__)
#include <winsock.h>
#endif
+/* MinGW doesn't define these in its winsock.h. */
+#ifdef __MINGW32__
+#ifndef IP_TTL
+#define IP_TTL 7
+#endif
+#ifndef IP_TOS
+#define IP_TOS 8
+#endif
+#endif
+
#include "primpl.h"
#if defined(NEXTSTEP)
@@ -57,7 +67,7 @@
#include <netinet/in_systm.h> /* n_short, n_long, n_time */
#endif
-#if defined(XP_UNIX) || defined(OS2)
+#if defined(XP_UNIX) || defined(OS2) || (defined(XP_BEOS) && defined(BONE_VERSION))
#include <netinet/tcp.h> /* TCP_NODELAY, TCP_MAXSEG */
#endif
@@ -86,7 +96,7 @@ PRStatus PR_CALLBACK _PR_SocketGetSocketOption(PRFileDesc *fd, PRSocketOptionDat
{
case PR_SockOpt_Linger:
{
-#if !defined(XP_BEOS)
+#if !defined(XP_BEOS) || defined(BONE_VERSION)
struct linger linger;
length = sizeof(linger);
rv = _PR_MD_GETSOCKOPT(
@@ -244,7 +254,7 @@ PRStatus PR_CALLBACK _PR_SocketSetSocketOption(PRFileDesc *fd, const PRSocketOpt
{
case PR_SockOpt_Linger:
{
-#if !defined(XP_BEOS)
+#if !defined(XP_BEOS) || defined(BONE_VERSION)
struct linger linger;
linger.l_onoff = data->value.linger.polarity;
linger.l_linger = PR_IntervalToSeconds(data->value.linger.linger);
diff --git a/pr/src/io/prmwait.c b/pr/src/io/prmwait.c
index a48fbc19..65ea1cd6 100644
--- a/pr/src/io/prmwait.c
+++ b/pr/src/io/prmwait.c
@@ -58,19 +58,8 @@ typedef struct TimerEvent {
struct {
PRLock *ml;
PRCondVar *new_timer;
- PRCondVar *cancel_timer; /* The cancel_timer condition variable is
- * used to cancel a timer (i.e., remove a
- * timer event from the timer queue). At
- * startup I'm borrowing this condition
- * variable for a different purpose (to
- * tell the primordial thread that the
- * timer manager thread has started) so
- * that I don't need to create a new
- * condition variable just for this one
- * time use.
- */
+ PRCondVar *cancel_timer;
PRThread *manager_thread;
- PRBool manager_started;
PRCList timer_queue;
} tm_vars;
@@ -88,11 +77,6 @@ static void TimerManager(void *arg)
TimerEvent *timer;
PR_Lock(tm_vars.ml);
- /* tell the primordial thread that we have started */
- tm_vars.manager_started = PR_TRUE;
- if (!_native_threads_only) {
- PR_NotifyCondVar(tm_vars.cancel_timer);
- }
while (1)
{
if (PR_CLIST_IS_EMPTY(&tm_vars.timer_queue))
@@ -216,16 +200,6 @@ static PRStatus TimerInit(void)
{
goto failed;
}
- /*
- * Need to wait until the timer manager thread starts
- * if the timer manager thread is a local thread.
- */
- if (!_native_threads_only) {
- PR_Lock(tm_vars.ml);
- while (!tm_vars.manager_started)
- PR_WaitCondVar(tm_vars.cancel_timer, PR_INTERVAL_NO_TIMEOUT);
- PR_Unlock(tm_vars.ml);
- }
return PR_SUCCESS;
failed:
@@ -269,6 +243,17 @@ void _PR_InitMW(void)
max_polling_interval = PR_MillisecondsToInterval(MAX_POLLING_INTERVAL);
} /* _PR_InitMW */
+void _PR_CleanupMW(void)
+{
+ PR_DestroyLock(mw_lock);
+ mw_lock = NULL;
+ if (mw_state->group) {
+ PR_DestroyWaitGroup(mw_state->group);
+ /* mw_state->group is set to NULL as a side effect. */
+ }
+ PR_DELETE(mw_state);
+} /* _PR_CleanupMW */
+
static PRWaitGroup *MW_Init2(void)
{
PRWaitGroup *group = mw_state->group; /* it's the null group */
diff --git a/pr/src/io/prprf.c b/pr/src/io/prprf.c
index 2d6a78d8..5f4de6f4 100644
--- a/pr/src/io/prprf.c
+++ b/pr/src/io/prprf.c
@@ -51,8 +51,12 @@
** Note: on some platforms va_list is defined as an array,
** and requires array notation.
*/
-#if (defined(LINUX) && defined(__powerpc__)) || defined(WIN16) || \
- defined(QNX) || \
+#if (defined(LINUX) && defined(__x86_64__))
+#define VARARGS_ASSIGN(foo, bar) __va_copy((foo), (bar))
+#elif (defined(LINUX) && defined(__powerpc__)) || \
+ (defined(LINUX) && defined(__s390__)) || \
+ (defined(LINUX) && defined(__s390x__)) || \
+ defined(WIN16) || defined(QNX) || \
(defined(__NetBSD__) && defined(__powerpc__) && \
__NetBSD_Version__ < 105000000)
#define VARARGS_ASSIGN(foo, bar) foo[0] = bar[0]
@@ -89,9 +93,6 @@ struct NumArgState{
va_list ap; /* point to the corresponding position on ap */
};
-static PRBool l10n_debug_init = PR_FALSE;
-static PRBool l10n_debug = PR_FALSE;
-
#define NAS_DEFAULT_NUM 20 /* default number of NumberedArgumentState array */
@@ -108,11 +109,11 @@ static PRBool l10n_debug = PR_FALSE;
#define TYPE_INTSTR 10
#define TYPE_UNKNOWN 20
-#define _LEFT 0x1
-#define _SIGNED 0x2
-#define _SPACED 0x4
-#define _ZEROS 0x8
-#define _NEG 0x10
+#define FLAG_LEFT 0x1
+#define FLAG_SIGNED 0x2
+#define FLAG_SPACED 0x4
+#define FLAG_ZEROS 0x8
+#define FLAG_NEG 0x10
/*
** Fill into the buffer using the data in src
@@ -124,8 +125,8 @@ static int fill2(SprintfState *ss, const char *src, int srclen, int width,
int rv;
width -= srclen;
- if ((width > 0) && ((flags & _LEFT) == 0)) { /* Right adjusting */
- if (flags & _ZEROS) {
+ if ((width > 0) && ((flags & FLAG_LEFT) == 0)) { /* Right adjusting */
+ if (flags & FLAG_ZEROS) {
space = '0';
}
while (--width >= 0) {
@@ -142,7 +143,7 @@ static int fill2(SprintfState *ss, const char *src, int srclen, int width,
return rv;
}
- if ((width > 0) && ((flags & _LEFT) != 0)) { /* Left adjusting */
+ if ((width > 0) && ((flags & FLAG_LEFT) != 0)) { /* Left adjusting */
while (--width >= 0) {
rv = (*ss->stuff)(ss, &space, 1);
if (rv < 0) {
@@ -169,13 +170,13 @@ static int fill_n(SprintfState *ss, const char *src, int srclen, int width,
char sign;
if ((type & 1) == 0) {
- if (flags & _NEG) {
+ if (flags & FLAG_NEG) {
sign = '-';
signwidth = 1;
- } else if (flags & _SIGNED) {
+ } else if (flags & FLAG_SIGNED) {
sign = '+';
signwidth = 1;
- } else if (flags & _SPACED) {
+ } else if (flags & FLAG_SPACED) {
sign = ' ';
signwidth = 1;
}
@@ -189,14 +190,14 @@ static int fill_n(SprintfState *ss, const char *src, int srclen, int width,
}
}
- if ((flags & _ZEROS) && (prec < 0)) {
+ if ((flags & FLAG_ZEROS) && (prec < 0)) {
if (width > cvtwidth) {
zerowidth = width - cvtwidth; /* Zero filling */
cvtwidth += zerowidth;
}
}
- if (flags & _LEFT) {
+ if (flags & FLAG_LEFT) {
if (width > cvtwidth) {
/* Space filling on the right (i.e. left adjusting) */
rightspaces = width - cvtwidth;
@@ -412,20 +413,6 @@ static struct NumArgState* BuildArgArray( const char *fmt, va_list ap, int* rv,
/*
- ** set the l10n_debug flag
- ** this routine should be executed only once
- ** 'cause getenv does take time
- */
- if( !l10n_debug_init ){
- l10n_debug_init = PR_TRUE;
- p = getenv( "NETSCAPE_LOCALIZATION_DEBUG" );
- if( ( p != NULL ) && ( *p == '1' ) ){
- l10n_debug = PR_TRUE;
- }
- }
-
-
- /*
** first pass:
** detemine how many legal % I have got, then allocate space
*/
@@ -444,23 +431,17 @@ static struct NumArgState* BuildArgArray( const char *fmt, va_list ap, int* rv,
if( c == '$' ){ /* numbered argument csae */
if( i > 0 ){
*rv = -1;
- if( l10n_debug )
- printf( "either no *OR* all arguments are numbered \"%s\"\n", fmt );
return NULL;
}
number++;
- break;
-
} else{ /* non-numbered argument case */
if( number > 0 ){
- if( l10n_debug )
- printf( "either no *OR* all arguments are numbered \"%s\"\n", fmt );
*rv = -1;
return NULL;
}
i = 1;
- break;
}
+ break;
}
c = *p++;
@@ -476,8 +457,6 @@ static struct NumArgState* BuildArgArray( const char *fmt, va_list ap, int* rv,
nas = (struct NumArgState*)PR_MALLOC( number * sizeof( struct NumArgState ) );
if( !nas ){
*rv = -1;
- if( l10n_debug )
- printf( "PR_MALLOC() error for \"%s\"\n", fmt );
return NULL;
}
} else {
@@ -508,8 +487,6 @@ static struct NumArgState* BuildArgArray( const char *fmt, va_list ap, int* rv,
if( !c || cn < 1 || cn > number ){
*rv = -1;
- if( l10n_debug )
- printf( "invalid argument number (valid range [1, %d]), \"%s\"\n", number, fmt );
break;
}
@@ -524,13 +501,11 @@ static struct NumArgState* BuildArgArray( const char *fmt, va_list ap, int* rv,
if (c == '*') {
/* not supported feature, for the argument is not numbered */
*rv = -1;
- if( l10n_debug )
- printf( "* width specifier not support for numbered arguments \"%s\"\n", fmt );
break;
- } else {
- while ((c >= '0') && (c <= '9')) {
- c = *p++;
- }
+ }
+
+ while ((c >= '0') && (c <= '9')) {
+ c = *p++;
}
/* precision */
@@ -538,14 +513,12 @@ static struct NumArgState* BuildArgArray( const char *fmt, va_list ap, int* rv,
c = *p++;
if (c == '*') {
/* not supported feature, for the argument is not numbered */
- if( l10n_debug )
- printf( "* precision specifier not support for numbered arguments \"%s\"\n", fmt );
*rv = -1;
break;
- } else {
- while ((c >= '0') && (c <= '9')) {
- c = *p++;
- }
+ }
+
+ while ((c >= '0') && (c <= '9')) {
+ c = *p++;
}
}
@@ -622,8 +595,6 @@ static struct NumArgState* BuildArgArray( const char *fmt, va_list ap, int* rv,
/* get a legal para. */
if( nas[ cn ].type == TYPE_UNKNOWN ){
- if( l10n_debug )
- printf( "unknown type \"%s\"\n", fmt );
*rv = -1;
break;
}
@@ -757,8 +728,6 @@ static int dosprintf(SprintfState *ss, const char *fmt, va_list ap)
}
if( nas[i-1].type == TYPE_UNKNOWN ){
- if( l10n_debug )
- printf( "numbered argument type unknown\n" );
if( nas && ( nas != nasArray ) )
PR_DELETE( nas );
return -1;
@@ -777,14 +746,14 @@ static int dosprintf(SprintfState *ss, const char *fmt, va_list ap)
* on this feature.
*/
while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) {
- if (c == '-') flags |= _LEFT;
- if (c == '+') flags |= _SIGNED;
- if (c == ' ') flags |= _SPACED;
- if (c == '0') flags |= _ZEROS;
+ if (c == '-') flags |= FLAG_LEFT;
+ if (c == '+') flags |= FLAG_SIGNED;
+ if (c == ' ') flags |= FLAG_SPACED;
+ if (c == '0') flags |= FLAG_ZEROS;
c = *fmt++;
}
- if (flags & _SIGNED) flags &= ~_SPACED;
- if (flags & _LEFT) flags &= ~_ZEROS;
+ if (flags & FLAG_SIGNED) flags &= ~FLAG_SPACED;
+ if (flags & FLAG_LEFT) flags &= ~FLAG_ZEROS;
/* width */
if (c == '*') {
@@ -866,7 +835,7 @@ static int dosprintf(SprintfState *ss, const char *fmt, va_list ap)
u.l = va_arg(ap, int);
if (u.l < 0) {
u.l = -u.l;
- flags |= _NEG;
+ flags |= FLAG_NEG;
}
goto do_long;
case TYPE_UINT16:
@@ -876,7 +845,7 @@ static int dosprintf(SprintfState *ss, const char *fmt, va_list ap)
u.l = va_arg(ap, int);
if (u.l < 0) {
u.l = -u.l;
- flags |= _NEG;
+ flags |= FLAG_NEG;
}
goto do_long;
case TYPE_UINTN:
@@ -887,7 +856,7 @@ static int dosprintf(SprintfState *ss, const char *fmt, va_list ap)
u.l = va_arg(ap, PRInt32);
if (u.l < 0) {
u.l = -u.l;
- flags |= _NEG;
+ flags |= FLAG_NEG;
}
goto do_long;
case TYPE_UINT32:
@@ -903,7 +872,7 @@ static int dosprintf(SprintfState *ss, const char *fmt, va_list ap)
u.ll = va_arg(ap, PRInt64);
if (!LL_GE_ZERO(u.ll)) {
LL_NEG(u.ll, u.ll);
- flags |= _NEG;
+ flags |= FLAG_NEG;
}
goto do_longlong;
case TYPE_UINT64:
@@ -939,7 +908,7 @@ static int dosprintf(SprintfState *ss, const char *fmt, va_list ap)
case 'c':
u.ch = va_arg(ap, int);
- if ((flags & _LEFT) == 0) {
+ if ((flags & FLAG_LEFT) == 0) {
while (width-- > 1) {
rv = (*ss->stuff)(ss, " ", 1);
if (rv < 0) {
@@ -951,7 +920,7 @@ static int dosprintf(SprintfState *ss, const char *fmt, va_list ap)
if (rv < 0) {
return rv;
}
- if (flags & _LEFT) {
+ if (flags & FLAG_LEFT) {
while (width-- > 1) {
rv = (*ss->stuff)(ss, " ", 1);
if (rv < 0) {
@@ -1044,7 +1013,7 @@ PR_IMPLEMENT(PRUint32) PR_sxprintf(PRStuffFunc func, void *arg,
const char *fmt, ...)
{
va_list ap;
- int rv;
+ PRUint32 rv;
va_start(ap, fmt);
rv = PR_vsxprintf(func, arg, fmt, ap);
@@ -1168,7 +1137,7 @@ static int LimitStuff(SprintfState *ss, const char *sp, PRUint32 len)
PR_IMPLEMENT(PRUint32) PR_snprintf(char *out, PRUint32 outlen, const char *fmt, ...)
{
va_list ap;
- int rv;
+ PRUint32 rv;
PR_ASSERT((PRInt32)outlen > 0);
if ((PRInt32)outlen <= 0) {
diff --git a/pr/src/io/prsocket.c b/pr/src/io/prsocket.c
index 2483f963..999fc03d 100644
--- a/pr/src/io/prsocket.c
+++ b/pr/src/io/prsocket.c
@@ -44,7 +44,7 @@
PRBool IsValidNetAddr(const PRNetAddr *addr)
{
if ((addr != NULL)
-#ifdef XP_UNIX
+#if defined(XP_UNIX) || defined(XP_OS2)
&& (addr->raw.family != PR_AF_LOCAL)
#endif
&& (addr->raw.family != PR_AF_INET6)
@@ -61,7 +61,7 @@ static PRBool IsValidNetAddrLen(const PRNetAddr *addr, PRInt32 addr_len)
* is not uniform, so we don't check it.
*/
if ((addr != NULL)
-#ifdef XP_UNIX
+#if defined(XP_UNIX) || defined(XP_OS2)
&& (addr->raw.family != AF_UNIX)
#endif
&& (PR_NETADDR_SIZE(addr) != addr_len)) {
@@ -338,27 +338,16 @@ static PRStatus PR_CALLBACK SocketConnectContinue(
#elif defined(XP_OS2)
- if (out_flags & PR_POLL_EXCEPT) {
- int len = sizeof(err);
- if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, (char *) &err, &len)
- < 0) {
- _PR_MD_MAP_GETSOCKOPT_ERROR(sock_errno());
- return PR_FAILURE;
- }
- if (err != 0) {
- _PR_MD_MAP_CONNECT_ERROR(err);
- } else {
- PR_SetError(PR_UNKNOWN_ERROR, 0);
- }
+ err = _MD_os2_get_nonblocking_connect_error(osfd);
+ if (err != 0) {
+ _PR_MD_MAP_CONNECT_ERROR(err);
return PR_FAILURE;
}
-
- PR_ASSERT(out_flags & PR_POLL_WRITE);
return PR_SUCCESS;
#elif defined(XP_MAC)
- err = _MD_mac_get_nonblocking_connect_error(osfd);
+ err = _MD_mac_get_nonblocking_connect_error(fd);
if (err == -1)
return PR_FAILURE;
else
@@ -366,13 +355,23 @@ static PRStatus PR_CALLBACK SocketConnectContinue(
#elif defined(XP_BEOS)
+#ifdef BONE_VERSION /* bug 122364 */
+ /* temporary workaround until getsockopt(SO_ERROR) works in BONE */
+ if (out_flags & PR_POLL_EXCEPT) {
+ PR_SetError(PR_CONNECT_REFUSED_ERROR, 0);
+ return PR_FAILURE;
+ }
+ PR_ASSERT(out_flags & PR_POLL_WRITE);
+ return PR_SUCCESS;
+#else
err = _MD_beos_get_nonblocking_connect_error(fd);
if( err != 0 ) {
- _PR_MD_MAP_CONNECT_ERROR(err);
- return PR_FAILURE;
+ _PR_MD_MAP_CONNECT_ERROR(err);
+ return PR_FAILURE;
}
else
- return PR_SUCCESS;
+ return PR_SUCCESS;
+#endif /* BONE_VERSION */
#else
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
@@ -1274,7 +1273,7 @@ PR_IMPLEMENT(PRFileDesc*) PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto)
if (!_pr_initialized) _PR_ImplicitInitialization();
if (PR_AF_INET != domain
&& PR_AF_INET6 != domain
-#if defined(XP_UNIX)
+#if defined(XP_UNIX) || defined(XP_OS2)
&& PR_AF_LOCAL != domain
#endif
) {
@@ -1396,7 +1395,7 @@ PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc *f[])
*/
SOCKET listenSock;
SOCKET osfd[2];
- struct sockaddr_in selfAddr;
+ struct sockaddr_in selfAddr, peerAddr;
int addrLen;
if (!_pr_initialized) _PR_ImplicitInitialization();
@@ -1440,10 +1439,24 @@ PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc *f[])
addrLen) == SOCKET_ERROR) {
goto failed;
}
- osfd[1] = accept(listenSock, NULL, NULL);
+ /*
+ * A malicious local process may connect to the listening
+ * socket, so we need to verify that the accepted connection
+ * is made from our own socket osfd[0].
+ */
+ if (getsockname(osfd[0], (struct sockaddr *) &selfAddr,
+ &addrLen) == SOCKET_ERROR) {
+ goto failed;
+ }
+ osfd[1] = accept(listenSock, (struct sockaddr *) &peerAddr, &addrLen);
if (osfd[1] == INVALID_SOCKET) {
goto failed;
}
+ if (peerAddr.sin_port != selfAddr.sin_port) {
+ /* the connection we accepted is not from osfd[0] */
+ PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
+ goto failed;
+ }
closesocket(listenSock);
f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods());
@@ -1480,7 +1493,7 @@ failed:
* default implementation
*/
PRFileDesc *listenSock;
- PRNetAddr selfAddr;
+ PRNetAddr selfAddr, peerAddr;
PRUint16 port;
f[0] = f[1] = NULL;
@@ -1503,6 +1516,17 @@ failed:
if (f[0] == NULL) {
goto failed;
}
+#ifdef _PR_CONNECT_DOES_NOT_BIND
+ /*
+ * If connect does not implicitly bind the socket (e.g., on
+ * BeOS), we have to bind the socket so that we can get its
+ * port with getsockname later.
+ */
+ PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr);
+ if (PR_Bind(f[0], &selfAddr) == PR_FAILURE) {
+ goto failed;
+ }
+#endif
PR_InitializeNetAddr(PR_IpAddrLoopback, port, &selfAddr);
/*
@@ -1518,10 +1542,23 @@ failed:
== PR_FAILURE) {
goto failed;
}
- f[1] = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT);
+ /*
+ * A malicious local process may connect to the listening
+ * socket, so we need to verify that the accepted connection
+ * is made from our own socket f[0].
+ */
+ if (PR_GetSockName(f[0], &selfAddr) == PR_FAILURE) {
+ goto failed;
+ }
+ f[1] = PR_Accept(listenSock, &peerAddr, PR_INTERVAL_NO_TIMEOUT);
if (f[1] == NULL) {
goto failed;
}
+ if (peerAddr.inet.port != selfAddr.inet.port) {
+ /* the connection we accepted is not from f[0] */
+ PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
+ goto failed;
+ }
PR_Close(listenSock);
return PR_SUCCESS;
@@ -1532,6 +1569,9 @@ failed:
if (f[0]) {
PR_Close(f[0]);
}
+ if (f[1]) {
+ PR_Close(f[1]);
+ }
return PR_FAILURE;
#endif
}
@@ -1539,20 +1579,14 @@ failed:
PR_IMPLEMENT(PRInt32)
PR_FileDesc2NativeHandle(PRFileDesc *fd)
{
- if (fd) {
- /*
- * The fd may be layered. Chase the links to the
- * bottom layer to get the osfd.
- */
- PRFileDesc *bottom = fd;
- while (bottom->lower != NULL) {
- bottom = bottom->lower;
- }
- return bottom->secret->md.osfd;
- } else {
- PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
- return -1;
- }
+ if (fd) {
+ fd = PR_GetIdentitiesLayer(fd, PR_NSPR_IO_LAYER);
+ }
+ if (!fd) {
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ return -1;
+ }
+ return fd->secret->md.osfd;
}
PR_IMPLEMENT(void)
diff --git a/pr/src/io/prstdio.c b/pr/src/io/prstdio.c
index 4ae2f267..de4c39de 100644
--- a/pr/src/io/prstdio.c
+++ b/pr/src/io/prstdio.c
@@ -56,7 +56,45 @@ PR_IMPLEMENT(PRUint32) PR_vfprintf(PRFileDesc* fd, const char *fmt, va_list ap)
PRUint32 rv, len;
char* msg = PR_vsmprintf(fmt, ap);
len = strlen(msg);
+#ifdef XP_OS2
+ /*
+ * OS/2 really needs a \r for every \n.
+ * In the future we should try to use scatter-gather instead of a
+ * succession of PR_Write.
+ */
+ if (isatty(PR_FileDesc2NativeHandle(fd))) {
+ PRUint32 last = 0, idx;
+ PRInt32 tmp;
+ rv = 0;
+ for (idx = 0; idx < len+1; idx++) {
+ if ((idx - last > 0) && (('\n' == msg[idx]) || (idx == len))) {
+ tmp = PR_Write(fd, msg + last, idx - last);
+ if (tmp >= 0) {
+ rv += tmp;
+ }
+ last = idx;
+ }
+ /*
+ * if current character is \n, and
+ * previous character isn't \r, and
+ * next character isn't \r
+ */
+ if (('\n' == msg[idx]) &&
+ ((0 == idx) || ('\r' != msg[idx-1])) &&
+ ('\r' != msg[idx+1])) {
+ /* add extra \r */
+ tmp = PR_Write(fd, "\r", 1);
+ if (tmp >= 0) {
+ rv += tmp;
+ }
+ }
+ }
+ } else {
+ rv = PR_Write(fd, msg, len);
+ }
+#else
rv = PR_Write(fd, msg, len);
+#endif
PR_DELETE(msg);
return rv;
}