summaryrefslogtreecommitdiffstats
path: root/src/libs/xpcom18a4/nsprpub/pr/src/md/mac
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/xpcom18a4/nsprpub/pr/src/md/mac')
-rw-r--r--src/libs/xpcom18a4/nsprpub/pr/src/md/mac/MANIFEST7
-rw-r--r--src/libs/xpcom18a4/nsprpub/pr/src/md/mac/MacErrorHandling.h668
-rw-r--r--src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macdll.c587
-rw-r--r--src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macdll.h57
-rw-r--r--src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macio.c1949
-rw-r--r--src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macio.h51
-rw-r--r--src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macrng.c52
-rw-r--r--src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macsocket.h238
-rw-r--r--src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macsockotpt.c2321
-rw-r--r--src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macthr.c721
-rw-r--r--src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mactime.c253
-rw-r--r--src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mactime.h51
-rw-r--r--src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mdcriticalregion.c173
-rw-r--r--src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mdcriticalregion.h59
-rw-r--r--src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mdmac.c776
-rw-r--r--src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mdmac.h51
-rw-r--r--src/libs/xpcom18a4/nsprpub/pr/src/md/mac/prcpucfg.h136
17 files changed, 8150 insertions, 0 deletions
diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/MANIFEST b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/MANIFEST
new file mode 100644
index 00000000..c51cbd5a
--- /dev/null
+++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/MANIFEST
@@ -0,0 +1,7 @@
+#
+# This is a list of local files which get copied to the mozilla:dist directory
+#
+
+MacErrorHandling.h
+macsocket.h
+prcpucfg.h
diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/MacErrorHandling.h b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/MacErrorHandling.h
new file mode 100644
index 00000000..b0e03900
--- /dev/null
+++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/MacErrorHandling.h
@@ -0,0 +1,668 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*********************************************************************
+
+FILENAME
+ Exceptions.h
+
+DESCRIPTION
+ A collection of routines and macros to handle assertions and
+ exceptions.
+
+COPYRIGHT
+ Copyright © Apple Computer, Inc. 1989-1991
+ All rights reserved.
+
+ROUTINES
+ EXTERNALS
+ dprintf
+ check_dprintf
+ checkpos_dprintf
+
+MACROS
+ EXTERNALS
+ check
+ ncheck
+ check_action
+ ncheck_action
+ require
+ nrequire
+ require_action
+ nrequire_action
+ resume
+
+MODIFICATION HISTORY
+ Nov 12 95 BKJ Moved to MetroWerks environment & the NSPR
+
+NOTE
+ To keep code size down, use these routines and macros with the C
+ compiler option -b2 or -b3. This will eliminate duplicate strings
+ within a procedure.
+
+*********************************************************************/
+
+#ifndef __MACERRORHANDLING__
+#define __MACERRORHANDLING__
+
+/*********************************************************************
+
+INCLUDES
+
+*********************************************************************/
+
+#include <Types.h>
+
+/*<FF>*/
+/*********************************************************************
+
+CONSTANTS AND CONTROL
+
+*********************************************************************/
+
+/*
+ These defines are used to control the amount of information
+ displayed when an assertion fails. DEBUGOFF and WARN will run
+ silently. MIN will simply break into the debugger. ON will break
+ and display the assertion that failed and the exception (for
+ require statements). FULL will also display the source file name
+ and line number. SYM does a SysBreak and is usefull when using a
+ symbolic debugger like SourceBug or SADE. They should be set into
+ DEBUGLEVEL. The default LEVEL is OFF.
+*/
+
+#define DEBUGOFF 0
+#define DEBUGWARN 1
+#define DEBUGMIN 2
+#define DEBUGON 3
+#define DEBUGFULL 4
+#define DEBUGSYM 6
+
+#ifndef DEBUGLEVEL
+#define DEBUGLEVEL DEBUGOFF
+#endif DEBUGLEVEL
+
+/*
+ resumeLabel is used to control the insertion of labels for use with
+ the resume macro. If you do not use the resume macro and you wish
+ to have multible exceptions per label then you can add the
+ following define to you source code.
+
+*/
+#define resumeLabel(exception) // Multiple exceptions per label
+// #define resumeLabel(exception) resume_ ## exception: // Single exception per label
+
+
+/*
+ traceon and debugon are used to test for options
+*/
+
+#define traceon ((DEBUGLEVEL > DEBUGWARN) && defined(TRACEON))
+#define debugon (DEBUGLEVEL > DEBUGWARN)
+
+/*
+ Add some macros for DEBUGMIN and DEBUGSYM to keep the size down.
+*/
+
+#define __DEBUGSMALL ((DEBUGLEVEL == DEBUGMIN) || \
+ (DEBUGLEVEL == DEBUGSYM))
+
+#if DEBUGLEVEL == DEBUGMIN
+#define __DebuggerBreak Debugger()
+#elif DEBUGLEVEL == DEBUGSYM
+#define __DebuggerBreak SysBreak()
+#endif
+
+
+/*<FF>*/
+/*********************************************************************
+
+MACRO
+ check(assertion)
+
+DESCRIPTION
+ If debugging is on then check will test assertion and if it fails
+ break into the debugger. Otherwise check does nothing.
+
+*********************************************************************/
+
+#if __DEBUGSMALL
+
+#define check(assertion) \
+ do { \
+ if (assertion) ; \
+ else __DebuggerBreak; \
+ } while (false)
+
+#elif DEBUGLEVEL == DEBUGON
+
+#define check(assertion) \
+ do { \
+ if (assertion) ; \
+ else { \
+ dprintf(notrace, "Assertion \"%s\" Failed", #assertion); \
+ } \
+ } while (false)
+
+#elif DEBUGLEVEL == DEBUGFULL
+
+#define check(assertion) \
+ do { \
+ if (assertion) ; \
+ else { \
+ dprintf(notrace, "Assertion \"%s\" Failed\n" \
+ "File: %s\n" \
+ "Line: %d", \
+ #assertion, __FILE__, __LINE__); \
+ } \
+ } while (false)
+
+#else
+
+#define check(assertion)
+
+#endif
+
+/*<FF>*/
+/*********************************************************************
+
+MACRO
+ ncheck(assertion)
+
+DESCRIPTION
+ If debugging is on then ncheck will test !assertion and if it fails
+ break into the debugger. Otherwise ncheck does nothing.
+
+*********************************************************************/
+
+#if __DEBUGSMALL
+
+#define ncheck(assertion) \
+ do { \
+ if (assertion) __DebuggerBreak; \
+ } while (false)
+
+#elif DEBUGLEVEL == DEBUGON
+
+#define ncheck(assertion) \
+ do { \
+ void* __privateAssertion = (void*)(assertion); \
+ \
+ if (__privateAssertion) { \
+ dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed", \
+ #assertion, __privateAssertion); \
+ } \
+ } while (false)
+
+#elif DEBUGLEVEL == DEBUGFULL
+
+#define ncheck(assertion) \
+ do { \
+ void* __privateAssertion = (void*)(assertion); \
+ \
+ if (__privateAssertion) { \
+ dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed\n" \
+ "File: %s\n" \
+ "Line: %d", \
+ #assertion, __privateAssertion, __FILE__, __LINE__); \
+ } \
+ } while (false)
+
+#else
+
+#define ncheck(assertion)
+
+#endif
+
+/*<FF>*/
+/*********************************************************************
+
+MACRO
+ check_action(assertion, action)
+
+DESCRIPTION
+ If debugging is on then check_action will test assertion and if it
+ fails break into the debugger then execute action. Otherwise
+ check_action does nothing.
+
+*********************************************************************/
+
+#if __DEBUGSMALL
+
+#define check_action(assertion, action) \
+ do { \
+ if (assertion) ; \
+ else { \
+ __DebuggerBreak; \
+ { action } \
+ } while (false)
+
+#elif DEBUGLEVEL == DEBUGON
+
+#define check_action(assertion, action) \
+ do { \
+ if (assertion) ; \
+ else { \
+ dprintf(notrace, "Assertion \"%s\" Failed", #assertion); \
+ { action } \
+ } \
+ } while (false)
+
+#elif DEBUGLEVEL == DEBUGFULL
+
+#define check_action(assertion, action) \
+ do { \
+ if (assertion) ; \
+ else { \
+ dprintf(notrace, "Assertion \"%s\" Failed\n" \
+ "File: %s\n" \
+ "Line: %d", \
+ #assertion, __FILE__, __LINE__); \
+ { action } \
+ } \
+ } while (false)
+
+#else
+
+#define check_action(assertion, action)
+
+#endif
+
+/*<FF>*/
+/**************************************************************************************
+
+MACRO
+ ncheck_action(assertion, action)
+
+DESCRIPTION
+ If debugging is on then ncheck_action will test !assertion and if
+ it fails break into the debugger then execute action. Otherwise
+ ncheck_action does nothing.
+
+*********************************************************************/
+
+#if __DEBUGSMALL
+
+#define ncheck_action(assertion, action) \
+ do { \
+ if (assertion) { \
+ __DebuggerBreak; \
+ { action } \
+ } \
+ } while (false)
+
+#elif DEBUGLEVEL == DEBUGON
+
+#define ncheck_action(assertion, action) \
+ do { \
+ void* __privateAssertion = (void*)(assertion); \
+ \
+ if (__privateAssertion) { \
+ dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed", \
+ #assertion, __privateAssertion); \
+ { action } \
+ } \
+ } while (false)
+
+#elif DEBUGLEVEL == DEBUGFULL
+
+#define ncheck_action(assertion, action) \
+ do { \
+ void* __privateAssertion = (void*)(assertion); \
+ \
+ if (__privateAssertion) { \
+ dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed\n" \
+ "File: %s\n" \
+ "Line: %d", \
+ #assertion, __privateAssertion, __FILE__, __LINE__); \
+ { action } \
+ } \
+ } while (false)
+
+#else
+
+#define ncheck_action(assertion, action)
+
+#endif
+
+/*<FF>*/
+/*********************************************************************
+
+MACRO
+ require(assertion, exception)
+
+DESCRIPTION
+ require will test assertion and if it fails:
+ break into the debugger if debugging is on.
+ goto exception.
+
+*********************************************************************/
+
+#if __DEBUGSMALL
+
+#define require(assertion, exception) \
+ do { \
+ if (assertion) ; \
+ else { \
+ __DebuggerBreak; \
+ goto exception; \
+ resumeLabel(exception); \
+ } \
+ } while (false)
+
+#elif DEBUGLEVEL == DEBUGON
+
+#define require(assertion, exception) \
+ do { \
+ if (assertion) ; \
+ else { \
+ dprintf(notrace, "Assertion \"%s\" Failed\n" \
+ "Exception \"%s\" Raised", \
+ #assertion, #exception); \
+ goto exception; \
+ resumeLabel(exception); \
+ } \
+ } while (false)
+
+#elif DEBUGLEVEL == DEBUGFULL
+
+#define require(assertion, exception) \
+ do { \
+ if (assertion) ; \
+ else { \
+ dprintf(notrace, "Assertion \"%s\" Failed\n" \
+ "Exception \"%s\" Raised\n" \
+ "File: %s\n" \
+ "Line: %d", \
+ #assertion, #exception, __FILE__, __LINE__); \
+ goto exception; \
+ resumeLabel(exception); \
+ } \
+ } while (false)
+
+#else
+
+#define require(assertion, exception) \
+ do { \
+ if (assertion) ; \
+ else { \
+ goto exception; \
+ resumeLabel(exception); \
+ } \
+ } while (false)
+
+#endif
+
+/*<FF>*/
+/*********************************************************************
+
+MACRO
+ nrequire(assertion, exception)
+
+DESCRIPTION
+ nrequire will test !assertion and if it fails:
+ break into the debugger if debugging is on.
+ goto exception.
+
+*********************************************************************/
+
+#if __DEBUGSMALL
+
+#define nrequire(assertion, exception) \
+ do { \
+ if (assertion) { \
+ DebugStr(); \
+ goto exception; \
+ resumeLabel(exception); \
+ } \
+ } while (false)
+
+#elif DEBUGLEVEL == DEBUGON
+
+#define nrequire(assertion, exception) \
+ do { \
+ void* __privateAssertion = (void*)(assertion); \
+ \
+ if (__privateAssertion) { \
+ dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed\n" \
+ "Exception \"%s\" Raised", \
+ #assertion, __privateAssertion, #exception); \
+ goto exception; \
+ resumeLabel(exception); \
+ } \
+ } while (false)
+
+#elif DEBUGLEVEL == DEBUGFULL
+
+#define nrequire(assertion, exception) \
+ do { \
+ void* __privateAssertion = (void*)(assertion); \
+ \
+ if (__privateAssertion) { \
+ dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed\n" \
+ "Exception \"%s\" Raised\n" \
+ "File: %s\n" \
+ "Line: %d", \
+ #assertion, __privateAssertion, #exception, __FILE__, \
+ __LINE__); \
+ goto exception; \
+ resumeLabel(exception); \
+ } \
+ } while (false)
+
+#else
+
+#define nrequire(assertion, exception) \
+ do { \
+ if (assertion) { \
+ goto exception; \
+ resumeLabel(exception); \
+ } \
+ } while (false)
+
+#endif
+
+/*<FF>*/
+/*********************************************************************
+
+MACRO
+ require_action(assertion, exception, action)
+
+DESCRIPTION
+ require_action will test assertion and if it fails:
+ break into the debugger if debugging is on.
+ execute action.
+ goto exception.
+
+*********************************************************************/
+
+#if __DEBUGSMALL
+
+#define require_action(assertion, exception, action) \
+ do { \
+ if (assertion) ; \
+ else { \
+ __DebuggerBreak; \
+ { action } \
+ goto exception; \
+ resumeLabel(exception); \
+ } \
+ } while (false)
+
+#elif DEBUGLEVEL == DEBUGON
+
+#define require_action(assertion, exception, action) \
+ do { \
+ if (assertion) ; \
+ else { \
+ dprintf(notrace, "Assertion \"%s\" Failed\n" \
+ "Exception \"%s\" Raised", \
+ #assertion, #exception); \
+ { action } \
+ goto exception; \
+ resumeLabel(exception); \
+ } \
+ } while (false)
+
+#elif DEBUGLEVEL == DEBUGFULL
+
+#define require_action(assertion, exception, action) \
+ do { \
+ if (assertion) ; \
+ else { \
+ dprintf(notrace, "Assertion \"%s\" Failed\n" \
+ "Exception \"%s\" Raised\n" \
+ "File: %s\n" \
+ "Line: %d", \
+ #assertion, #exception, __FILE__, __LINE__); \
+ { action } \
+ goto exception; \
+ resumeLabel(exception); \
+ } \
+ } while (false)
+
+#else
+
+#define require_action(assertion, exception, action) \
+ do { \
+ if (assertion) ; \
+ else { \
+ { action } \
+ goto exception; \
+ resumeLabel(exception); \
+ } \
+ } while (false)
+
+#endif
+
+/*<FF>*/
+/*********************************************************************
+
+MACRO
+ nrequire_action(assertion, exception, action)
+
+DESCRIPTION
+ nrequire_action will test !assertion and if it fails:
+ break into the debugger if debugging is on.
+ execute action.
+ goto exception.
+
+*********************************************************************/
+
+#if __DEBUGSMALL
+
+#define nrequire_action(assertion, exception, action) \
+ do { \
+ if (assertion) { \
+ __DebuggerBreak; \
+ { action } \
+ goto exception; \
+ resumeLabel(exception); \
+ } \
+ } while (false)
+
+#elif DEBUGLEVEL == DEBUGON
+
+#define nrequire_action(assertion, exception, action) \
+ do { \
+ void* __privateAssertion = (void*)(assertion); \
+ \
+ if (__privateAssertion) { \
+ dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed\n" \
+ "Exception \"%s\" Raised", \
+ #assertion, __privateAssertion, #exception); \
+ { action } \
+ goto exception; \
+ resumeLabel(exception); \
+ } \
+ } while (false)
+
+#elif DEBUGLEVEL == DEBUGFULL
+
+#define nrequire_action(assertion, exception, action) \
+ do { \
+ void* __privateAssertion = (void*)(assertion); \
+ \
+ if (__privateAssertion) { \
+ dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed\n" \
+ "Exception \"%s\" Raised\n" \
+ "File: %s\n" \
+ "Line: %d", \
+ #assertion, __privateAssertion, #exception, __FILE__, \
+ __LINE__); \
+ { action } \
+ goto exception; \
+ resumeLabel(exception); \
+ } \
+ } while (false)
+
+#else
+
+#define nrequire_action(assertion, exception, action) \
+ do { \
+ if (assertion) { \
+ { action } \
+ goto exception; \
+ resumeLabel(exception); \
+ } \
+ } while (false)
+
+#endif
+
+/*<FF>*/
+/*********************************************************************
+
+MACRO
+ resume(exception)
+
+DESCRIPTION
+ resume will resume execution after the n/require/_action statement
+ specified by exception. Resume lables must be on (the default) in
+ order to use resume. If an action form of require was used then the
+ action will not be re-executed.
+
+*********************************************************************/
+
+
+#define resume(exception) \
+ do { \
+ goto resume_ ## exception; \
+ } while (false)
+
+
+/*<FF>*/
+/********************************************************************/
+#endif
diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macdll.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macdll.c
new file mode 100644
index 00000000..a5ecce78
--- /dev/null
+++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macdll.c
@@ -0,0 +1,587 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <string.h>
+
+#include <Files.h>
+#include <Errors.h>
+#include <Folders.h>
+#include <CodeFragments.h>
+#include <Aliases.h>
+#include <Resources.h>
+
+#include "IterateDirectory.h" /* MoreFiles */
+
+#include "MacErrorHandling.h"
+#include "macdll.h"
+#include "mdmac.h"
+#include "macio.h"
+
+#include "primpl.h"
+#include "plstr.h"
+
+/*
+ turds used to iterate through the directories looking
+ for the desired library.
+*/
+
+struct GetSharedLibraryFilterProcData
+{
+ Boolean inRecursive;
+ StringPtr inName;
+
+ Boolean outFound;
+ CFragConnectionID outID;
+ Ptr outAddress;
+ OSErr outError;
+};
+typedef struct GetSharedLibraryFilterProcData GetSharedLibraryFilterProcData;
+
+static pascal void
+GetSharedLibraryFilterProc(const CInfoPBRec* const inCpb, Boolean* inWantQuit, void *inFilterData);
+
+
+/*
+ NSGetSharedLibrary
+
+ Unfortunately CFM doesn't support user specified loader paths,
+ so we emulate the behavior. Effectively this is a GetSharedLibrary
+ where the loader path is user defined.
+*/
+
+OSErr
+NSGetSharedLibrary(Str255 inLibName, CFragConnectionID* outID, Ptr* outMainAddr)
+{
+ char* curLibPath;
+ char* freeCurLibPath;
+ OSErr tempErr;
+ Boolean recursive;
+ FSSpec curFolder;
+ GetSharedLibraryFilterProcData filterData;
+ char *endCurLibPath;
+ Boolean done;
+
+ filterData.outFound = false;
+ filterData.outID = (CFragConnectionID)(-1);
+ filterData.outAddress = NULL;
+ filterData.inName = inLibName;
+
+ freeCurLibPath = curLibPath = PR_GetLibraryPath();
+
+ if (curLibPath == NULL)
+ return (cfragNoLibraryErr);
+
+ tempErr = cfragNoLibraryErr;
+
+ do
+ {
+ endCurLibPath = PL_strchr(curLibPath, PR_PATH_SEPARATOR);
+ done = (endCurLibPath == NULL);
+
+#if 0
+ // we overload the first character of a path if it's :
+ // then we want to recursively search that path
+ // see if path should be recursive
+ if (*curLibPath == ':')
+ {
+ // ':' is an illegal character in the name of a file
+ // if we start any path with this, we want to allow
+ // search recursively
+ curLibPath++;
+ recursive = true;
+ }
+ else
+#endif
+ {
+ recursive = false;
+ }
+
+ if (!done)
+ *endCurLibPath = '\0'; // NULL terminate the string
+
+ // convert to FSSpec
+ tempErr = ConvertUnixPathToFSSpec(curLibPath, &curFolder);
+
+ // now look in this directory
+ if (noErr == tempErr)
+ {
+ filterData.inRecursive = recursive;
+ FSpIterateDirectory(&curFolder, recursive ? 0 : 1, &GetSharedLibraryFilterProc, &filterData);
+
+ if (filterData.outFound)
+ {
+ *outID = filterData.outID;
+ *outMainAddr = filterData.outAddress;
+ tempErr = noErr;
+ break;
+ }
+ else
+ {
+ tempErr = cfragNoLibraryErr;
+ }
+ }
+
+ curLibPath = endCurLibPath + 1; // skip to next path (past the '\0');
+ } while (!done);
+
+ free(freeCurLibPath);
+ return (tempErr);
+}
+
+
+static Boolean
+LibInPefContainer(const FSSpec* inSpec, StringPtr inName, UInt32* outCodeOffset, UInt32* outCodeLength);
+
+
+/*
+ GetSharedLibraryFilterProc
+
+ Callback to FSpIterateDirectory, finds a library with the name matching the
+ data in inFilterData (of type GetSharedLibraryFilterProcData). Forces a quit
+ when a match is found.
+*/
+
+static pascal void
+GetSharedLibraryFilterProc(const CInfoPBRec* const inCpb, Boolean* inWantQuit, void *inFilterData)
+{
+ GetSharedLibraryFilterProcData* pFilterData = (GetSharedLibraryFilterProcData*) inFilterData;
+
+ if ((inCpb->hFileInfo.ioFlAttrib & (1 << ioDirFlg)) == 0)
+ {
+ FSSpec fragSpec;
+ OSErr tempErr;
+ Str255 errName;
+ Boolean crap;
+ UInt32 codeOffset;
+ UInt32 codeLength;
+
+ // it's a file
+
+ // ¥ fix-me do we really want to allow all 'APPL's' for in which to find this library?
+ switch (inCpb->hFileInfo.ioFlFndrInfo.fdType)
+ {
+ case kCFragLibraryFileType:
+ case 'APPL':
+ tempErr = FSMakeFSSpec(inCpb->hFileInfo.ioVRefNum, inCpb->hFileInfo.ioFlParID, inCpb->hFileInfo.ioNamePtr, &fragSpec);
+
+ // this shouldn't fail
+ if (noErr != tempErr)
+ {
+ return;
+ }
+
+ // resolve an alias if this was one
+ tempErr = ResolveAliasFile(&fragSpec, true, &crap, &crap);
+
+ // if got here we have a shlb (or app-like shlb)
+ if (noErr != tempErr)
+ {
+ // probably couldn't resolve an alias
+ return;
+ }
+
+ break;
+ default:
+ return;
+ }
+
+ // see if this symbol is in this fragment
+ if (LibInPefContainer(&fragSpec, pFilterData->inName, &codeOffset, &codeLength))
+ tempErr = GetDiskFragment(&fragSpec, codeOffset, codeLength, fragSpec.name, kLoadCFrag, &pFilterData->outID, &pFilterData->outAddress, errName);
+ else
+ return;
+
+ // stop if we found a library by that name
+ if (noErr == tempErr)
+ {
+ *inWantQuit = true;
+ pFilterData->outFound = true;
+ pFilterData->outError = tempErr;
+ }
+ }
+ // FSpIterateDirectory will automagically call us for subsequent sub-dirs if necessary
+}
+
+
+/*
+ LibInPefContainer
+
+ Tell whether library inName is contained it the file pointed to by inSpec.
+ Return the codeOffset and codeLength information, for a subsequent
+ call to GetDiskFragment.
+*/
+
+static Boolean
+LibInPefContainer(const FSSpec* inSpec, StringPtr inName, UInt32* outCodeOffset, UInt32* outCodeLength)
+{
+ short refNum;
+ CFragResourceHandle hCfrg;
+ CFragResourceMember* pCurItem;
+ UInt32 curLibIndex;
+ Boolean found;
+
+ // asume we didn't find it
+ found = false;
+
+ // open the resource fork, if we can't bail
+ refNum = FSpOpenResFile(inSpec, fsRdPerm);
+ require(-1 != refNum, Exit);
+
+ // grab out the alias record, if it's not there bail
+ hCfrg = (CFragResourceHandle) Get1Resource(kCFragResourceType, kCFragResourceID);
+ require(NULL != hCfrg, CloseResourceAndExit);
+
+ HLock((Handle)hCfrg);
+
+ // get ptr to first item
+ pCurItem = &(*hCfrg)->firstMember;
+ for (curLibIndex = 0; curLibIndex < (*hCfrg)->memberCount; curLibIndex++)
+ {
+ // is this our library?
+ if ((pCurItem->name[0] == inName[0]) &&
+ (strncmp((char*) inName + 1, (char*) pCurItem->name + 1, PR_MIN(pCurItem->name[0], inName[0])) == 0))
+ {
+ *outCodeOffset = pCurItem->offset;
+ *outCodeLength = pCurItem->length;
+ found = true;
+ }
+
+ // skip to next one
+ pCurItem = (CFragResourceMember*) ((char*) pCurItem + pCurItem->memberSize);
+ }
+
+ HUnlock((Handle)hCfrg);
+
+CloseResourceAndExit:
+ CloseResFile(refNum);
+Exit:
+ return (found);
+
+}
+
+
+/*
+ NSFindSymbol
+
+ Workaround bug in CFM FindSymbol (in at least 7.5.5) where symbols with lengths
+ greater than 63 chars cause a "paramErr". We iterate through all symbols
+ in the library to find the desired symbol.
+*/
+
+OSErr
+NSFindSymbol(CFragConnectionID inID, Str255 inSymName, Ptr* outMainAddr, CFragSymbolClass *outSymClass)
+{
+ OSErr err;
+
+ if (inSymName[0] > 63)
+ {
+ /*
+ if there are greater than 63 characters in the
+ name, CFM FindSymbol fails, so let's iterate through all
+ of the symbols in the fragment and grab it
+ that way.
+ */
+ long symbolCount;
+ Str255 curSymName;
+ long curIndex;
+ Boolean found;
+
+ found = false;
+ err = CountSymbols(inID, &symbolCount);
+ if (noErr == err)
+ {
+ /* now iterate through all the symbols in the library */
+ /* per DTS the indices apparently go 0 to n-1 */
+ for (curIndex = 0; (curIndex <= symbolCount - 1 && !found); curIndex++)
+ {
+ err = GetIndSymbol(inID, curIndex, curSymName, outMainAddr, outSymClass);
+ if (noErr == err && curSymName[0] == inSymName[0] && !strncmp((char*)curSymName + 1, (char*)inSymName + 1, curSymName[0]))
+ {
+ /* found our symbol */
+ found = true;
+ }
+ }
+
+ /* if we didn't find it set the error code so below it won't take this symbol */
+ if (!found)
+ err = cfragNoSymbolErr;
+ }
+ }
+ else
+ {
+ err = FindSymbol(inID, inSymName, outMainAddr, outSymClass);
+ }
+
+ return (err);
+}
+
+
+#pragma mark -
+
+
+/*-----------------------------------------------------------------
+
+ GetNamedFragmentOffsets
+
+ Get the offsets into the data fork of the named fragment,
+ by reading the 'cfrg' resoruce.
+
+-----------------------------------------------------------------*/
+OSErr GetNamedFragmentOffsets(const FSSpec *fileSpec, const char* fragmentName,
+ UInt32 *outOffset, UInt32 *outLength)
+{
+ CFragResourceHandle cFragHandle;
+ short fileRefNum;
+ OSErr err = noErr;
+
+ fileRefNum = FSpOpenResFile(fileSpec, fsRdPerm);
+ err = ResError();
+ if (err != noErr) return err;
+
+ cFragHandle = (CFragResourceHandle)Get1Resource(kCFragResourceType, kCFragResourceID);
+ if (!cFragHandle)
+ {
+ err = resNotFound;
+ goto done;
+ }
+
+ /* nothing here moves memory, so no need to lock the handle */
+
+ err = cfragNoLibraryErr; /* in case of failure */
+ *outOffset = 0;
+ *outLength = 0;
+
+ /* Now look for the named fragment */
+ if ((**cFragHandle).memberCount > 0)
+ {
+ CFragResourceMemberPtr memberPtr;
+ UInt16 i;
+
+ for ( i = 0, memberPtr = &(**cFragHandle).firstMember;
+ i < (**cFragHandle).memberCount;
+ i ++, memberPtr = (CFragResourceMemberPtr)((char *)memberPtr + memberPtr->memberSize))
+ {
+ char memberName[256];
+ UInt16 nameLen = PR_MIN(memberPtr->name[0], 255);
+
+ // avoid malloc here for speed
+ strncpy(memberName, (char *)&memberPtr->name[1], nameLen);
+ memberName[nameLen] = '\0';
+
+ // fragment names are case insensitive, so act like the system
+ if (PL_strcasecmp(memberName, fragmentName) == 0)
+ {
+ *outOffset = memberPtr->offset;
+ *outLength = memberPtr->length;
+ err = noErr;
+ break;
+ }
+ }
+ }
+
+ /* Resource handle will go away when the res fork is closed */
+
+done:
+ CloseResFile(fileRefNum);
+ return err;
+}
+
+
+/*-----------------------------------------------------------------
+
+ GetIndexedFragmentOffsets
+
+ Get the offsets into the data fork of the indexed fragment,
+ by reading the 'cfrg' resoruce.
+
+-----------------------------------------------------------------*/
+OSErr GetIndexedFragmentOffsets(const FSSpec *fileSpec, UInt32 fragmentIndex,
+ UInt32 *outOffset, UInt32 *outLength, char **outFragmentName)
+{
+ CFragResourceHandle cFragHandle;
+ short fileRefNum;
+ OSErr err = noErr;
+
+ fileRefNum = FSpOpenResFile(fileSpec, fsRdPerm);
+ err = ResError();
+ if (err != noErr) return err;
+
+ cFragHandle = (CFragResourceHandle)Get1Resource(kCFragResourceType, kCFragResourceID);
+ if (!cFragHandle)
+ {
+ err = resNotFound;
+ goto done;
+ }
+
+ err = cfragNoLibraryErr; /* in case of failure */
+ *outOffset = 0;
+ *outLength = 0;
+ *outFragmentName = NULL;
+
+ /* the CStrFromPStr mallocs, so might move memory */
+ HLock((Handle)cFragHandle);
+
+ /* Now look for the named fragment */
+ if ((**cFragHandle).memberCount > 0)
+ {
+ CFragResourceMemberPtr memberPtr;
+ UInt16 i;
+
+ for ( i = 0, memberPtr = &(**cFragHandle).firstMember;
+ i < (**cFragHandle).memberCount;
+ i ++, memberPtr = (CFragResourceMemberPtr)((char *)memberPtr + memberPtr->memberSize))
+ {
+
+ if (i == fragmentIndex)
+ {
+ char *fragmentStr;
+ CStrFromPStr(memberPtr->name, &fragmentStr);
+ if (!fragmentStr) /* test for allocation failure */
+ {
+ err = memFullErr;
+ break;
+ }
+
+ *outFragmentName = fragmentStr;
+ *outOffset = memberPtr->offset;
+ *outLength = memberPtr->length;
+ err = noErr;
+ break;
+ }
+ }
+ }
+
+ HUnlock((Handle)cFragHandle);
+
+ /* Resource handle will go away when the res fork is closed */
+
+done:
+ CloseResFile(fileRefNum);
+ return err;
+}
+
+
+/*-----------------------------------------------------------------
+
+ NSLoadNamedFragment
+
+ Load the named fragment from the specified file. Aliases must
+ have been resolved by this point.
+
+-----------------------------------------------------------------*/
+
+OSErr NSLoadNamedFragment(const FSSpec *fileSpec, const char* fragmentName, CFragConnectionID *outConnectionID)
+{
+ UInt32 fragOffset, fragLength;
+ short fragNameLength;
+ Ptr main;
+ Str255 fragName;
+ Str255 errName;
+ OSErr err;
+
+ err = GetNamedFragmentOffsets(fileSpec, fragmentName, &fragOffset, &fragLength);
+ if (err != noErr) return err;
+
+ // convert fragment name to pascal string
+ fragNameLength = strlen(fragmentName);
+ if (fragNameLength > 255)
+ fragNameLength = 255;
+ BlockMoveData(fragmentName, &fragName[1], fragNameLength);
+ fragName[0] = fragNameLength;
+
+ // Note that we pass the fragment name as the 4th param to GetDiskFragment.
+ // This value affects the ability of debuggers, and the Talkback system,
+ // to match code fragments with symbol files
+ err = GetDiskFragment(fileSpec, fragOffset, fragLength, fragName,
+ kLoadCFrag, outConnectionID, &main, errName);
+
+ return err;
+}
+
+
+/*-----------------------------------------------------------------
+
+ NSLoadIndexedFragment
+
+ Load the indexed fragment from the specified file. Aliases must
+ have been resolved by this point.
+
+ *outFragName is a malloc'd block containing the fragment name,
+ if returning noErr.
+
+-----------------------------------------------------------------*/
+
+OSErr NSLoadIndexedFragment(const FSSpec *fileSpec, PRUint32 fragmentIndex,
+ char** outFragName, CFragConnectionID *outConnectionID)
+{
+ UInt32 fragOffset, fragLength;
+ char *fragNameBlock = NULL;
+ Ptr main;
+ Str255 fragName = "\p";
+ Str255 errName;
+ OSErr err;
+
+ *outFragName = NULL;
+
+ err = GetIndexedFragmentOffsets(fileSpec, fragmentIndex, &fragOffset, &fragLength, &fragNameBlock);
+ if (err != noErr) return err;
+
+ if (fragNameBlock)
+ {
+ UInt32 nameLen = strlen(fragNameBlock);
+ if (nameLen > 63)
+ nameLen = 63;
+ BlockMoveData(fragNameBlock, &fragName[1], nameLen);
+ fragName[0] = nameLen;
+ }
+
+ // Note that we pass the fragment name as the 4th param to GetDiskFragment.
+ // This value affects the ability of debuggers, and the Talkback system,
+ // to match code fragments with symbol files
+ err = GetDiskFragment(fileSpec, fragOffset, fragLength, fragName,
+ kLoadCFrag, outConnectionID, &main, errName);
+ if (err != noErr)
+ {
+ free(fragNameBlock);
+ return err;
+ }
+
+ *outFragName = fragNameBlock;
+ return noErr;
+}
+
+
diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macdll.h b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macdll.h
new file mode 100644
index 00000000..a34890cd
--- /dev/null
+++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macdll.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef macdll_h__
+#define macdll_h__
+
+#include "prtypes.h"
+
+OSErr GetNamedFragmentOffsets(const FSSpec *fileSpec, const char* fragmentName,
+ UInt32 *outOffset, UInt32 *outLength);
+OSErr GetIndexedFragmentOffsets(const FSSpec *fileSpec, UInt32 fragmentIndex,
+ UInt32 *outOffset, UInt32 *outLength, char **outFragmentName);
+
+OSErr NSLoadNamedFragment(const FSSpec *fileSpec, const char* fragmentName, CFragConnectionID *outConnectionID);
+OSErr NSLoadIndexedFragment(const FSSpec *fileSpec, PRUint32 fragmentIndex,
+ char** outFragName, CFragConnectionID *outConnectionID);
+
+
+OSErr NSGetSharedLibrary(Str255 inLibName, CFragConnectionID* outID, Ptr* outMainAddr);
+OSErr NSFindSymbol(CFragConnectionID inID, Str255 inSymName,
+ Ptr* outMainAddr, CFragSymbolClass *outSymClass);
+
+#endif /* macdll_h__ */
diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macio.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macio.c
new file mode 100644
index 00000000..ae3516de
--- /dev/null
+++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macio.c
@@ -0,0 +1,1949 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <string.h>
+
+#include <Types.h>
+#include <Files.h>
+#include <Devices.h>
+#include <Folders.h>
+#include <Errors.h>
+#include <Resources.h>
+#include <Processes.h>
+#include <TextUtils.h>
+
+#include <fcntl.h>
+
+#include "FullPath.h" /* MoreFiles */
+
+#include "primpl.h"
+#include "MacErrorHandling.h"
+#include "mdmac.h"
+
+#include "macio.h"
+
+/* forward declarations */
+extern unsigned long gJanuaryFirst1970Seconds;
+
+extern void WaitOnThisThread(PRThread *thread, PRIntervalTime timeout);
+extern void DoneWaitingOnThisThread(PRThread *thread);
+extern void AsyncNotify(PRThread *thread);
+
+
+/* PB for Read and Write */
+struct ExtendedParamBlock {
+ /* PB must be first so that the file system can get the right data. */
+ ParamBlockRec pb;
+ PRThread *thread;
+};
+typedef struct ExtendedParamBlock ExtendedParamBlock;
+
+
+/* XXX Not done yet for 68K */
+/* I/O completion routne for _MD_READ and _MD_WRITE */
+static void AsyncIOCompletion (ExtendedParamBlock *pbAsyncPtr)
+{
+ _PRCPU *cpu = _PR_MD_CURRENT_CPU();
+ PRThread *thread = pbAsyncPtr->thread;
+ PRIntn is;
+
+ if (_PR_MD_GET_INTSOFF()) {
+ thread->md.missedIONotify = PR_TRUE;
+ cpu->u.missed[cpu->where] |= _PR_MISSED_IO;
+ } else {
+ _PR_INTSOFF(is);
+
+ thread->md.osErrCode = noErr;
+ DoneWaitingOnThisThread(thread);
+
+ _PR_FAST_INTSON(is);
+ }
+
+ SignalIdleSemaphore();
+}
+
+void _MD_SetError(OSErr oserror)
+{
+ PRErrorCode code;
+
+ switch (oserror) {
+ case memFullErr:
+ code = PR_OUT_OF_MEMORY_ERROR;
+ break;
+ case fnfErr:
+ code = PR_FILE_NOT_FOUND_ERROR;
+ break;
+ case dupFNErr:
+ code = PR_FILE_EXISTS_ERROR;
+ break;
+ case ioErr:
+ code = PR_IO_ERROR;
+ break;
+ case nsvErr:
+ case wrgVolTypErr:
+ code = PR_INVALID_DEVICE_STATE_ERROR;
+ break;
+ case bdNamErr:
+ case fsRnErr:
+ code = PR_NAME_TOO_LONG_ERROR;
+ break;
+ case tmfoErr:
+ code = PR_INSUFFICIENT_RESOURCES_ERROR;
+ break;
+ case opWrErr:
+ case wrPermErr:
+ case permErr:
+ case afpAccessDenied:
+ code = PR_NO_ACCESS_RIGHTS_ERROR;
+ break;
+ case afpObjectTypeErr:
+ code = PR_DIRECTORY_LOOKUP_ERROR;
+ break;
+ case wPrErr:
+ case vLckdErr:
+ code = PR_DEVICE_IS_LOCKED_ERROR;
+ break;
+ case fLckdErr:
+ code = PR_FILE_IS_LOCKED_ERROR;
+ break;
+ case dirNFErr:
+ code = PR_NOT_DIRECTORY_ERROR;
+ break;
+ case dirFulErr:
+ code = PR_MAX_DIRECTORY_ENTRIES_ERROR;
+ break;
+ case dskFulErr:
+ code = PR_NO_DEVICE_SPACE_ERROR;
+ break;
+ case rfNumErr:
+ case fnOpnErr:
+ code = PR_BAD_DESCRIPTOR_ERROR;
+ break;
+ case eofErr:
+ code = PR_END_OF_FILE_ERROR;
+ break;
+ case posErr:
+ case gfpErr:
+ code = PR_FILE_SEEK_ERROR;
+ break;
+ case fBsyErr:
+ code = PR_FILE_IS_BUSY_ERROR;
+ break;
+ case extFSErr:
+ code = PR_REMOTE_FILE_ERROR;
+ break;
+ case abortErr:
+ code = PR_PENDING_INTERRUPT_ERROR;
+ break;
+ case paramErr:
+ code = PR_INVALID_ARGUMENT_ERROR;
+ break;
+ case unimpErr:
+ code = PR_NOT_IMPLEMENTED_ERROR;
+ break;
+ }
+
+ PR_SetError(code, oserror);
+}
+
+void _MD_IOInterrupt(void)
+{
+ PRCList *qp;
+ PRThread *thread, *me = _PR_MD_CURRENT_THREAD();
+
+ PR_ASSERT(_PR_MD_GET_INTSOFF() != 0);
+
+ _PR_SLEEPQ_LOCK(me->cpu);
+ qp = _PR_PAUSEQ(me->cpu).next;
+ while (qp != &_PR_PAUSEQ(me->cpu)) {
+
+ thread = _PR_THREAD_PTR(qp);
+ PR_ASSERT(thread->flags & _PR_ON_PAUSEQ);
+
+ qp = qp->next;
+
+ if (thread->md.missedIONotify) {
+ thread->md.missedIONotify = PR_FALSE;
+ DoneWaitingOnThisThread(thread);
+ }
+
+ if (thread->md.missedAsyncNotify) {
+ thread->md.missedAsyncNotify = PR_FALSE;
+ AsyncNotify(thread);
+ }
+ }
+ qp = _PR_SLEEPQ(me->cpu).next;
+ while (qp != &_PR_SLEEPQ(me->cpu)) {
+
+ thread = _PR_THREAD_PTR(qp);
+ PR_ASSERT(thread->flags & _PR_ON_SLEEPQ);
+
+ qp = qp->next;
+
+ if (thread->md.missedIONotify) {
+ thread->md.missedIONotify = PR_FALSE;
+ DoneWaitingOnThisThread(thread);
+ }
+
+ if (thread->md.missedAsyncNotify) {
+ thread->md.missedAsyncNotify = PR_FALSE;
+ AsyncNotify(thread);
+ }
+ }
+ _PR_SLEEPQ_UNLOCK(thread->cpu);
+}
+
+/*
+** All PR_read and PR_Write calls are synchronous from caller's perspective.
+** They are internally made asynchronous calls. This gives cpu to other
+** user threads while the async io is in progress.
+*/
+PRInt32 ReadWriteProc(PRFileDesc *fd, void *buf, PRUint32 bytes, IOOperation op)
+{
+ PRInt32 refNum = fd->secret->md.osfd;
+ OSErr err;
+ ExtendedParamBlock pbAsync;
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+ _PRCPU *cpu = _PR_MD_CURRENT_CPU();
+
+ /* quick hack to allow PR_fprintf, etc to work with stderr, stdin, stdout */
+ /* note, if a user chooses "seek" or the like as an operation in another function */
+ /* this will not work */
+ if (refNum >= 0 && refNum < 3)
+ {
+ switch (refNum)
+ {
+ case 0:
+ /* stdin - not on a Mac for now */
+ err = paramErr;
+ goto ErrorExit;
+ break;
+ case 1: /* stdout */
+ case 2: /* stderr */
+ puts(buf);
+ break;
+ }
+
+ return (bytes);
+ }
+ else
+ {
+ static IOCompletionUPP sCompletionUPP = NULL;
+
+ PRBool doingAsync = PR_FALSE;
+
+ /* allocate the callback Universal Procedure Pointer (UPP). This actually allocates
+ a 32 byte Ptr in the heap, so only do this once
+ */
+ if (!sCompletionUPP)
+ sCompletionUPP = NewIOCompletionUPP((IOCompletionProcPtr)&AsyncIOCompletion);
+
+ /* grab the thread so we know which one to post to at completion */
+ pbAsync.thread = me;
+
+ pbAsync.pb.ioParam.ioCompletion = sCompletionUPP;
+ pbAsync.pb.ioParam.ioResult = noErr;
+ pbAsync.pb.ioParam.ioRefNum = refNum;
+ pbAsync.pb.ioParam.ioBuffer = buf;
+ pbAsync.pb.ioParam.ioReqCount = bytes;
+ pbAsync.pb.ioParam.ioPosMode = fsAtMark;
+ pbAsync.pb.ioParam.ioPosOffset = 0;
+
+ /*
+ ** Issue the async read call and wait for the io semaphore associated
+ ** with this thread.
+ ** Async file system calls *never* return error values, so ignore their
+ ** results (see <http://developer.apple.com/technotes/fl/fl_515.html>);
+ ** the completion routine is always called.
+ */
+ me->io_fd = refNum;
+ me->md.osErrCode = noErr;
+ if (op == READ_ASYNC)
+ {
+ /*
+ ** Skanky optimization so that reads < 20K are actually done synchronously
+ ** to optimize performance on small reads (e.g. registry reads on startup)
+ */
+ if ( bytes > 20480L )
+ {
+ doingAsync = PR_TRUE;
+ me->io_pending = PR_TRUE;
+
+ (void)PBReadAsync(&pbAsync.pb);
+ }
+ else
+ {
+ pbAsync.pb.ioParam.ioCompletion = NULL;
+ me->io_pending = PR_FALSE;
+
+ err = PBReadSync(&pbAsync.pb);
+ if (err != noErr && err != eofErr)
+ goto ErrorExit;
+ }
+ }
+ else
+ {
+ doingAsync = PR_TRUE;
+ me->io_pending = PR_TRUE;
+
+ /* writes are currently always async */
+ (void)PBWriteAsync(&pbAsync.pb);
+ }
+
+ if (doingAsync) {
+ WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
+ }
+ }
+
+ err = me->md.osErrCode;
+ if (err != noErr)
+ goto ErrorExit;
+
+ err = pbAsync.pb.ioParam.ioResult;
+ if (err != noErr && err != eofErr)
+ goto ErrorExit;
+
+ return pbAsync.pb.ioParam.ioActCount;
+
+ErrorExit:
+ me->md.osErrCode = err;
+ _MD_SetError(err);
+ return -1;
+}
+
+/*
+Special WriteSyncProc for logging only. IO occurs synchronously. Otherwise,
+logging internal to NSPR causes ReadWriteProc above to recurse on PR_WaitSem logging.
+*/
+PRInt32 WriteSyncProc(PRFileDesc *fd, void *buf, PRUint32 bytes)
+{
+ PRInt32 refNum = fd->secret->md.osfd;
+ OSErr err;
+ ParamBlockRec pb;
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+
+ if (refNum >= 0 && refNum < 3)
+ {
+ PR_ASSERT(FALSE); /* writing to these is hazardous to a Mac's health (refNum 2 is the system file) */
+ err = paramErr;
+ goto ErrorExit;
+ }
+
+ pb.ioParam.ioCompletion = NULL;
+ pb.ioParam.ioResult = noErr;
+ pb.ioParam.ioRefNum = refNum;
+ pb.ioParam.ioBuffer = buf;
+ pb.ioParam.ioReqCount = bytes;
+ pb.ioParam.ioPosMode = fsAtMark;
+ pb.ioParam.ioPosOffset = 0;
+
+ err = PBWriteSync(&pb);
+
+ if (err != noErr)
+ goto ErrorExit;
+ else
+ return pb.ioParam.ioActCount;
+
+ErrorExit:
+ me->md.osErrCode = err;
+ _MD_SetError(err);
+ return -1;
+}
+
+/* File I/O functions called by PR I/O routines */
+PRInt32 _MD_Open(const char *path, PRIntn flags, int mode)
+{
+// Macintosh doesn't really have mode bits, just drop them
+#pragma unused (mode)
+
+ OSErr err;
+ HParamBlockRec hpb;
+ ParamBlockRec pb;
+ char *macFileName = NULL;
+ Str255 pascalName;
+ PRInt8 perm;
+
+ err = ConvertUnixPathToMacPath(path, &macFileName);
+
+ if (err != noErr)
+ goto ErrorExit;
+
+ hpb.ioParam.ioCompletion = NULL;
+ PStrFromCStr(macFileName, pascalName);
+ PR_DELETE(macFileName);
+ hpb.ioParam.ioNamePtr = pascalName;
+ hpb.ioParam.ioVRefNum = 0;
+ hpb.ioParam.ioVersNum = 0;
+ hpb.fileParam.ioDirID = 0;
+
+ if (flags & PR_RDWR)
+ perm = fsRdWrPerm;
+ else if (flags & PR_WRONLY)
+ perm = fsWrPerm;
+ else
+ perm = fsRdPerm;
+ hpb.ioParam.ioPermssn = perm;
+
+
+ if (flags & PR_CREATE_FILE) {
+ err = PBHCreateSync(&hpb);
+
+ /* If opening with the PR_EXCL flag the existence of the file prior to opening is an error */
+ if ((flags & PR_EXCL) && (err == dupFNErr)) {
+ err = PR_FILE_EXISTS_ERROR;
+ goto ErrorExit;
+ }
+
+ if ((err != noErr) && (err != dupFNErr))
+ goto ErrorExit;
+ }
+
+ err = PBHOpenDFSync(&hpb);
+
+ if (err != noErr)
+ goto ErrorExit;
+
+ if (flags & PR_TRUNCATE) {
+ pb.ioParam.ioCompletion = NULL;
+ pb.ioParam.ioRefNum = hpb.ioParam.ioRefNum;
+ pb.ioParam.ioMisc = NULL;
+ err = PBSetEOFSync(&pb);
+ if (err != noErr)
+ goto ErrorExit;
+ } else if (flags & PR_APPEND) {
+ pb.ioParam.ioCompletion = NULL;
+ pb.ioParam.ioRefNum = hpb.ioParam.ioRefNum;
+ pb.ioParam.ioPosMode = fsFromLEOF;
+ pb.ioParam.ioPosOffset = 0;
+ err = PBSetFPosSync(&pb);
+ if (err != noErr)
+ goto ErrorExit;
+ }
+ return hpb.ioParam.ioRefNum;
+
+ErrorExit:
+ _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
+ _MD_SetError(err);
+ return -1;
+}
+
+/* _MD_CLOSE_FILE, _MD_READ, _MD_WRITE, _MD_GET_FILE_ERROR are defined in _macos.h */
+
+PROffset32 _MD_LSeek(PRFileDesc *fd, PROffset32 offset, PRSeekWhence how)
+{
+ PRInt32 refNum = fd->secret->md.osfd;
+ OSErr err = noErr;
+ long curPos, endPos;
+
+ /* compute new mark */
+ switch (how) {
+ case PR_SEEK_SET:
+ endPos = offset;
+ break;
+
+ case PR_SEEK_CUR:
+ err = GetFPos(refNum, &curPos);
+ endPos = curPos + offset;
+ break;
+
+ case PR_SEEK_END:
+ err = GetEOF(refNum, &curPos);
+ endPos = curPos + offset;
+ break;
+
+ default:
+ err = paramErr;
+ break;
+ }
+
+ /* set the new mark and extend the file if seeking beyond current EOF */
+ /* making sure to set the mark after any required extend */
+ if (err == noErr) {
+ err = SetFPos(refNum, fsFromStart, endPos);
+ if (err == eofErr) {
+ err = SetEOF(refNum, endPos);
+ if (err == noErr) {
+ err = SetFPos(refNum, fsFromStart, endPos);
+ }
+ }
+ }
+
+ if (err == noErr) {
+ return endPos;
+ } else {
+ _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
+ _MD_SetError(err);
+ return -1;
+ }
+}
+
+PRInt32 _MD_FSync(PRFileDesc *fd)
+{
+ PRInt32 refNum = fd->secret->md.osfd;
+ OSErr err;
+ ParamBlockRec pb;
+
+ pb.ioParam.ioCompletion = NULL;
+ pb.ioParam.ioRefNum = refNum;
+
+ err = PBFlushFileSync(&pb);
+ if (err != noErr)
+ goto ErrorExit;
+
+ return 0;
+
+ErrorExit:
+ _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
+ _MD_SetError(err);
+ return -1;
+}
+
+#include "plstr.h"
+
+PRStatus _MD_OpenDir(_MDDir *mdDir,const char *name)
+{
+ // Emulate the Unix opendir() routine.
+
+ OSErr err;
+ CInfoPBRec pb;
+ char *macDirName = NULL;
+ char *position = NULL;
+ char volumeName[32];
+ Str255 pascalName;
+
+ // Get the Macintosh path
+ err = ConvertUnixPathToMacPath(name, &macDirName);
+ if (err != noErr)
+ goto ErrorExit;
+
+ // Get the vRefNum
+ position = PL_strchr(macDirName, PR_PATH_SEPARATOR);
+ if ((position == macDirName) || (position == NULL))
+ mdDir->ioVRefNum = 0; // Use application relative searching
+ else {
+ memset(volumeName, 0, sizeof(volumeName));
+ strncpy(volumeName, macDirName, position-macDirName);
+ mdDir->ioVRefNum = GetVolumeRefNumFromName(volumeName);
+ }
+
+ // Get info about the object.
+ PStrFromCStr(macDirName, pascalName);
+ PR_DELETE(macDirName);
+
+ pb.dirInfo.ioNamePtr = pascalName;
+ pb.dirInfo.ioVRefNum = mdDir->ioVRefNum;
+ pb.dirInfo.ioDrDirID = 0;
+ pb.dirInfo.ioFDirIndex = 0;
+ err = PBGetCatInfoSync(&pb);
+ if (err != noErr)
+ goto ErrorExit;
+
+ // Are we dealing with a directory?
+ if ((pb.dirInfo.ioFlAttrib & ioDirMask) == 0) {
+ err = dirNFErr;
+ goto ErrorExit;
+ }
+
+ /* This is a directory, store away the pertinent information.
+ ** We post increment. I.e. index is always the nth. item we
+ ** should get on the next call
+ */
+ mdDir->ioDirID = pb.dirInfo.ioDrDirID;
+ mdDir->currentEntryName = NULL;
+ mdDir->ioFDirIndex = 1;
+ return PR_SUCCESS;
+
+ErrorExit:
+ _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
+ _MD_SetError(err);
+ return PR_FAILURE;
+}
+
+char *_MD_ReadDir(_MDDir *mdDir, PRIntn flags)
+{
+ // Emulate the Unix readdir() routine.
+
+ // Mac doesnÕt have the concept of .(PR_SKIP_DOT) & ..(PR_SKIP_DOT_DOT)
+
+ OSErr err;
+ CInfoPBRec pb;
+ char *returnedCStr;
+ Str255 pascalName = "\p";
+ PRBool foundEntry;
+
+ PR_ASSERT(mdDir != NULL);
+
+ do {
+
+ // Release the last name read.
+ PR_DELETE(mdDir->currentEntryName);
+ mdDir->currentEntryName = NULL;
+
+ // WeÕve got all the info we need, just get info about this guy.
+ pb.hFileInfo.ioNamePtr = pascalName;
+ pb.hFileInfo.ioVRefNum = mdDir->ioVRefNum;
+ pb.hFileInfo.ioFDirIndex = mdDir->ioFDirIndex;
+ pb.hFileInfo.ioDirID = mdDir->ioDirID;
+ err = PBGetCatInfoSync(&pb);
+ if (err != noErr)
+ goto ErrorExit;
+
+ // Convert the Pascal string to a C string (actual allocation occurs in CStrFromPStr)
+ CStrFromPStr(pascalName, &returnedCStr);
+
+ mdDir->currentEntryName = returnedCStr;
+ mdDir->ioFDirIndex++;
+
+ // If it is not a hidden file and the flags did not specify skipping, we are done.
+ if ((flags & PR_SKIP_HIDDEN) && (pb.hFileInfo.ioFlFndrInfo.fdFlags & fInvisible))
+ foundEntry = PR_FALSE;
+ else
+ foundEntry = PR_TRUE;
+
+ } while (!foundEntry);
+
+ return (mdDir->currentEntryName);
+
+ErrorExit:
+ _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
+ _MD_SetError(err);
+ return NULL;
+}
+
+
+void _MD_CloseDir(_MDDir *mdDir)
+{
+ // Emulate the Unix closedir() routine
+
+ PR_DELETE(mdDir->currentEntryName);
+}
+
+PRInt32 _MD_MkDir(char *unixPath, PRIntn mode)
+{
+ HFileParam fpb;
+ Str255 pascalName = "\p";
+ char *cMacPath = NULL;
+ OSErr err;
+
+ #pragma unused (mode) // Mode is ignored on the Mac
+
+ if (unixPath) {
+ err = ConvertUnixPathToMacPath(unixPath, &cMacPath);
+ if (err != noErr)
+ goto ErrorExit;
+
+ PStrFromCStr(cMacPath, pascalName);
+ PR_DELETE(cMacPath);
+ fpb.ioNamePtr = pascalName;
+ fpb.ioVRefNum = 0;
+ fpb.ioDirID = 0L;
+
+ err = PBDirCreateSync((HParmBlkPtr)&fpb);
+ if (err != noErr)
+ goto ErrorExit;
+ }
+
+ return 0;
+
+ErrorExit:
+ _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
+ _MD_SetError(err);
+ return -1;
+}
+
+PRInt32 _MD_Delete(char *unixPath)
+{
+ HFileParam fpb;
+ Str255 pascalName = "\p";
+ char *cMacPath = NULL;
+ OSErr err;
+
+ if (unixPath) {
+ err = ConvertUnixPathToMacPath(unixPath, &cMacPath);
+ if (err != noErr)
+ goto ErrorExit;
+
+ PStrFromCStr(cMacPath, pascalName);
+ PR_DELETE(cMacPath);
+ fpb.ioNamePtr = pascalName;
+ fpb.ioVRefNum = 0;
+ fpb.ioDirID = 0L;
+
+ err = PBHDeleteSync((HParmBlkPtr)&fpb);
+ if (err != noErr)
+ goto ErrorExit;
+ }
+
+ return 0;
+
+ErrorExit:
+ _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
+ _MD_SetError(err);
+ return -1;
+}
+
+PRInt32 _MD_Rename(char *fromUnixPath, char *toUnixPath)
+{
+ OSErr err;
+ FSSpec fromSpec;
+ FSSpec toSpec;
+ FSSpec destDirSpec;
+ FSSpec beforeRenameSpec;
+
+ if (fromUnixPath && toUnixPath) {
+ err = ConvertUnixPathToFSSpec(fromUnixPath, &fromSpec);
+ if (err != noErr)
+ goto ErrorExit;
+
+ err = ConvertUnixPathToFSSpec(toUnixPath, &toSpec);
+ if (err != noErr && err != fnfErr)
+ goto ErrorExit;
+
+ /* make an FSSpec for the destination directory */
+ err = FSMakeFSSpec(toSpec.vRefNum, toSpec.parID, nil, &destDirSpec);
+ if (err != noErr) /* parent directory must exist */
+ goto ErrorExit;
+
+ // move it to the directory specified
+ err = FSpCatMove(&fromSpec, &destDirSpec);
+ if (err != noErr)
+ goto ErrorExit;
+
+ // make a new FSSpec for the file or directory in its new location
+ err = FSMakeFSSpec(toSpec.vRefNum, toSpec.parID, fromSpec.name, &beforeRenameSpec);
+ if (err != noErr)
+ goto ErrorExit;
+
+ // rename the file or directory
+ err = FSpRename(&beforeRenameSpec, toSpec.name);
+ if (err != noErr)
+ goto ErrorExit;
+
+ } else {
+ err = paramErr;
+ goto ErrorExit;
+ }
+
+ return 0;
+
+ErrorExit:
+ _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
+ _MD_SetError(err);
+ return -1;
+}
+
+#define kWriteAccessAllowed (0x100)
+PRInt32 _MD_Access(char *unixPath, int amode)
+{
+ //
+ // Emulate the Unix access routine
+ //
+
+ OSErr err;
+ CInfoPBRec pb;
+ FCBPBRec fcbpb;
+ char *cMacPath = NULL;
+ Str255 pascalMacPath;
+ struct stat info;
+
+ // Convert to a Mac style path
+ err = ConvertUnixPathToMacPath(unixPath, &cMacPath);
+ if (err != noErr)
+ goto ErrorExit;
+
+ err = stat(cMacPath, &info);
+ if (err != noErr)
+ goto ErrorExit;
+
+
+ // If all weÕre doing is checking for the existence of the file, weÕre out of here.
+ // On the Mac, if a file exists, you can read from it.
+ // This doesnÕt handle remote AppleShare volumes. Does it need to?
+ if ((amode == PR_ACCESS_EXISTS) || (amode == PR_ACCESS_READ_OK)) {
+ goto success;
+ }
+
+ PStrFromCStr(cMacPath, pascalMacPath);
+
+ pb.hFileInfo.ioNamePtr = pascalMacPath;
+ pb.hFileInfo.ioVRefNum = info.st_dev;
+ pb.hFileInfo.ioDirID = 0;
+ pb.hFileInfo.ioFDirIndex = 0;
+
+ err = PBGetCatInfoSync(&pb);
+ if (err != noErr)
+ goto ErrorExit;
+ // Check out all the access permissions.
+
+ if (amode == PR_ACCESS_WRITE_OK) {
+ fcbpb.ioNamePtr = NULL;
+ fcbpb.ioVRefNum = pb.hFileInfo.ioVRefNum;
+ fcbpb.ioRefNum = pb.hFileInfo.ioFRefNum;
+ fcbpb.ioFCBIndx = 0;
+
+ err = PBGetFCBInfoSync(&fcbpb);
+ if (err != noErr)
+ goto ErrorExit;
+
+ /* Look at Inside Mac IV-180 */
+ if ((fcbpb.ioFCBFlags & kWriteAccessAllowed) == 0) {
+ err = permErr;
+ goto ErrorExit;
+ }
+ }
+
+success:
+ PR_DELETE(cMacPath);
+ return 0;
+
+ErrorExit:
+ if (cMacPath != NULL)
+ PR_DELETE(cMacPath);
+ _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
+ _MD_SetError(err);
+ return -1;
+}
+
+PRInt32 _MD_GetFileInfo(char *unixPath, PRFileInfo *info)
+{
+ CInfoPBRec pb;
+ OSErr err;
+ char *cMacPath = NULL;
+ Str255 pascalMacPath;
+ PRTime oneMillion, dateInMicroSeconds;
+
+ // Convert to a Mac style path
+ err = ConvertUnixPathToMacPath(unixPath, &cMacPath);
+ if (err != noErr)
+ goto ErrorExit;
+
+ PStrFromCStr(cMacPath, pascalMacPath);
+ PR_DELETE(cMacPath);
+
+ pb.hFileInfo.ioNamePtr = pascalMacPath;
+ pb.hFileInfo.ioVRefNum = 0;
+ pb.hFileInfo.ioDirID = 0;
+ pb.hFileInfo.ioFDirIndex = 0;
+
+ err = PBGetCatInfoSync(&pb);
+ if (err != noErr)
+ goto ErrorExit;
+
+ if (pb.hFileInfo.ioFlAttrib & ioDirMask) {
+ info->type = PR_FILE_DIRECTORY;
+ info->size = 0;
+ } else {
+ info->type = PR_FILE_FILE;
+ info->size = pb.hFileInfo.ioFlLgLen + pb.hFileInfo.ioFlRLgLen;
+ }
+
+ pb.hFileInfo.ioFlCrDat -= gJanuaryFirst1970Seconds;
+ LL_I2L(dateInMicroSeconds, pb.hFileInfo.ioFlCrDat);
+ LL_I2L(oneMillion, PR_USEC_PER_SEC);
+ LL_MUL(info->creationTime, oneMillion, dateInMicroSeconds);
+
+ pb.hFileInfo.ioFlMdDat -= gJanuaryFirst1970Seconds;
+ LL_I2L(dateInMicroSeconds, pb.hFileInfo.ioFlMdDat);
+ LL_MUL(info->modifyTime, oneMillion, dateInMicroSeconds);
+
+ return 0;
+
+ErrorExit:
+ _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
+ _MD_SetError(err);
+ return -1;
+}
+
+PRInt32 _MD_GetOpenFileInfo(const PRFileDesc *fd, PRFileInfo *info)
+{
+ OSErr err;
+ FCBPBRec fcbpb;
+ CInfoPBRec pb;
+ Str255 pascalMacPath;
+ PRTime oneMillion, dateInMicroSeconds;
+
+ fcbpb.ioNamePtr = pascalMacPath;
+ fcbpb.ioVRefNum = 0;
+ fcbpb.ioRefNum = fd->secret->md.osfd;
+ fcbpb.ioFCBIndx = 0;
+
+ err = PBGetFCBInfoSync(&fcbpb);
+ if (err != noErr)
+ goto ErrorExit;
+
+ info->type = PR_FILE_FILE;
+ info->size = fcbpb.ioFCBEOF;
+
+ pb.hFileInfo.ioNamePtr = pascalMacPath;
+ pb.hFileInfo.ioVRefNum = fcbpb.ioFCBVRefNum;
+ pb.hFileInfo.ioDirID = fcbpb.ioFCBParID;
+ pb.hFileInfo.ioFDirIndex = 0;
+
+ err = PBGetCatInfoSync(&pb);
+ if (err != noErr)
+ goto ErrorExit;
+
+ pb.hFileInfo.ioFlCrDat -= gJanuaryFirst1970Seconds;
+ LL_I2L(dateInMicroSeconds, pb.hFileInfo.ioFlCrDat);
+ LL_I2L(oneMillion, PR_USEC_PER_SEC);
+ LL_MUL(info->creationTime, oneMillion, dateInMicroSeconds);
+
+ pb.hFileInfo.ioFlMdDat -= gJanuaryFirst1970Seconds;
+ LL_I2L(dateInMicroSeconds, pb.hFileInfo.ioFlMdDat);
+ LL_MUL(info->modifyTime, oneMillion, dateInMicroSeconds);
+
+ return 0;
+
+ErrorExit:
+ _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
+ _MD_SetError(err);
+ return -1;
+}
+
+PRInt32 _MD_Stat(const char *path, struct stat *buf)
+{
+ OSErr err;
+ char *macFileName = NULL;
+
+ err = ConvertUnixPathToMacPath(path, &macFileName);
+ if (err != noErr)
+ goto ErrorExit;
+
+ err = stat(macFileName, buf);
+ if (err != noErr)
+ goto ErrorExit;
+
+ PR_DELETE(macFileName);
+
+ return 0;
+
+ErrorExit:
+ _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
+ _MD_SetError(err);
+ return -1;
+}
+
+PRStatus _MD_LockFile(PRInt32 fd)
+{
+ OSErr err;
+ FCBPBRec fcbpb;
+ HFileParam fpb;
+ Str255 pascalName;
+
+ fcbpb.ioNamePtr = pascalName;
+ fcbpb.ioVRefNum = 0;
+ fcbpb.ioRefNum = fd;
+ fcbpb.ioFCBIndx = 0;
+
+ err = PBGetFCBInfoSync(&fcbpb);
+ if (err != noErr)
+ goto ErrorExit;
+
+ fpb.ioCompletion = NULL;
+ fpb.ioNamePtr = pascalName;
+ fpb.ioVRefNum = fcbpb.ioFCBVRefNum;
+ fpb.ioDirID = fcbpb.ioFCBParID;
+
+ err = PBHSetFLockSync((HParmBlkPtr)&fpb);
+ if (err != noErr)
+ goto ErrorExit;
+
+ return PR_SUCCESS;
+
+ErrorExit:
+ _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
+ _MD_SetError(err);
+ return PR_FAILURE;
+}
+
+PRStatus _MD_TLockFile(PRInt32 fd)
+{
+ return (_MD_LockFile(fd));
+}
+
+PRStatus _MD_UnlockFile(PRInt32 fd)
+{
+ OSErr err;
+ FCBPBRec fcbpb;
+ HFileParam fpb;
+ Str255 pascalName;
+
+ fcbpb.ioNamePtr = pascalName;
+ fcbpb.ioVRefNum = 0;
+ fcbpb.ioRefNum = fd;
+ fcbpb.ioFCBIndx = 0;
+
+ err = PBGetFCBInfoSync(&fcbpb);
+ if (err != noErr)
+ goto ErrorExit;
+
+ fpb.ioCompletion = NULL;
+ fpb.ioNamePtr = pascalName;
+ fpb.ioVRefNum = fcbpb.ioFCBVRefNum;
+ fpb.ioDirID = fcbpb.ioFCBParID;
+
+ err = PBHRstFLockSync((HParmBlkPtr)&fpb);
+ if (err != noErr)
+ goto ErrorExit;
+
+ return PR_SUCCESS;
+
+ErrorExit:
+ _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
+ _MD_SetError(err);
+ return PR_FAILURE;
+}
+
+void SetLogFileTypeCreator(const char *logFile)
+{
+ HParamBlockRec pb;
+ OSErr err;
+ Str31 pName;
+
+ PStrFromCStr(logFile, pName);
+ pb.fileParam.ioCompletion = nil;
+ pb.fileParam.ioNamePtr = pName;
+ pb.fileParam.ioVRefNum = 0;
+ pb.fileParam.ioFDirIndex = 0;
+ pb.fileParam.ioDirID = 0;
+ err = PBHGetFInfoSync(&pb);
+ PR_ASSERT(err == noErr);
+
+ pb.fileParam.ioDirID = 0;
+ pb.fileParam.ioFlFndrInfo.fdType = 'TEXT';
+ pb.fileParam.ioFlFndrInfo.fdCreator = 'ttxt';
+ err = PBHSetFInfoSync(&pb);
+ PR_ASSERT(err == noErr);
+}
+
+#if DEVELOPER_DEBUG
+PR_IMPLEMENT (void)
+SetupMacPrintfLog(char *logFile)
+{
+ /*
+ * We do _PR_InitLog() twice. The first to force the implicit initialization which
+ * will set logging to highest levels in _MD_EARLY_INIT. Then, change the env variable
+ * to disable kernel logging and call _PR_InitLog() again to make it effective. Since
+ * we are using logging to log test program output, we disable kernel logging to avoid
+ * all Kernel logging output.
+ */
+#ifdef PR_INTERNAL_LOGGING
+ _PR_InitLog();
+ _MD_PutEnv("NSPR_LOG_MODULES=clock:0,cmon:0,io:0,mon:0,linker:0,cvar:0,sched:0,thread:0");
+ _PR_InitLog();
+#endif
+ PR_ASSERT(PR_SetLogFile(logFile) == PR_TRUE);
+
+ SetLogFileTypeCreator(logFile);
+}
+#endif
+
+
+/*
+********************** Old name related stuff that is unchanged. **********************
+*/
+
+#if !defined(MAC_NSPR_STANDALONE)
+
+short GetVolumeRefNumFromName(const char *cTgtVolName)
+{
+ OSErr err;
+ Str32 pVolName;
+ char *cVolName = NULL;
+ HParamBlockRec hPB;
+ short refNum = 0;
+
+ hPB.volumeParam.ioVolIndex = 0;
+ hPB.volumeParam.ioNamePtr = pVolName;
+ do {
+ hPB.volumeParam.ioVolIndex++;
+ err = PBHGetVInfoSync(&hPB);
+ CStrFromPStr(pVolName, &cVolName);
+ if (strcmp(cTgtVolName, cVolName) == 0) {
+ refNum = hPB.volumeParam.ioVRefNum;
+ PR_DELETE(cVolName);
+ break;
+ }
+ PR_DELETE(cVolName);
+ } while (err == noErr);
+
+ return refNum;
+}
+
+static OSErr CreateMacPathFromUnixPath(const char *unixPath, char **macPath)
+{
+ // Given a Unix style path with '/' directory separators, this allocates
+ // a path with Mac style directory separators in the path.
+ //
+ // It does not do any special directory translation; use ConvertUnixPathToMacPath
+ // for that.
+
+ const char *src;
+ char *tgt;
+ OSErr err = noErr;
+
+ PR_ASSERT(unixPath != nil);
+ if (nil == unixPath) {
+ err = paramErr;
+ goto exit;
+ }
+
+ // If unixPath is a zero-length string, we copy ":" into
+ // macPath, so we need a minimum of two bytes to handle
+ // the case of ":".
+ *macPath = malloc(strlen(unixPath) + 2); // Will be enough extra space.
+ require_action (*macPath != NULL, exit, err = memFullErr;);
+
+ src = unixPath;
+ tgt = *macPath;
+
+ if (PL_strchr(src, PR_DIRECTORY_SEPARATOR) == src) // If weÕre dealing with an absolute
+ src++; // path, skip the separator
+ else
+ *(tgt++) = PR_PATH_SEPARATOR;
+
+ if (PL_strstr(src, UNIX_THIS_DIRECTORY_STR) == src) // If it starts with /
+ src += 2; // skip it.
+
+ while (*src)
+ { // deal with the rest of the path
+ if (PL_strstr(src, UNIX_PARENT_DIRECTORY_STR) == src) { // Going up?
+ *(tgt++) = PR_PATH_SEPARATOR; // simply add an extra colon.
+ src +=3;
+ }
+ else if (*src == PR_DIRECTORY_SEPARATOR) { // Change the separator
+ *(tgt++) = PR_PATH_SEPARATOR;
+ src++;
+ }
+ else
+ *(tgt++) = *(src++);
+ }
+
+ *tgt = NULL; // make sure itÕs null terminated.
+
+exit:
+ return err;
+}
+
+
+static ProcessInfoRec gNavigatorProcInfo;
+static FSSpec gGutsFolder;
+static FSSpec gNetscapeFolder;
+
+static OSErr SetupRequiredFSSpecs(void)
+{
+ OSErr err;
+ CInfoPBRec pb;
+ ProcessSerialNumber curPSN = {0, kCurrentProcess};
+
+ gNavigatorProcInfo.processInfoLength = sizeof(ProcessInfoRec);
+ gNavigatorProcInfo.processName = NULL;
+ gNavigatorProcInfo.processAppSpec = &gNetscapeFolder;
+
+ err = GetProcessInformation (&curPSN, &gNavigatorProcInfo);
+ if (err != noErr)
+ goto ErrorExit;
+
+ /* guts folder resides at the same place as the app file itself */
+ gGutsFolder = gNetscapeFolder;
+ /* How else do we do this hack???
+ * Should NSPR have a string resource for this ?
+ */
+ GetIndString( gGutsFolder.name, 300, 34);
+
+ /*
+ * vRefNum and parentDirID are now set up correctly for the app file itself.
+ * parentDirID is the Netscape Folder's ID. Then Find it's parent ID to
+ * set up the FSSpec and its own name.
+ */
+
+ pb.dirInfo.ioCompletion = NULL;
+ pb.dirInfo.ioNamePtr = gNetscapeFolder.name;
+ pb.dirInfo.ioVRefNum = gNetscapeFolder.vRefNum;
+ pb.dirInfo.ioFDirIndex = -1;
+ pb.dirInfo.ioDrDirID = gNetscapeFolder.parID;
+
+ err = PBGetCatInfoSync(&pb);
+ if (err != noErr)
+ goto ErrorExit;
+
+ gNetscapeFolder.parID = pb.dirInfo.ioDrParID;
+
+ return noErr;
+
+ErrorExit:
+ return err;
+}
+
+static OSErr FindGutsFolder(FSSpec *foundSpec)
+{
+ OSErr err;
+
+ if (gNavigatorProcInfo.processInfoLength == 0) { /* Uninitialized? */
+ err = SetupRequiredFSSpecs();
+ if (err != noErr)
+ goto ErrorExit;
+ }
+
+ *foundSpec = gGutsFolder;
+
+ return noErr;
+
+ErrorExit:
+ _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
+ return err;
+}
+
+static OSErr FindNetscapeFolder(FSSpec *foundSpec)
+{
+ OSErr err;
+
+ if (gNavigatorProcInfo.processInfoLength == 0) { /* Uninitialized? */
+ err = SetupRequiredFSSpecs();
+ if (err != noErr)
+ goto ErrorExit;
+ }
+
+ *foundSpec = gNetscapeFolder;
+
+ return noErr;
+
+ErrorExit:
+ _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
+ return err;
+}
+
+
+PR_IMPLEMENT (OSErr)
+ConvertUnixPathToMacPath(const char *unixPath, char **macPath)
+{
+ OSErr err = noErr;
+
+ // ******** HACK ALERT ********
+ //
+ // Java really wants long file names (>31 chars). We truncate file names
+ // greater than 31 characters long. Truncation is from the middle.
+ //
+ // Convert UNIX style path names (with . and / separators) into a Macintosh
+ // style path (with :).
+ //
+ // There are also a couple of special paths that need to be dealt with
+ // by translating them to the appropriate Mac special folders. These include:
+ //
+ // /usr/tmp/file => {TempFolder}file
+ //
+ // The file conversions we need to do are as follows:
+ //
+ // file => file
+ // dir/file => :dir:file
+ // ./file => file
+ // ../file => ::file
+ // ../dir/file => ::dir:file
+ // /file => ::BootDrive:file
+ // /dir/file => ::BootDrive:dir:file
+
+
+ if (!strcmp(unixPath, "."))
+ {
+ *macPath = malloc(sizeof(":"));
+ if (*macPath == NULL)
+ err = memFullErr;
+ (*macPath)[0] = ':';
+ (*macPath)[1] = '\0';
+ }
+ else
+
+ if (*unixPath != PR_DIRECTORY_SEPARATOR) { // Not root relative, just convert it.
+ err = CreateMacPathFromUnixPath(unixPath, macPath);
+ }
+
+ else {
+ // WeÕre root-relative. This is either a special Unix directory, or a
+ // full path (which weÕll support on the Mac since they might be generated).
+ // This is not condoning the use of full-paths on the Macintosh for file
+ // specification.
+
+ FSSpec foundSpec;
+ short pathBufferSize;
+#if DEBUG
+ char *temp;
+#endif
+ int tempLen;
+
+ // Are we dealing with the temp folder?
+ if ((strncmp(unixPath, "/usr/tmp", strlen("/usr/tmp")) == 0) ||
+ ((strncmp(unixPath, "/tmp", strlen("/tmp")) == 0))) {
+ CInfoPBRec pb;
+
+ unixPath = PL_strchr(unixPath, PR_DIRECTORY_SEPARATOR);
+ if (strncmp(unixPath, "/tmp", strlen("/tmp")) == 0) // skip past temp spec
+ unixPath += 5;
+ else
+ unixPath += 9;
+
+ err = FindFolder(kOnSystemDisk, kTemporaryFolderType, kCreateFolder, // Create if needed
+ &foundSpec.vRefNum, &foundSpec.parID);
+ if (err == noErr) {
+ pb.dirInfo.ioCompletion = NULL;
+ pb.dirInfo.ioNamePtr = foundSpec.name;
+ pb.dirInfo.ioVRefNum = foundSpec.vRefNum;
+ pb.dirInfo.ioFDirIndex = -1;
+ pb.dirInfo.ioDrDirID = foundSpec.parID;
+
+ err = PBGetCatInfoSync(&pb);
+ foundSpec.parID = pb.dirInfo.ioDrParID;
+ }
+ }
+
+ else if (!strncmp(unixPath, "/usr/local/netscape/", (tempLen = strlen("/usr/local/netscape/")))) {
+
+ unixPath += tempLen;
+
+ if (!strncmp(unixPath, "RequiredGuts/", (tempLen = strlen("RequiredGuts/"))))
+ {
+ unixPath += tempLen;
+ err = FindGutsFolder(&foundSpec);
+ }
+ else if (!strncmp(unixPath, "bin/", (tempLen = strlen("bin/"))))
+ {
+ unixPath += tempLen;
+ err = FindNetscapeFolder(&foundSpec);
+ }
+ else if (*unixPath == '\0')
+ {
+ // it's /usr/local/netscape
+ err = FindGutsFolder(&foundSpec);
+ }
+
+ }
+
+ else {
+ // This is a root relative directory, weÕll just convert the whole thing.
+ err = CreateMacPathFromUnixPath(unixPath, macPath);
+ goto Exit_ConvertUnixPathToMacPath;
+ }
+
+
+
+ // WeÕre dealing with a special folder
+ if (err == noErr)
+ {
+ Handle hPathStr;
+ // Get the path to the root-relative directory
+ err = FSpGetFullPath(&foundSpec, &pathBufferSize, &hPathStr); // NewHandle's hPathStr
+
+ if (noErr == err)
+ {
+ // convert handle to c-string
+ // add one for NULL termination
+ // pathBufferSize is now one greater than the length of the string
+ pathBufferSize++;
+
+ *macPath = (char*) malloc(sizeof(char) * pathBufferSize);
+ (*macPath)[pathBufferSize - 1] = '\0';
+ BlockMoveData(*hPathStr, *macPath, pathBufferSize - 1);
+
+ DisposeHandle(hPathStr);
+ }
+ }
+
+ if (err == noErr)
+ {
+ UInt32 unixPathLeft;
+ UInt32 macPathLen;
+
+ unixPathLeft = strlen(unixPath);
+ macPathLen = strlen(*macPath);
+
+
+ // copy over the remaining file name, converting
+ if (pathBufferSize - 1 < macPathLen + unixPathLeft)
+ {
+ // need to grow string
+ *macPath = realloc(*macPath, macPathLen + unixPathLeft + 1);
+ err = (*macPath == NULL ? memFullErr : noErr);
+ }
+
+ if (err == noErr)
+ {
+ // carefully remove the '/''s out of the unix path. If we see an "escaped" /
+ // we will leave it in there, otherwise we take it out and replace it with a :
+ // we have to do this before we convert to a mac-path, so we can tell what is
+ // really a path separator and what is in the name of a file or directory
+ // Make sure that all of the /Õs are :Õs in the final pathname
+ // effectively we do a
+ // strcat(*macPath, unixPath); while replace all occurrences of / with : in unixPath
+ char* dp;
+ const char* sp;
+
+ sp = unixPath;
+ dp = *macPath + macPathLen;
+
+ for (;*sp != '\0'; sp++, dp++)
+ {
+ if (*sp == PR_DIRECTORY_SEPARATOR)
+ {
+ // if we can look at the previous character
+ if (sp > unixPath)
+ {
+ // check to see if previous character is an escape
+ if (sp[-1] == '\\')
+ {
+ // leave it in, and cycle
+ continue;
+ }
+ else
+ {
+ *dp = PR_PATH_SEPARATOR;
+ }
+ }
+ else
+ *dp = PR_PATH_SEPARATOR;
+ }
+ else
+ {
+ // just copy;
+ *dp = *sp;
+ }
+ }
+
+ *dp = '\0'; // NULL terminate *macPath
+ }
+#if DEBUG
+ // we used to check here, now we check above, we leave this in
+ // the debug build to make sure we didn't screw up
+ // Make sure that all of the /Õs are :Õs in the final pathname
+ for (temp = *macPath + strlen(*macPath) - strlen(unixPath); *temp != '\0'; temp++) {
+
+ if (*temp == PR_DIRECTORY_SEPARATOR)
+ {
+ DebugStr("\pFound a slash");
+ *temp = PR_PATH_SEPARATOR;
+ }
+ }
+#endif
+ }
+ }
+
+
+Exit_ConvertUnixPathToMacPath:
+
+ return err;
+}
+
+// Hey! Before you delete this "hack" you should look at how it's being
+// used by sun-java/netscape/applet/appletStubs.c.
+PR_IMPLEMENT (OSErr)
+ConvertMacPathToUnixPath(const char *macPath, char **unixPath)
+{
+ // *** HACK ***
+ // Get minimal version working
+
+ char *unixPathPtr;
+
+ *unixPath = malloc(strlen(macPath) + 2); // Add one for the front slash, one for null
+ if (*unixPath == NULL)
+ return (memFullErr);
+
+ unixPathPtr = *unixPath;
+
+ *unixPathPtr++ = PR_DIRECTORY_SEPARATOR;
+
+ do {
+ // Translate all colons to slashes
+ if (*macPath == PR_PATH_SEPARATOR)
+ *unixPathPtr = PR_DIRECTORY_SEPARATOR;
+ else
+ *unixPathPtr = *macPath;
+
+ unixPathPtr++;
+ macPath++;
+ } while (*macPath != NULL);
+
+ // Terminate the string
+ *unixPathPtr = '\0';
+
+ return (noErr);
+}
+
+OSErr
+ConvertUnixPathToFSSpec(const char *unixPath, FSSpec *fileSpec)
+{
+ char* macPath;
+ OSErr convertError;
+ int len;
+
+ convertError = ConvertUnixPathToMacPath(unixPath, &macPath);
+ if (convertError != noErr)
+ return convertError;
+
+ len = strlen(macPath);
+
+ if (*macPath == PR_PATH_SEPARATOR)
+ {
+ if (len < sizeof(Str255))
+ {
+ short vRefNum;
+ long dirID;
+ Str255 pascalMacPath;
+
+ convertError = HGetVol(NULL, &vRefNum, &dirID);
+ if (convertError == noErr)
+ {
+ PStrFromCStr(macPath, pascalMacPath);
+ convertError = FSMakeFSSpec(vRefNum, dirID, pascalMacPath, fileSpec);
+ }
+ }
+ else
+ convertError = paramErr;
+ }
+ else
+ {
+ convertError = FSpLocationFromFullPath(len, macPath, fileSpec);
+ if (convertError == fnfErr)
+ {
+ CInfoPBRec pb;
+ Str255 pascalMacPath;
+ OSErr err;
+
+ PStrFromCStr(macPath, pascalMacPath);
+ /*
+ FSpLocationFromFullPath does not work for directories unless there is
+ a ":" at the end. We will make sure of an existence of a directory.
+ If so, the returned fileSpec is valid from FSpLocationFromFullPath eventhough
+ it returned an error.
+ */
+ pb.hFileInfo.ioNamePtr = pascalMacPath;
+ pb.hFileInfo.ioVRefNum = 0;
+ pb.hFileInfo.ioDirID = 0;
+ pb.hFileInfo.ioFDirIndex = 0;
+
+ err = PBGetCatInfoSync(&pb);
+ if (err == noErr)
+ convertError = noErr;
+ }
+ }
+
+ free(macPath);
+
+ return (convertError);
+}
+
+
+FILE *_OS_FOPEN(const char *filename, const char *mode)
+{
+ OSErr err = noErr;
+ char *macFileName = NULL;
+ FILE *result;
+
+ err = ConvertUnixPathToMacPath(filename, &macFileName);
+ if (err != noErr)
+ goto ErrorExit;
+
+ result = fopen(macFileName, mode);
+
+ PR_DELETE(macFileName);
+
+ return result;
+
+ErrorExit:
+ _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
+ _MD_SetError(err);
+ return NULL;
+}
+
+#else
+
+short GetVolumeRefNumFromName(const char *cTgtVolName)
+{
+ OSErr err;
+ Str32 pVolName;
+ char *cVolName = NULL;
+ HParamBlockRec hPB;
+ short refNum = 0;
+
+ hPB.volumeParam.ioVolIndex = 0;
+ hPB.volumeParam.ioNamePtr = pVolName;
+ do {
+ hPB.volumeParam.ioVolIndex++;
+ err = PBHGetVInfoSync(&hPB);
+ CStrFromPStr(pVolName, &cVolName);
+ if (strcmp(cTgtVolName, cVolName) == 0) {
+ refNum = hPB.volumeParam.ioVRefNum;
+ PR_DELETE(cVolName);
+ break;
+ }
+ PR_DELETE(cVolName);
+ } while (err == noErr);
+
+ return refNum;
+}
+
+
+
+static OSErr GetFullPath(short vRefNum, long dirID, char **fullPath, int *strSize)
+{
+ Str255 pascalDirName;
+ char cDirName[256];
+ char *tmpPath = NULL; // needed since sprintf isnÕt safe
+ CInfoPBRec myPB;
+ OSErr err = noErr;
+
+
+ // get the full path of the temp folder.
+ *strSize = 256;
+ *fullPath = NULL;
+ *fullPath = malloc(*strSize); // How big should this thing be?
+ require_action (*fullPath != NULL, errorExit, err = memFullErr;);
+
+ tmpPath = malloc(*strSize);
+ require_action (tmpPath != NULL, errorExit, err = memFullErr;);
+
+ strcpy(*fullPath, ""); // Clear C result
+ strcpy(tmpPath, "");
+ pascalDirName[0] = 0; // Clear Pascal intermediate string
+
+ myPB.dirInfo.ioNamePtr = &pascalDirName[0];
+ myPB.dirInfo.ioVRefNum = vRefNum;
+ myPB.dirInfo.ioDrParID = dirID;
+ myPB.dirInfo.ioFDirIndex = -1; // Getting info about
+
+ do {
+ myPB.dirInfo.ioDrDirID = myPB.dirInfo.ioDrParID;
+
+ err = PBGetCatInfoSync(&myPB);
+ require(err == noErr, errorExit);
+
+ // Move the name into C domain
+ memcpy(&cDirName, &pascalDirName, 256);
+ p2cstr((unsigned char *)&cDirName); // Changes in place!
+
+ if ((strlen(cDirName) + strlen(*fullPath)) > *strSize) {
+ // We need to grow the string, do it in 256 byte chunks
+ (*strSize) += 256;
+ *fullPath = PR_REALLOC(*fullPath, *strSize);
+ require_action (*fullPath != NULL, errorExit, err = memFullErr;);
+
+ tmpPath = PR_REALLOC(tmpPath, *strSize);
+ require_action (tmpPath != NULL, errorExit, err = memFullErr;);
+ }
+ sprintf(tmpPath, "%s:%s", cDirName, *fullPath);
+ strcpy(*fullPath, tmpPath);
+ } while (myPB.dirInfo.ioDrDirID != fsRtDirID);
+
+ PR_DELETE(tmpPath);
+
+ return noErr;
+
+
+errorExit:
+ PR_DELETE(*fullPath);
+ PR_DELETE(tmpPath);
+
+ return err;
+
+}
+
+static OSErr CreateMacPathFromUnixPath(const char *unixPath, char **macPath)
+{
+ // Given a Unix style path with '/' directory separators, this allocates
+ // a path with Mac style directory separators in the path.
+ //
+ // It does not do any special directory translation; use ConvertUnixPathToMacPath
+ // for that.
+
+ const char *src;
+ char *tgt;
+ OSErr err = noErr;
+
+ PR_ASSERT(unixPath != nil);
+ if (nil == unixPath) {
+ err = paramErr;
+ goto exit;
+ }
+
+ // If unixPath is a zero-length string, we copy ":" into
+ // macPath, so we need a minimum of two bytes to handle
+ // the case of ":".
+ *macPath = malloc(strlen(unixPath) + 2); // Will be enough extra space.
+ require_action (*macPath != NULL, exit, err = memFullErr;);
+
+ src = unixPath;
+ tgt = *macPath;
+
+ if (PL_strchr(src, PR_DIRECTORY_SEPARATOR) == src) // If weÕre dealing with an absolute
+ src++; // path, skip the separator
+ else
+ *(tgt++) = PR_PATH_SEPARATOR;
+
+ if (PL_strstr(src, UNIX_THIS_DIRECTORY_STR) == src) // If it starts with ./
+ src += 2; // skip it.
+
+ while (*src)
+ { // deal with the rest of the path
+ if (PL_strstr(src, UNIX_PARENT_DIRECTORY_STR) == src) { // Going up?
+ *(tgt++) = PR_PATH_SEPARATOR; // simply add an extra colon.
+ src +=3;
+ }
+ else if (*src == PR_DIRECTORY_SEPARATOR) { // Change the separator
+ *(tgt++) = PR_PATH_SEPARATOR;
+ src++;
+ }
+ else
+ *(tgt++) = *(src++);
+ }
+
+ *tgt = NULL; // make sure itÕs null terminated.
+
+exit:
+ return err;
+}
+
+static OSErr ConvertUnixPathToMacPath(const char *unixPath, char **macPath)
+{
+ OSErr err = noErr;
+
+
+ //
+ // Convert UNIX style path names (with . and / separators) into a Macintosh
+ // style path (with :).
+ //
+ // There are also a couple of special paths that need to be dealt with
+ // by translating them to the appropriate Mac special folders. These include:
+ //
+ // /usr/tmp/file => {TempFolder}file
+ //
+ // The file conversions we need to do are as follows:
+ //
+ // file => file
+ // dir/file => :dir:file
+ // ./file => file
+ // ../file => ::file
+ // ../dir/file => ::dir:file
+ // /file => ::BootDrive:file
+ // /dir/file => ::BootDrive:dir:file
+
+
+ if (*unixPath != PR_DIRECTORY_SEPARATOR) { // Not root relative, just convert it.
+ err = CreateMacPathFromUnixPath(unixPath, macPath);
+ }
+
+ else {
+ // WeÕre root-relative. This is either a special Unix directory, or a
+ // full path (which weÕll support on the Mac since they might be generated).
+ // This is not condoning the use of full-paths on the Macintosh for file
+ // specification.
+
+ short foundVRefNum;
+ long foundDirID;
+ int pathBufferSize;
+ char *temp;
+ char isNetscapeDir = false;
+
+ // Are we dealing with the temp folder?
+ if (strncmp(unixPath, "/usr/tmp", strlen("/usr/tmp")) == 0){
+ unixPath += 8;
+ if (*unixPath == PR_DIRECTORY_SEPARATOR)
+ unixPath++; // Skip the slash
+ err = FindFolder(kOnSystemDisk, kTemporaryFolderType, kCreateFolder, // Create if needed
+ &foundVRefNum, &foundDirID);
+ }
+
+ if (strncmp(unixPath, "/tmp", strlen("/tmp")) == 0) {
+ unixPath += 4; // Skip the slash
+ if (*unixPath == PR_DIRECTORY_SEPARATOR)
+ unixPath++; // Skip the slash
+ err = FindFolder(kOnSystemDisk, kTemporaryFolderType, kCreateFolder, // Create if needed
+ &foundVRefNum, &foundDirID);
+ }
+
+ else if (strncmp(unixPath, "/usr", strlen("/usr")) == 0) {
+
+ int usrNetscapePathLen;
+
+ usrNetscapePathLen = strlen("/usr/local/netscape/");
+
+ if (strncmp(unixPath, "/usr/local/netscape/", usrNetscapePathLen) == 0) {
+ unixPath += usrNetscapePathLen;
+// err = FindPreferencesFolder(&foundVRefNum, &foundDirID);
+ err = paramErr;
+ isNetscapeDir = true;
+ }
+
+ else {
+ dprintf("Unable to translate Unix file path %s to Mac path\n", unixPath);
+ err = -1;
+ goto Exit_ConvertUnixPathToMacPath;
+ }
+
+ }
+
+ else {
+ // This is a root relative directory, weÕll just convert the whole thing.
+ err = CreateMacPathFromUnixPath(unixPath, macPath);
+ goto Exit_ConvertUnixPathToMacPath;
+ }
+
+ // WeÕre dealing with a special folder
+ if (err == noErr)
+ // Get the path to the root-relative directory
+ err = GetFullPath(foundVRefNum, foundDirID, macPath, &pathBufferSize); // mallocs macPath
+
+ if (err == noErr){
+
+ // copy over the remaining file name, converting
+ if (pathBufferSize < (strlen(*macPath) + strlen(unixPath))) {
+ // need to grow string
+ *macPath = PR_REALLOC(*macPath, (strlen(*macPath) + strlen(unixPath) +
+ (isNetscapeDir ? strlen("Netscape Ä:") : 0)));
+ err = (*macPath == NULL ? memFullErr : noErr);
+ }
+
+ if (isNetscapeDir)
+ strcat(*macPath, "Netscape Ä:");
+
+ if (err == noErr)
+ strcat(*macPath, unixPath);
+
+ // Make sure that all of the /Õs are :Õs in the final pathname
+
+ for (temp = *macPath + strlen(*macPath) - strlen(unixPath); *temp != '\0'; temp++) {
+ if (*temp == PR_DIRECTORY_SEPARATOR)
+ *temp = PR_PATH_SEPARATOR;
+ }
+
+ }
+ }
+
+
+Exit_ConvertUnixPathToMacPath:
+
+ return err;
+}
+
+OSErr
+ConvertUnixPathToFSSpec(const char *unixPath, FSSpec *fileSpec)
+{
+ char* macPath;
+ OSErr convertError;
+ int len;
+
+ convertError = ConvertUnixPathToMacPath(unixPath, &macPath);
+ if (convertError != noErr)
+ return convertError;
+
+ len = strlen(macPath);
+
+ if (*macPath == PR_PATH_SEPARATOR)
+ {
+ if (len < sizeof(Str255))
+ {
+ short vRefNum;
+ long dirID;
+ Str255 pascalMacPath;
+
+ convertError = HGetVol(NULL, &vRefNum, &dirID);
+ if (convertError == noErr)
+ {
+ PStrFromCStr(macPath, pascalMacPath);
+ convertError = FSMakeFSSpec(vRefNum, dirID, pascalMacPath, fileSpec);
+ }
+ }
+ else
+ convertError = paramErr;
+ }
+ else
+ {
+ convertError = FSpLocationFromFullPath(len, macPath, fileSpec);
+ }
+
+ free(macPath);
+
+ return (convertError);
+}
+
+
+#endif
+
+/*
+ **********************************************************************
+ *
+ * Memory-mapped files are not implementable on the Mac.
+ *
+ **********************************************************************
+ */
+
+PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size)
+{
+#pragma unused (fmap, size)
+
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return PR_FAILURE;
+}
+
+PRInt32 _MD_GetMemMapAlignment(void)
+{
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return -1;
+}
+
+void * _MD_MemMap(
+ PRFileMap *fmap,
+ PROffset64 offset,
+ PRUint32 len)
+{
+#pragma unused (fmap, offset, len)
+
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return NULL;
+}
+
+PRStatus _MD_MemUnmap(void *addr, PRUint32 len)
+{
+#pragma unused (addr, len)
+
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return PR_FAILURE;
+}
+
+PRStatus _MD_CloseFileMap(PRFileMap *fmap)
+{
+#pragma unused (fmap)
+
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return PR_FAILURE;
+}
diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macio.h b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macio.h
new file mode 100644
index 00000000..06b85a9a
--- /dev/null
+++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macio.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef macio_h__
+#define macio_h__
+
+
+PR_BEGIN_EXTERN_C
+
+OSErr ConvertUnixPathToMacPath(const char *, char **);
+OSErr ConvertUnixPathToFSSpec(const char *unixPath, FSSpec *fileSpec);
+
+PR_END_EXTERN_C
+
+
+#endif /* macio_h__ */
+
diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macrng.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macrng.c
new file mode 100644
index 00000000..c869cc3d
--- /dev/null
+++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macrng.c
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+
+/* XXX are all these headers required for a call to TickCount()? */
+#include <Events.h>
+#include <OSUtils.h>
+#include <QDOffscreen.h>
+#include <PPCToolbox.h>
+#include <Processes.h>
+#include <LowMem.h>
+#include "primpl.h"
+
+extern PRSize _PR_MD_GetRandomNoise( buf, size )
+{
+ uint32 c = TickCount();
+ return _pr_CopyLowBits((void *)buf, size, &c, sizeof(c));
+}
diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macsocket.h b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macsocket.h
new file mode 100644
index 00000000..7e99faf2
--- /dev/null
+++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macsocket.h
@@ -0,0 +1,238 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef macksocket_h___
+#define macksocket_h___
+
+// macsock.h
+// Interface visible to xp code
+// C socket type definitions and routines
+// from sys/socket.h
+#include <Files.h>
+#include <OpenTptInternet.h> // All the internet typedefs
+#include <utime.h> // For timeval
+/*
+ * sleep and delay conflict with the same in unistd.h from Metrowerks. OT
+ * defines them as
+ *
+ * extern pascal void OTDelay(UInt32 seconds);
+ * extern pascal void OTIdle(void);
+ *
+ * #define sleep(x) OTDelay(x)
+ * #define delay(x) OTDelay(x)
+ */
+
+#undef sleep
+#undef delay
+
+#pragma once
+
+#include "prio.h"
+
+struct sockaddr {
+ unsigned char sa_len; /* total length */
+ unsigned char sa_family; /* address family */
+ char sa_data[14]; /* actually longer; address value */
+};
+
+// from netinet/in.h
+struct in_addr {
+ unsigned long s_addr;
+};
+
+struct sockaddr_in {
+ unsigned char sin_len;
+ unsigned char sin_family; // AF_INET
+ unsigned short sin_port;
+ struct in_addr sin_addr;
+ char sin_zero[8];
+};
+
+struct hostent {
+ char *h_name; /* official name of host */
+ char **h_aliases; /* alias list */
+ int h_addrtype; /* host address type */
+ int h_length; /* length of address */
+ char **h_addr_list; /* list of addresses from name server */
+#define h_addr h_addr_list[0] /* address, for backward compatiblity */
+};
+
+// Necessary network defines, found by grepping unix headers when XP code would not compile
+#define FIONBIO 1
+#define SOCK_STREAM 1
+#define SOCK_DGRAM 2
+#define IPPROTO_TCP INET_TCP // Default TCP protocol
+#define IPPROTO_UDP INET_UDP // Default UDP protocol
+#define INADDR_ANY kOTAnyInetAddress
+#define SOL_SOCKET XTI_GENERIC // Any type of socket
+#define SO_REUSEADDR IP_REUSEADDR
+#define SO_BROADCAST IP_BROADCAST
+#define MSG_PEEK 0x2 // Just look at a message waiting, donÕt actually read it.
+
+typedef unsigned long u_long;
+
+/* ldap.h has its own definition of fd_set */
+/* select support */
+#if !defined(FD_SET)
+#define NBBY 8
+typedef long fd_mask;
+#define NFDBITS (sizeof(fd_mask) * NBBY) /* bits per mask */
+
+#ifndef howmany
+#define howmany(x, y) (((x)+((y)-1))/(y))
+#endif
+#define FD_SETSIZE 64
+typedef struct fd_set{
+ fd_mask fds_bits[howmany(FD_SETSIZE, NFDBITS)];
+} fd_set;
+
+#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
+#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
+#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
+#define FD_ZERO(p) memset (p, 0, sizeof(*(p)))
+#endif /* !FD_SET */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern unsigned long inet_addr(const char *cp);
+extern char *inet_ntoa(struct in_addr in);
+
+inline unsigned long htonl(unsigned long hostlong) {return hostlong;}
+inline unsigned long ntohl(unsigned long netlong) {return netlong;}
+inline unsigned short ntohs(unsigned short netshort) {return netshort;}
+inline unsigned short htons(unsigned short hostshort) {return hostshort;}
+
+
+// UNIX look-alike routines
+// They make sure that the arguments passed in are valid, and then
+//
+extern struct hostent *macsock_gethostbyaddr(const void *addr, int addrlen, int type);
+
+extern int macsock_socket(int domain, int type, int protocol);
+extern int macsock_ioctl(int sID, unsigned int request, void *value);
+extern int macsock_connect(int sID, struct sockaddr *name, int namelen);
+extern int macsock_write(int sID, const void *buffer, unsigned buflen);
+extern int macsock_read(int sID, void *buf, unsigned nbyte);
+extern int macsock_close(int sID);
+
+extern int macsock_accept(int sID, struct sockaddr *addr, int *addrlen);
+extern int macsock_bind(int sID, const struct sockaddr *name, int namelen);
+extern int macsock_listen(int sID, int backlog);
+
+extern int macsock_shutdown(int sID, int how);
+extern int macsock_getpeername(int sID, struct sockaddr *name, int *namelen);
+extern int macsock_getsockname(int sID, struct sockaddr *name, int *namelen);
+extern int macsock_getsockopt(int sID, int level, int optname, void *optval,int *optlen);
+extern int macsock_setsockopt(int sID, int level, int optname, const void *optval,int optlen);
+extern int macsock_socketavailable(int sID, size_t *bytesAvailable);
+extern int macsock_dup(int sID);
+
+extern int macsock_send(int sID, const void *msg, int len, int flags);
+extern int macsock_sendto(int sID, const void *msg, int len, int flags, struct sockaddr *toAddr, int toLen);
+extern int macsock_recvfrom(int sID, void *buf, int len, int flags, struct sockaddr *from, int *fromLen);
+extern int macsock_recv(int sID, void *buf, int len, int flags);
+
+extern int select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
+
+
+#define macsock_gethostbyaddr PR_GetHostByAddr
+#define macsock_socket PR_Socket
+#define macsock_connect PR_Connect
+#define macsock_write PR_Write
+#define macsock_read PR_Read
+#define macsock_close PR_Close
+#define macsock_accept PR_Accept
+#define macsock_bind PR_Bind
+#define macsock_listen PR_Listen
+#define macsock_shutdown PR_Shutdown
+#define macsock_getpeername PR_GetPeerName
+#define macsock_getsockname PR_GetSockName
+#define macsock_socketavailable PR_SocketAvailable
+#define macsock_send PR_Send
+#define macsock_sendto PR_SendTo
+#define macsock_recvfrom PR_RecvFrom
+#define macsock_recv PR_Recv
+
+#ifdef __cplusplus
+}
+#endif
+//extern int errno;
+
+/*
+macsock_sendmsg
+macsock_readv
+macsock_writev
+*/
+
+/* New definitions that are not defined in macsock.h in macsock library */
+struct protoent {
+ char *p_name; /* official protocol name */
+ char **p_aliases; /* alias list */
+ int p_proto; /* protocol # */
+};
+
+extern struct protoent *getprotobyname(const char * name);
+extern struct protoent *getprotobynumber(int number);
+
+extern int gethostname (char *name, int namelen);
+extern struct hostent *gethostbyname(const char * name);
+extern struct hostent *gethostbyaddr(const void *addr, int addrlen, int type);
+
+#define INADDR_LOOPBACK 0x7F000001
+
+#define SO_KEEPALIVE TCP_KEEPALIVE
+#define SO_RCVBUF XTI_RCVBUF
+#define SO_SNDBUF XTI_SNDBUF
+#define SO_LINGER XTI_LINGER /* linger on close if data present */
+
+#define IPPROTO_IP INET_IP
+
+/* Get/Set sock opt until fixed in NSPR 2.0 */
+struct linger {
+ int l_onoff; /* option on/off */
+ int l_linger; /* linger time */
+};
+
+struct ip_mreq {
+ struct in_addr imr_multiaddr; /* IP multicast address of group */
+ struct in_addr imr_interface; /* local IP address of interface */
+};
+
+#endif /* macksocket_h___ */
diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macsockotpt.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macsockotpt.c
new file mode 100644
index 00000000..b357eea6
--- /dev/null
+++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macsockotpt.c
@@ -0,0 +1,2321 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* This turns on UNIX style errors in OT 1.1 headers */
+#define OTUNIXERRORS 1
+
+#include <string.h>
+
+#include <Gestalt.h>
+#include <Files.h>
+#include <OpenTransport.h>
+#include <OSUtils.h>
+
+#define GESTALT_OPEN_TPT_PRESENT gestaltOpenTptPresentMask
+#define GESTALT_OPEN_TPT_TCP_PRESENT gestaltOpenTptTCPPresentMask
+
+#include <OpenTptInternet.h> // All the internet typedefs
+
+#if (UNIVERSAL_INTERFACES_VERSION >= 0x0330)
+// for some reason Apple removed this typedef.
+typedef struct OTConfiguration OTConfiguration;
+#endif
+
+#include "primpl.h"
+
+typedef enum SndRcvOpCode {
+ kSTREAM_SEND,
+ kSTREAM_RECEIVE,
+ kDGRAM_SEND,
+ kDGRAM_RECEIVE
+} SndRcvOpCode;
+
+static struct {
+ PRLock * lock;
+ InetSvcRef serviceRef;
+ PRThread * thread;
+ void * cookie;
+} dnsContext;
+
+
+static pascal void DNSNotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie);
+static pascal void NotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie);
+static pascal void RawEndpointNotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie);
+
+static PRBool GetState(PRFileDesc *fd, PRBool *readReady, PRBool *writeReady, PRBool *exceptReady);
+
+void
+WakeUpNotifiedThread(PRThread *thread, OTResult result);
+
+extern void WaitOnThisThread(PRThread *thread, PRIntervalTime timeout);
+extern void DoneWaitingOnThisThread(PRThread *thread);
+
+#if TARGET_CARBON
+OTClientContextPtr clientContext = NULL;
+
+#define INIT_OPEN_TRANSPORT() InitOpenTransportInContext(kInitOTForExtensionMask, &clientContext)
+#define OT_OPEN_INTERNET_SERVICES(config, flags, err) OTOpenInternetServicesInContext(config, flags, err, clientContext)
+#define OT_OPEN_ENDPOINT(config, flags, info, err) OTOpenEndpointInContext(config, flags, info, err, clientContext)
+
+#else
+
+#define INIT_OPEN_TRANSPORT() InitOpenTransport()
+#define OT_OPEN_INTERNET_SERVICES(config, flags, err) OTOpenInternetServices(config, flags, err)
+#define OT_OPEN_ENDPOINT(config, flags, info, err) OTOpenEndpoint(config, flags, info, err)
+#endif /* TARGET_CARBON */
+
+static OTNotifyUPP DNSNotifierRoutineUPP;
+static OTNotifyUPP NotifierRoutineUPP;
+static OTNotifyUPP RawEndpointNotifierRoutineUPP;
+
+void _MD_InitNetAccess()
+{
+ OSErr err;
+ OSStatus errOT;
+ PRBool hasOTTCPIP = PR_FALSE;
+ PRBool hasOT = PR_FALSE;
+ long gestaltResult;
+
+ err = Gestalt(gestaltOpenTpt, &gestaltResult);
+ if (err == noErr)
+ if (gestaltResult & GESTALT_OPEN_TPT_PRESENT)
+ hasOT = PR_TRUE;
+
+ if (hasOT)
+ if (gestaltResult & GESTALT_OPEN_TPT_TCP_PRESENT)
+ hasOTTCPIP = PR_TRUE;
+
+ PR_ASSERT(hasOTTCPIP == PR_TRUE);
+
+ DNSNotifierRoutineUPP = NewOTNotifyUPP(DNSNotifierRoutine);
+ NotifierRoutineUPP = NewOTNotifyUPP(NotifierRoutine);
+ RawEndpointNotifierRoutineUPP = NewOTNotifyUPP(RawEndpointNotifierRoutine);
+
+ errOT = INIT_OPEN_TRANSPORT();
+ PR_ASSERT(err == kOTNoError);
+
+ dnsContext.serviceRef = NULL;
+ dnsContext.lock = PR_NewLock();
+ PR_ASSERT(dnsContext.lock != NULL);
+
+ dnsContext.thread = _PR_MD_CURRENT_THREAD();
+ dnsContext.cookie = NULL;
+
+/* XXX Does not handle absence of open tpt and tcp yet! */
+}
+
+static void _MD_FinishInitNetAccess()
+{
+ OSStatus errOT;
+
+ if (dnsContext.serviceRef)
+ return;
+
+ dnsContext.serviceRef = OT_OPEN_INTERNET_SERVICES(kDefaultInternetServicesPath, NULL, &errOT);
+ if (errOT != kOTNoError) {
+ dnsContext.serviceRef = NULL;
+ return; /* no network -- oh well */
+ }
+
+ PR_ASSERT((dnsContext.serviceRef != NULL) && (errOT == kOTNoError));
+
+ /* Install notify function for DNR Address To String completion */
+ errOT = OTInstallNotifier(dnsContext.serviceRef, DNSNotifierRoutineUPP, &dnsContext);
+ PR_ASSERT(errOT == kOTNoError);
+
+ /* Put us into async mode */
+ errOT = OTSetAsynchronous(dnsContext.serviceRef);
+ PR_ASSERT(errOT == kOTNoError);
+}
+
+
+static pascal void DNSNotifierRoutine(void * contextPtr, OTEventCode otEvent, OTResult result, void * cookie)
+{
+#pragma unused(contextPtr)
+ _PRCPU * cpu = _PR_MD_CURRENT_CPU();
+ OSStatus errOT;
+
+ dnsContext.thread->md.osErrCode = result;
+ dnsContext.cookie = cookie;
+
+ switch (otEvent) {
+ case T_DNRSTRINGTOADDRCOMPLETE:
+ if (_PR_MD_GET_INTSOFF()) {
+ dnsContext.thread->md.missedIONotify = PR_TRUE;
+ cpu->u.missed[cpu->where] |= _PR_MISSED_IO;
+ } else {
+ DoneWaitingOnThisThread(dnsContext.thread);
+ }
+ break;
+
+ case kOTProviderWillClose:
+ errOT = OTSetSynchronous(dnsContext.serviceRef);
+ // fall through to kOTProviderIsClosed case
+
+ case kOTProviderIsClosed:
+ errOT = OTCloseProvider((ProviderRef)dnsContext.serviceRef);
+ dnsContext.serviceRef = nil;
+
+ if (_PR_MD_GET_INTSOFF()) {
+ dnsContext.thread->md.missedIONotify = PR_TRUE;
+ cpu->u.missed[cpu->where] |= _PR_MISSED_IO;
+ } else {
+ DoneWaitingOnThisThread(dnsContext.thread);
+ }
+ break;
+
+ default: // or else we don't handle the event
+ PR_ASSERT(otEvent==NULL);
+
+ }
+ // or else we don't handle the event
+
+ SignalIdleSemaphore();
+}
+
+
+static void macsock_map_error(OSStatus err)
+{
+ _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
+
+ if (IsEError(err) || (err >= EPERM && err <= ELASTERRNO)) {
+ switch (IsEError(err) ? OSStatus2E(err) : err) {
+ case EBADF:
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+ break;
+ case EADDRNOTAVAIL:
+ PR_SetError(PR_ADDRESS_NOT_AVAILABLE_ERROR, err);
+ break;
+ case EINPROGRESS:
+ PR_SetError(PR_IN_PROGRESS_ERROR, err);
+ break;
+ case EWOULDBLOCK:
+ case EAGAIN:
+ PR_SetError(PR_WOULD_BLOCK_ERROR, err);
+ break;
+ case ENOTSOCK:
+ PR_SetError(PR_NOT_SOCKET_ERROR, err);
+ break;
+ case ETIMEDOUT:
+ PR_SetError(PR_IO_TIMEOUT_ERROR, err);
+ break;
+ case ECONNREFUSED:
+ PR_SetError(PR_CONNECT_REFUSED_ERROR, err);
+ break;
+ case ENETUNREACH:
+ PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, err);
+ break;
+ case EADDRINUSE:
+ PR_SetError(PR_ADDRESS_IN_USE_ERROR, err);
+ break;
+ case EFAULT:
+ PR_SetError(PR_ACCESS_FAULT_ERROR, err);
+ break;
+ case EINTR:
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, err);
+ break;
+ case EINVAL:
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, err);
+ break;
+ case EIO:
+ PR_SetError(PR_IO_ERROR, err);
+ break;
+ case ENOENT:
+ PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err);
+ break;
+ case ENXIO:
+ PR_SetError(PR_IO_ERROR, err);
+ break;
+ case EPROTOTYPE:
+ PR_SetError(PR_PROTOCOL_NOT_SUPPORTED_ERROR, err);
+ break;
+ case EOPNOTSUPP:
+ PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+ } else {
+ PR_ASSERT(IsXTIError(err));
+ switch (err) {
+ case kOTNoDataErr:
+ case kOTFlowErr:
+ PR_SetError(PR_WOULD_BLOCK_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+ }
+}
+
+static void PrepareForAsyncCompletion(PRThread * thread, PRInt32 osfd)
+{
+ thread->io_pending = PR_TRUE;
+ thread->io_fd = osfd;
+ thread->md.osErrCode = noErr;
+}
+
+
+void
+WakeUpNotifiedThread(PRThread *thread, OTResult result)
+{
+ _PRCPU * cpu = _PR_MD_CURRENT_CPU();
+
+ if (thread) {
+ thread->md.osErrCode = result;
+ if (_PR_MD_GET_INTSOFF()) {
+ thread->md.missedIONotify = PR_TRUE;
+ cpu->u.missed[cpu->where] |= _PR_MISSED_IO;
+ } else {
+ DoneWaitingOnThisThread(thread);
+ }
+ }
+
+ SignalIdleSemaphore();
+}
+
+// Notification routine
+// Async callback routine.
+// A5 is OK. Cannot allocate memory here
+// Ref: http://gemma.apple.com/techpubs/mac/NetworkingOT/NetworkingWOT-100.html
+//
+static pascal void NotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie)
+{
+ PRFilePrivate *secret = (PRFilePrivate *) contextPtr;
+ _MDFileDesc * md = &(secret->md);
+ EndpointRef endpoint = (EndpointRef)secret->md.osfd;
+ PRThread * readThread = NULL; // also used for 'misc'
+ PRThread * writeThread = NULL;
+ OSStatus err;
+ OTResult resultOT;
+ TDiscon discon;
+
+ switch (code)
+ {
+// OTLook Events -
+ case T_LISTEN: // A connection request is available
+ // If md->doListen is true, then PR_Listen has been
+ // called on this endpoint; therefore, we're ready to
+ // accept connections. But we'll do that with PR_Accept
+ // (which calls OTListen, OTAccept, etc) instead of
+ // doing it here.
+ if (md->doListen) {
+ readThread = secret->md.misc.thread;
+ secret->md.misc.thread = NULL;
+ secret->md.misc.cookie = cookie;
+ break;
+ } else {
+ // Reject the connection, we're not listening
+ OTSndDisconnect(endpoint, NULL);
+ }
+ break;
+
+ case T_CONNECT: // Confirmation of a connect request
+ // cookie = sndCall parameter from OTConnect()
+ err = OTRcvConnect(endpoint, NULL);
+ PR_ASSERT(err == kOTNoError);
+
+ // wake up waiting thread, if any.
+ writeThread = secret->md.write.thread;
+ secret->md.write.thread = NULL;
+ secret->md.write.cookie = cookie;
+ break;
+
+ case T_DATA: // Standard data is available
+ // Mark this socket as readable.
+ secret->md.readReady = PR_TRUE;
+
+ // wake up waiting thread, if any
+ readThread = secret->md.read.thread;
+ secret->md.read.thread = NULL;
+ secret->md.read.cookie = cookie;
+ break;
+
+ case T_EXDATA: // Expedited data is available
+ PR_ASSERT(!"T_EXDATA Not implemented");
+ return;
+
+ case T_DISCONNECT: // A disconnect is available
+ discon.udata.len = 0;
+ err = OTRcvDisconnect(endpoint, &discon);
+ PR_ASSERT(err == kOTNoError);
+ secret->md.exceptReady = PR_TRUE; // XXX Check this
+
+ md->disconnectError = discon.reason; // save for _MD_mac_get_nonblocking_connect_error
+
+ // wake up waiting threads, if any
+ result = -3199 - discon.reason; // obtain the negative error code
+ if ((readThread = secret->md.read.thread) != NULL) {
+ secret->md.read.thread = NULL;
+ secret->md.read.cookie = cookie;
+ }
+
+ if ((writeThread = secret->md.write.thread) != NULL) {
+ secret->md.write.thread = NULL;
+ secret->md.write.cookie = cookie;
+ }
+ break;
+
+ case T_ERROR: // obsolete/unused in library
+ PR_ASSERT(!"T_ERROR Not implemented");
+ return;
+
+ case T_UDERR: // UDP Send error; clear the error
+ (void) OTRcvUDErr((EndpointRef) cookie, NULL);
+ break;
+
+ case T_ORDREL: // An orderly release is available
+ err = OTRcvOrderlyDisconnect(endpoint);
+ PR_ASSERT(err == kOTNoError);
+ secret->md.readReady = PR_TRUE; // mark readable (to emulate bsd sockets)
+ // remember connection is closed, so we can return 0 on read or receive
+ secret->md.orderlyDisconnect = PR_TRUE;
+
+ readThread = secret->md.read.thread;
+ secret->md.read.thread = NULL;
+ secret->md.read.cookie = cookie;
+ break;
+
+ case T_GODATA: // Flow control lifted on standard data
+ secret->md.writeReady = PR_TRUE;
+ resultOT = OTLook(endpoint); // clear T_GODATA event
+ PR_ASSERT(resultOT == T_GODATA);
+
+ // wake up waiting thread, if any
+ writeThread = secret->md.write.thread;
+ secret->md.write.thread = NULL;
+ secret->md.write.cookie = cookie;
+ break;
+
+ case T_GOEXDATA: // Flow control lifted on expedited data
+ PR_ASSERT(!"T_GOEXDATA Not implemented");
+ return;
+
+ case T_REQUEST: // An Incoming request is available
+ PR_ASSERT(!"T_REQUEST Not implemented");
+ return;
+
+ case T_REPLY: // An Incoming reply is available
+ PR_ASSERT(!"T_REPLY Not implemented");
+ return;
+
+ case T_PASSCON: // State is now T_DATAXFER
+ // OTAccept() complete, receiving endpoint in T_DATAXFER state
+ // cookie = OTAccept() resRef parameter
+ break;
+
+ case T_RESET: // Protocol has been reset
+ PR_ASSERT(!"T_RESET Not implemented");
+ return;
+
+// Async Completion Events
+ case T_BINDCOMPLETE:
+ case T_UNBINDCOMPLETE:
+ case T_ACCEPTCOMPLETE:
+ case T_OPTMGMTCOMPLETE:
+ case T_GETPROTADDRCOMPLETE:
+ readThread = secret->md.misc.thread;
+ secret->md.misc.thread = NULL;
+ secret->md.misc.cookie = cookie;
+ break;
+
+// case T_OPENCOMPLETE: // we open endpoints in synchronous mode
+// case T_REPLYCOMPLETE:
+// case T_DISCONNECTCOMPLETE: // we don't call OTSndDisconnect()
+// case T_RESOLVEADDRCOMPLETE:
+// case T_GETINFOCOMPLETE:
+// case T_SYNCCOMPLETE:
+// case T_MEMORYRELEASED: // only if OTAckSends() called on endpoint
+// case T_REGNAMECOMPLETE:
+// case T_DELNAMECOMPLETE:
+// case T_LKUPNAMECOMPLETE:
+// case T_LKUPNAMERESULT:
+ // OpenTptInternet.h
+// case T_DNRSTRINGTOADDRCOMPLETE: // DNS is handled by dnsContext in DNSNotifierRoutine()
+// case T_DNRADDRTONAMECOMPLETE:
+// case T_DNRSYSINFOCOMPLETE:
+// case T_DNRMAILEXCHANGECOMPLETE:
+// case T_DNRQUERYCOMPLETE:
+ default:
+ // we should probably have a bit more sophisticated handling of kOTSystemSleep, etc.
+ // PR_ASSERT(code != 0);
+ return;
+ }
+
+ if (readThread)
+ WakeUpNotifiedThread(readThread, result);
+
+ if (writeThread && (writeThread != readThread))
+ WakeUpNotifiedThread(writeThread, result);
+}
+
+
+static OSErr CreateSocket(int type, EndpointRef *endpoint)
+{
+ OSStatus err;
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+ char * configName;
+ OTConfiguration *config;
+ EndpointRef ep;
+
+ // for now we just create the endpoint
+ // we'll make it asynchronous and give it a notifier routine in _MD_makenonblock()
+
+ switch (type){
+ case SOCK_STREAM: configName = kTCPName; break;
+ case SOCK_DGRAM: configName = kUDPName; break;
+ }
+ config = OTCreateConfiguration(configName);
+ ep = OT_OPEN_ENDPOINT(config, 0, NULL, &err);
+ if (err != kOTNoError)
+ goto ErrorExit;
+
+ *endpoint = ep;
+ PR_ASSERT(*endpoint != NULL);
+
+ return kOTNoError;
+
+ErrorExit:
+ return err;
+}
+
+
+// Errors returned:
+// kOTXXXX - OT returned error
+// EPROTONOSUPPORT - bad socket type/protocol
+// ENOBUFS - not enough space for another socket, or failure in socket creation routine
+PRInt32 _MD_socket(int domain, int type, int protocol)
+{
+ OSStatus err;
+ EndpointRef endpoint;
+
+ _MD_FinishInitNetAccess();
+
+ // We only deal with internet domain
+ if (domain != AF_INET) {
+ err = kEPROTONOSUPPORTErr;
+ goto ErrorExit;
+ }
+
+ // We only know about tcp & udp
+ if ((type != SOCK_STREAM) && (type != SOCK_DGRAM)) {
+ err = kEPROTONOSUPPORTErr;
+ goto ErrorExit;
+ }
+
+ // Convert default types to specific types.
+ if (protocol == 0) {
+ if (type == SOCK_DGRAM)
+ protocol = IPPROTO_UDP;
+ else if (type == SOCK_STREAM)
+ protocol = IPPROTO_TCP;
+ }
+
+ // Only support default protocol for tcp
+ if ((type == SOCK_STREAM) && (protocol != IPPROTO_TCP)) {
+ err = kEPROTONOSUPPORTErr;
+ goto ErrorExit;
+ }
+
+ // Only support default protocol for udp
+ if ((type == SOCK_DGRAM) && (protocol != IPPROTO_UDP)) {
+ err = kEPROTONOSUPPORTErr;
+ goto ErrorExit;
+ }
+
+ // Create a socket, we might run out of memory
+ err = CreateSocket(type, &endpoint);
+ if (err != kOTNoError)
+ goto ErrorExit;
+
+ PR_ASSERT((PRInt32)endpoint != -1);
+
+ return ((PRInt32)endpoint);
+
+ErrorExit:
+ macsock_map_error(err);
+ return -1;
+}
+
+
+// Errors:
+// EBADF -- bad socket id
+// EFAULT -- bad address format
+PRInt32 _MD_bind(PRFileDesc *fd, PRNetAddr *addr, PRUint32 addrlen)
+{
+ OSStatus err;
+ EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
+ TBind bindReq;
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+ PRUint32 retryCount = 0;
+
+ if (endpoint == NULL) {
+ err = kEBADFErr;
+ goto ErrorExit;
+ }
+
+ if (addr == NULL) {
+ err = kEFAULTErr;
+ goto ErrorExit;
+ }
+
+/*
+ * There seems to be a bug with OT related to OTBind failing with kOTNoAddressErr even though
+ * a proper legal address was supplied. This happens very rarely and just retrying the
+ * operation after a certain time (less than 1 sec. does not work) seems to succeed.
+ */
+
+TryAgain:
+ // setup our request
+ bindReq.addr.len = addrlen;
+
+ bindReq.addr.maxlen = addrlen;
+ bindReq.addr.buf = (UInt8*) addr;
+ bindReq.qlen = 1;
+
+ PR_Lock(fd->secret->md.miscLock);
+ PrepareForAsyncCompletion(me, fd->secret->md.osfd);
+ fd->secret->md.misc.thread = me;
+
+ err = OTBind(endpoint, &bindReq, NULL);
+ if (err != kOTNoError) {
+ me->io_pending = PR_FALSE;
+ PR_Unlock(fd->secret->md.miscLock);
+ goto ErrorExit;
+ }
+
+ WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
+ PR_Unlock(fd->secret->md.miscLock);
+
+ err = me->md.osErrCode;
+ if (err != kOTNoError)
+ goto ErrorExit;
+
+ return kOTNoError;
+
+ErrorExit:
+ if ((err == kOTNoAddressErr) && (++retryCount <= 4)) {
+ unsigned long finalTicks;
+
+ Delay(100,&finalTicks);
+ goto TryAgain;
+ }
+ macsock_map_error(err);
+ return -1;
+}
+
+
+// Errors:
+// EBADF -- bad socket id
+PRInt32 _MD_listen(PRFileDesc *fd, PRIntn backlog)
+{
+ PRInt32 osfd = fd->secret->md.osfd;
+ OSStatus err = 0;
+ EndpointRef endpoint = (EndpointRef) osfd;
+ TBind bindReq;
+ PRNetAddr addr;
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+
+ if ((fd == NULL) || (endpoint == NULL)) {
+ err = EBADF;
+ goto ErrorExit;
+ }
+
+ if (backlog == 0)
+ backlog = 1;
+
+ if (endpoint == NULL) {
+ err = EBADF;
+ goto ErrorExit;
+ }
+
+ addr.inet.family = AF_INET;
+ addr.inet.port = addr.inet.ip = 0;
+
+ bindReq.addr.maxlen = PR_NETADDR_SIZE (&addr);
+ bindReq.addr.len = 0;
+ bindReq.addr.buf = (UInt8*) &addr;
+ bindReq.qlen = 0;
+
+ PrepareForAsyncCompletion(me, fd->secret->md.osfd);
+ fd->secret->md.misc.thread = me; // tell notifier routine what to wake up
+
+ err = OTGetProtAddress(endpoint, &bindReq, NULL);
+ if (err != kOTNoError)
+ goto ErrorExit;
+
+ WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
+
+ err = me->md.osErrCode;
+ if (err != kOTNoError)
+ goto ErrorExit;
+
+ PrepareForAsyncCompletion(me, fd->secret->md.osfd);
+ fd->secret->md.misc.thread = me; // tell notifier routine what to wake up
+
+ err = OTUnbind(endpoint);
+ if (err != kOTNoError)
+ goto ErrorExit;
+
+ WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
+
+ err = me->md.osErrCode;
+ if (err != kOTNoError)
+ goto ErrorExit;
+
+ /* tell the notifier func that we are interested in pending connections */
+ fd->secret->md.doListen = PR_TRUE;
+ /* accept up to (backlog) pending connections at any one time */
+ bindReq.qlen = backlog;
+
+ PrepareForAsyncCompletion(me, fd->secret->md.osfd);
+ fd->secret->md.misc.thread = me; // tell notifier routine what to wake up
+
+ err = OTBind(endpoint, &bindReq, NULL);
+ if (err != kOTNoError)
+ goto ErrorExit;
+
+ WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
+
+ err = me->md.osErrCode;
+ if (err != kOTNoError)
+ {
+ // If OTBind failed, we're really not ready to listen after all.
+ fd->secret->md.doListen = PR_FALSE;
+ goto ErrorExit;
+ }
+
+ return kOTNoError;
+
+ErrorExit:
+ me->io_pending = PR_FALSE; // clear pending wait state if any
+ macsock_map_error(err);
+ return -1;
+}
+
+
+// Errors:
+// EBADF -- bad socket id
+PRInt32 _MD_getsockname(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen)
+{
+ OSStatus err;
+ EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
+ TBind bindReq;
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+
+ if (endpoint == NULL) {
+ err = kEBADFErr;
+ goto ErrorExit;
+ }
+
+ if (addr == NULL) {
+ err = kEFAULTErr;
+ goto ErrorExit;
+ }
+
+ bindReq.addr.len = *addrlen;
+ bindReq.addr.maxlen = *addrlen;
+ bindReq.addr.buf = (UInt8*) addr;
+ bindReq.qlen = 0;
+
+ PR_Lock(fd->secret->md.miscLock);
+ PrepareForAsyncCompletion(me, fd->secret->md.osfd);
+ fd->secret->md.misc.thread = me;
+
+ err = OTGetProtAddress(endpoint, &bindReq, NULL);
+ if (err != kOTNoError) {
+ me->io_pending = PR_FALSE;
+ PR_Unlock(fd->secret->md.miscLock);
+ goto ErrorExit;
+ }
+
+ WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
+ PR_Unlock(fd->secret->md.miscLock);
+
+ err = me->md.osErrCode;
+ if (err != kOTNoError)
+ goto ErrorExit;
+
+ *addrlen = PR_NETADDR_SIZE(addr);
+ return kOTNoError;
+
+ErrorExit:
+ macsock_map_error(err);
+ return -1;
+}
+
+
+PRStatus _MD_getsockopt(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen)
+{
+ OSStatus err;
+ EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
+ TOptMgmt cmd;
+ TOption *opt;
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+ unsigned char optionBuffer[kOTOptionHeaderSize + sizeof(PRSocketOptionData)];
+
+ if (endpoint == NULL) {
+ err = kEBADFErr;
+ goto ErrorExit;
+ }
+
+ /*
+ OT wants IPPROTO_IP for level and not XTI_GENERIC. SO_REUSEADDR and SO_KEEPALIVE
+ are equated to IP level and TCP level options respectively and hence we need to set
+ the level correctly.
+ */
+ if (level == SOL_SOCKET) {
+ if (optname == SO_REUSEADDR)
+ level = IPPROTO_IP;
+ else if (optname == SO_KEEPALIVE)
+ level = INET_TCP;
+ }
+
+ opt = (TOption *)&optionBuffer[0];
+ opt->len = sizeof(TOption);
+ opt->level = level;
+ opt->name = optname;
+ opt->status = 0;
+
+ cmd.opt.len = sizeof(TOption);
+ cmd.opt.maxlen = sizeof(optionBuffer);
+ cmd.opt.buf = (UInt8*)optionBuffer;
+ cmd.flags = T_CURRENT;
+
+ PR_Lock(fd->secret->md.miscLock);
+ PrepareForAsyncCompletion(me, fd->secret->md.osfd);
+ fd->secret->md.misc.thread = me;
+
+ err = OTOptionManagement(endpoint, &cmd, &cmd);
+ if (err != kOTNoError) {
+ me->io_pending = PR_FALSE;
+ PR_Unlock(fd->secret->md.miscLock);
+ goto ErrorExit;
+ }
+
+ WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
+ PR_Unlock(fd->secret->md.miscLock);
+
+ err = me->md.osErrCode;
+ if (err != kOTNoError)
+ goto ErrorExit;
+
+ if (opt->status == T_FAILURE || opt->status == T_NOTSUPPORT){
+ err = kEOPNOTSUPPErr;
+ goto ErrorExit;
+ }
+
+ PR_ASSERT(opt->status == T_SUCCESS);
+
+ switch (optname) {
+ case SO_LINGER:
+ *((t_linger*)optval) = *((t_linger*)&opt->value);
+ *optlen = sizeof(t_linger);
+ break;
+ case SO_REUSEADDR:
+ case TCP_NODELAY:
+ case SO_KEEPALIVE:
+ case SO_RCVBUF:
+ case SO_SNDBUF:
+ *((PRIntn*)optval) = *((PRIntn*)&opt->value);
+ *optlen = sizeof(PRIntn);
+ break;
+ case IP_MULTICAST_LOOP:
+ *((PRUint8*)optval) = *((PRIntn*)&opt->value);
+ *optlen = sizeof(PRUint8);
+ break;
+ case IP_TTL:
+ *((PRUintn*)optval) = *((PRUint8*)&opt->value);
+ *optlen = sizeof(PRUintn);
+ break;
+ case IP_MULTICAST_TTL:
+ *((PRUint8*)optval) = *((PRUint8*)&opt->value);
+ *optlen = sizeof(PRUint8);
+ break;
+ case IP_ADD_MEMBERSHIP:
+ case IP_DROP_MEMBERSHIP:
+ {
+ /* struct ip_mreq and TIPAddMulticast are the same size and optval
+ is pointing to struct ip_mreq */
+ *((struct ip_mreq *)optval) = *((struct ip_mreq *)&opt->value);
+ *optlen = sizeof(struct ip_mreq);
+ break;
+ }
+ case IP_MULTICAST_IF:
+ {
+ *((PRUint32*)optval) = *((PRUint32*)&opt->value);
+ *optlen = sizeof(PRUint32);
+ break;
+ }
+ /*case IP_TOS:*/ /*IP_TOS has same value as TCP_MAXSEG */
+ case TCP_MAXSEG:
+ if (level == IPPROTO_TCP) { /* it is TCP_MAXSEG */
+ *((PRIntn*)optval) = *((PRIntn*)&opt->value);
+ *optlen = sizeof(PRIntn);
+ } else { /* it is IP_TOS */
+ *((PRUintn*)optval) = *((PRUint8*)&opt->value);
+ *optlen = sizeof(PRUintn);
+ }
+ break;
+ default:
+ PR_ASSERT(0);
+ break;
+ }
+
+ return PR_SUCCESS;
+
+ErrorExit:
+ macsock_map_error(err);
+ return PR_FAILURE;
+}
+
+
+PRStatus _MD_setsockopt(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen)
+{
+ OSStatus err;
+ EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
+ TOptMgmt cmd;
+ TOption *opt;
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+ unsigned char optionBuffer[kOTOptionHeaderSize + sizeof(PRSocketOptionData) + 1];
+
+ if (endpoint == NULL) {
+ err = kEBADFErr;
+ goto ErrorExit;
+ }
+
+ /*
+ OT wants IPPROTO_IP for level and not XTI_GENERIC. SO_REUSEADDR and SO_KEEPALIVE
+ are equated to IP level and TCP level options respectively and hence we need to set
+ the level correctly.
+ */
+ if (level == SOL_SOCKET) {
+ if (optname == SO_REUSEADDR)
+ level = IPPROTO_IP;
+ else if (optname == SO_KEEPALIVE)
+ level = INET_TCP;
+ }
+
+ opt = (TOption *)&optionBuffer[0];
+ opt->len = kOTOptionHeaderSize + optlen;
+
+ /* special case adjustments for length follow */
+ if (optname == SO_KEEPALIVE) /* we need to pass the timeout value for OT */
+ opt->len = kOTOptionHeaderSize + sizeof(t_kpalive);
+ if (optname == IP_MULTICAST_TTL || optname == IP_TTL) /* it is an unsigned char value */
+ opt->len = kOTOneByteOptionSize;
+ if (optname == IP_TOS && level == IPPROTO_IP)
+ opt->len = kOTOneByteOptionSize;
+
+ opt->level = level;
+ opt->name = optname;
+ opt->status = 0;
+
+ cmd.opt.len = opt->len;
+ cmd.opt.maxlen = sizeof(optionBuffer);
+ cmd.opt.buf = (UInt8*)optionBuffer;
+
+ optionBuffer[opt->len] = 0;
+
+ cmd.flags = T_NEGOTIATE;
+
+ switch (optname) {
+ case SO_LINGER:
+ *((t_linger*)&opt->value) = *((t_linger*)optval);
+ break;
+ case SO_REUSEADDR:
+ case TCP_NODELAY:
+ case SO_RCVBUF:
+ case SO_SNDBUF:
+ *((PRIntn*)&opt->value) = *((PRIntn*)optval);
+ break;
+ case IP_MULTICAST_LOOP:
+ if (*optval != 0)
+ opt->value[0] = T_YES;
+ else
+ opt->value[0] = T_NO;
+ break;
+ case SO_KEEPALIVE:
+ {
+ t_kpalive *kpalive = (t_kpalive *)&opt->value;
+
+ kpalive->kp_onoff = *((long*)optval);
+ kpalive->kp_timeout = 10; /* timeout in minutes */
+ break;
+ }
+ case IP_TTL:
+ *((unsigned char*)&opt->value) = *((PRUintn*)optval);
+ break;
+ case IP_MULTICAST_TTL:
+ *((unsigned char*)&opt->value) = *optval;
+ break;
+ case IP_ADD_MEMBERSHIP:
+ case IP_DROP_MEMBERSHIP:
+ {
+ /* struct ip_mreq and TIPAddMulticast are the same size and optval
+ is pointing to struct ip_mreq */
+ *((TIPAddMulticast *)&opt->value) = *((TIPAddMulticast *)optval);
+ break;
+ }
+ case IP_MULTICAST_IF:
+ {
+ *((PRUint32*)&opt->value) = *((PRUint32*)optval);
+ break;
+ }
+ /*case IP_TOS:*/ /*IP_TOS has same value as TCP_MAXSEG */
+ case TCP_MAXSEG:
+ if (level == IPPROTO_TCP) { /* it is TCP_MAXSEG */
+ *((PRIntn*)&opt->value) = *((PRIntn*)optval);
+ } else { /* it is IP_TOS */
+ *((unsigned char*)&opt->value) = *((PRUintn*)optval);
+ }
+ break;
+ default:
+ PR_ASSERT(0);
+ break;
+ }
+
+ PR_Lock(fd->secret->md.miscLock);
+ PrepareForAsyncCompletion(me, fd->secret->md.osfd);
+ fd->secret->md.misc.thread = me;
+
+ err = OTOptionManagement(endpoint, &cmd, &cmd);
+ if (err != kOTNoError) {
+ me->io_pending = PR_FALSE;
+ PR_Unlock(fd->secret->md.miscLock);
+ goto ErrorExit;
+ }
+
+ WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
+ PR_Unlock(fd->secret->md.miscLock);
+
+ err = me->md.osErrCode;
+ if (err != kOTNoError)
+ goto ErrorExit;
+
+ if (opt->status == T_FAILURE || opt->status == T_NOTSUPPORT){
+ err = kEOPNOTSUPPErr;
+ goto ErrorExit;
+ }
+
+ if (level == IPPROTO_TCP && optname == TCP_MAXSEG && opt->status == T_READONLY) {
+ err = kEOPNOTSUPPErr;
+ goto ErrorExit;
+ }
+
+ PR_ASSERT(opt->status == T_SUCCESS);
+
+ return PR_SUCCESS;
+
+ErrorExit:
+ macsock_map_error(err);
+ return PR_FAILURE;
+}
+
+
+PRInt32 _MD_socketavailable(PRFileDesc *fd)
+{
+ PRInt32 osfd = fd->secret->md.osfd;
+ OSStatus err;
+ EndpointRef endpoint = (EndpointRef) osfd;
+ size_t bytes;
+
+ if (endpoint == NULL) {
+ err = kEBADFErr;
+ goto ErrorExit;
+ }
+
+ bytes = 0;
+
+ err = OTCountDataBytes(endpoint, &bytes);
+ if ((err == kOTLookErr) || // Not really errors, we just need to do a read,
+ (err == kOTNoDataErr)) // or there's nothing there.
+ err = kOTNoError;
+
+ if (err != kOTNoError)
+ goto ErrorExit;
+
+ return bytes;
+
+ErrorExit:
+ macsock_map_error(err);
+ return -1;
+}
+
+
+typedef struct RawEndpointAndThread
+{
+ PRThread * thread;
+ EndpointRef endpoint;
+} RawEndpointAndThread;
+
+// Notification routine for raw endpoints not yet attached to a PRFileDesc.
+// Async callback routine.
+// A5 is OK. Cannot allocate memory here
+static pascal void RawEndpointNotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie)
+{
+ RawEndpointAndThread *endthr = (RawEndpointAndThread *) contextPtr;
+ PRThread * thread = endthr->thread;
+ EndpointRef * endpoint = endthr->endpoint;
+ _PRCPU * cpu = _PR_MD_CURRENT_CPU();
+ OSStatus err;
+ OTResult resultOT;
+
+ switch (code)
+ {
+// OTLook Events -
+ case T_LISTEN: // A connection request is available
+ PR_ASSERT(!"T_EXDATA not implemented for raw endpoints");
+ break;
+
+ case T_CONNECT: // Confirmation of a connect request
+ // cookie = sndCall parameter from OTConnect()
+ err = OTRcvConnect(endpoint, NULL);
+ PR_ASSERT(err == kOTNoError);
+
+ // wake up waiting thread
+ break;
+
+ case T_DATA: // Standard data is available
+ break;
+
+ case T_EXDATA: // Expedited data is available
+ PR_ASSERT(!"T_EXDATA Not implemented for raw endpoints");
+ return;
+
+ case T_DISCONNECT: // A disconnect is available
+ err = OTRcvDisconnect(endpoint, NULL);
+ PR_ASSERT(err == kOTNoError);
+ break;
+
+ case T_ERROR: // obsolete/unused in library
+ PR_ASSERT(!"T_ERROR Not implemented for raw endpoints");
+ return;
+
+ case T_UDERR: // UDP Send error; clear the error
+ (void) OTRcvUDErr((EndpointRef) cookie, NULL);
+ break;
+
+ case T_ORDREL: // An orderly release is available
+ err = OTRcvOrderlyDisconnect(endpoint);
+ PR_ASSERT(err == kOTNoError);
+ break;
+
+ case T_GODATA: // Flow control lifted on standard data
+ resultOT = OTLook(endpoint); // clear T_GODATA event
+ PR_ASSERT(resultOT == T_GODATA);
+
+ // wake up waiting thread, if any
+ break;
+
+ case T_GOEXDATA: // Flow control lifted on expedited data
+ PR_ASSERT(!"T_GOEXDATA Not implemented");
+ return;
+
+ case T_REQUEST: // An Incoming request is available
+ PR_ASSERT(!"T_REQUEST Not implemented");
+ return;
+
+ case T_REPLY: // An Incoming reply is available
+ PR_ASSERT(!"T_REPLY Not implemented");
+ return;
+
+ case T_PASSCON: // State is now T_DATAXFER
+ // OTAccept() complete, receiving endpoint in T_DATAXFER state
+ // cookie = OTAccept() resRef parameter
+ break;
+
+// Async Completion Events
+ case T_BINDCOMPLETE:
+ case T_UNBINDCOMPLETE:
+ case T_ACCEPTCOMPLETE:
+ case T_OPTMGMTCOMPLETE:
+ case T_GETPROTADDRCOMPLETE:
+ break;
+
+ // for other OT events, see NotifierRoutine above
+ default:
+ return;
+ }
+
+ if (thread) {
+ thread->md.osErrCode = result;
+ if (_PR_MD_GET_INTSOFF()) {
+ thread->md.asyncNotifyPending = PR_TRUE;
+ cpu->u.missed[cpu->where] |= _PR_MISSED_IO;
+ } else {
+ DoneWaitingOnThisThread(thread);
+ }
+ }
+
+ SignalIdleSemaphore();
+}
+
+PRInt32 _MD_accept(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout)
+{
+ OSStatus err;
+ EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+ TBind bindReq;
+ PRNetAddr bindAddr;
+ PRInt32 newosfd = -1;
+ TCall call;
+ PRNetAddr callAddr;
+ RawEndpointAndThread *endthr = NULL;
+
+ if (endpoint == NULL) {
+ err = kEBADFErr;
+ goto ErrorExit;
+ }
+
+ memset(&call, 0 , sizeof(call));
+
+ if (addr != NULL) {
+ call.addr.maxlen = *addrlen;
+ call.addr.len = *addrlen;
+ call.addr.buf = (UInt8*) addr;
+ } else {
+ call.addr.maxlen = sizeof(callAddr);
+ call.addr.len = sizeof(callAddr);
+ call.addr.buf = (UInt8*) &callAddr;
+ }
+
+ do {
+ PrepareForAsyncCompletion(me, fd->secret->md.osfd);
+ fd->secret->md.misc.thread = me;
+
+ // Perform the listen.
+ err = OTListen (endpoint, &call);
+ if (err == kOTNoError)
+ break; // got the call information
+ else if ((!fd->secret->nonblocking) && (err == kOTNoDataErr)) {
+ WaitOnThisThread(me, timeout);
+ err = me->md.osErrCode;
+ if ((err != kOTNoError) && (err != kOTNoDataErr))
+ goto ErrorExit;
+ // we can get kOTNoError here, but still need
+ // to loop back to call OTListen, in order
+ // to get call info for OTAccept
+ } else {
+ goto ErrorExit; // we're nonblocking, and/or we got an error
+ }
+ }
+ while(1);
+
+ newosfd = _MD_socket(AF_INET, SOCK_STREAM, 0);
+ if (newosfd == -1)
+ return -1;
+
+ // Attach the raw endpoint handler to this endpoint for now.
+ endthr = (RawEndpointAndThread *) PR_Malloc(sizeof(RawEndpointAndThread));
+ endthr->thread = me;
+ endthr->endpoint = (EndpointRef) newosfd;
+
+ err = OTInstallNotifier((ProviderRef) newosfd, RawEndpointNotifierRoutineUPP, endthr);
+ PR_ASSERT(err == kOTNoError);
+
+ err = OTSetAsynchronous((EndpointRef) newosfd);
+ PR_ASSERT(err == kOTNoError);
+
+ // Bind to a local port; let the system assign it.
+ bindAddr.inet.family = AF_INET;
+ bindAddr.inet.port = bindAddr.inet.ip = 0;
+
+ bindReq.addr.maxlen = PR_NETADDR_SIZE (&bindAddr);
+ bindReq.addr.len = 0;
+ bindReq.addr.buf = (UInt8*) &bindAddr;
+ bindReq.qlen = 0;
+
+ PrepareForAsyncCompletion(me, newosfd);
+ err = OTBind((EndpointRef) newosfd, &bindReq, NULL);
+ if (err != kOTNoError)
+ goto ErrorExit;
+
+ WaitOnThisThread(me, timeout);
+
+ err = me->md.osErrCode;
+ if (err != kOTNoError)
+ goto ErrorExit;
+
+ PrepareForAsyncCompletion(me, newosfd);
+
+ err = OTAccept (endpoint, (EndpointRef) newosfd, &call);
+ if ((err != kOTNoError) && (err != kOTNoDataErr))
+ goto ErrorExit;
+
+ WaitOnThisThread(me, timeout);
+
+ err = me->md.osErrCode;
+ if (err != kOTNoError)
+ goto ErrorExit;
+
+ if (addrlen != NULL)
+ *addrlen = call.addr.len;
+
+ // Remove the temporary notifier we installed to set up the new endpoint.
+ OTRemoveNotifier((EndpointRef) newosfd);
+ PR_Free(endthr); // free the temporary context we set up for this endpoint
+
+ return newosfd;
+
+ErrorExit:
+ me->io_pending = PR_FALSE; // clear pending wait state if any
+ if (newosfd != -1)
+ _MD_closesocket(newosfd);
+ macsock_map_error(err);
+ return -1;
+}
+
+
+PRInt32 _MD_connect(PRFileDesc *fd, PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout)
+{
+ OSStatus err;
+ EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+ TCall sndCall;
+ TBind bindReq;
+ PRNetAddr bindAddr;
+
+ if (endpoint == NULL) {
+ err = kEBADFErr;
+ goto ErrorExit;
+ }
+
+ if (addr == NULL) {
+ err = kEFAULTErr;
+ goto ErrorExit;
+ }
+
+ // Bind to a local port; let the system assign it.
+
+ bindAddr.inet.family = AF_INET;
+ bindAddr.inet.port = bindAddr.inet.ip = 0;
+
+ bindReq.addr.maxlen = PR_NETADDR_SIZE (&bindAddr);
+ bindReq.addr.len = 0;
+ bindReq.addr.buf = (UInt8*) &bindAddr;
+ bindReq.qlen = 0;
+
+ PR_Lock(fd->secret->md.miscLock);
+ PrepareForAsyncCompletion(me, fd->secret->md.osfd);
+ fd->secret->md.misc.thread = me;
+
+ err = OTBind(endpoint, &bindReq, NULL);
+ if (err != kOTNoError) {
+ me->io_pending = PR_FALSE;
+ PR_Unlock(fd->secret->md.miscLock);
+ goto ErrorExit;
+ }
+
+ WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
+ PR_Unlock(fd->secret->md.miscLock);
+
+ err = me->md.osErrCode;
+ if (err != kOTNoError)
+ goto ErrorExit;
+
+ memset(&sndCall, 0 , sizeof(sndCall));
+
+ sndCall.addr.maxlen = addrlen;
+ sndCall.addr.len = addrlen;
+ sndCall.addr.buf = (UInt8*) addr;
+
+ if (!fd->secret->nonblocking) {
+ PrepareForAsyncCompletion(me, fd->secret->md.osfd);
+ PR_ASSERT(fd->secret->md.write.thread == NULL);
+ fd->secret->md.write.thread = me;
+ }
+
+ err = OTConnect (endpoint, &sndCall, NULL);
+ if (err == kOTNoError) {
+ PR_ASSERT(!"OTConnect returned kOTNoError in async mode!?!");
+ }
+ if (fd->secret->nonblocking) {
+ if (err == kOTNoDataErr)
+ err = EINPROGRESS;
+ goto ErrorExit;
+ } else {
+ if (err != kOTNoError && err != kOTNoDataErr) {
+ me->io_pending = PR_FALSE;
+ goto ErrorExit;
+ }
+ }
+
+ WaitOnThisThread(me, timeout);
+
+ err = me->md.osErrCode;
+ if (err != kOTNoError)
+ goto ErrorExit;
+
+ return kOTNoError;
+
+ErrorExit:
+ macsock_map_error(err);
+ return -1;
+}
+
+
+// Errors:
+// EBADF -- bad socket id
+// EFAULT -- bad buffer
+static PRInt32 SendReceiveStream(PRFileDesc *fd, void *buf, PRInt32 amount,
+ PRIntn flags, PRIntervalTime timeout, SndRcvOpCode opCode)
+{
+ OSStatus err;
+ OTResult result;
+ EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+ PRInt32 bytesLeft = amount;
+
+ PR_ASSERT(flags == 0 ||
+ (opCode == kSTREAM_RECEIVE && flags == PR_MSG_PEEK));
+ PR_ASSERT(opCode == kSTREAM_SEND || opCode == kSTREAM_RECEIVE);
+
+ if (endpoint == NULL) {
+ err = kEBADFErr;
+ goto ErrorExit;
+ }
+
+ if (buf == NULL) {
+ err = kEFAULTErr;
+ goto ErrorExit;
+ }
+
+ PR_ASSERT(opCode == kSTREAM_SEND ? fd->secret->md.write.thread == NULL :
+ fd->secret->md.read.thread == NULL);
+
+ while (bytesLeft > 0)
+ {
+ Boolean disabledNotifications = OTEnterNotifier(endpoint);
+
+ PrepareForAsyncCompletion(me, fd->secret->md.osfd);
+
+ if (opCode == kSTREAM_SEND) {
+ do {
+ fd->secret->md.write.thread = me;
+ fd->secret->md.writeReady = PR_FALSE; // expect the worst
+ result = OTSnd(endpoint, buf, bytesLeft, NULL);
+ fd->secret->md.writeReady = (result != kOTFlowErr);
+ if (fd->secret->nonblocking) // hope for the best
+ break;
+ else {
+
+ // We drop through on anything other than a blocking write.
+ if (result != kOTFlowErr)
+ break;
+
+ // Blocking write, but the pipe is full. Turn notifications on and
+ // wait for an event, hoping that it's a T_GODATA event.
+ if (disabledNotifications) {
+ OTLeaveNotifier(endpoint);
+ disabledNotifications = false;
+ }
+ WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
+ result = me->md.osErrCode;
+ if (result != kOTNoError) // got interrupted, or some other error
+ break;
+
+ // Prepare to loop back and try again
+ disabledNotifications = OTEnterNotifier(endpoint);
+ PrepareForAsyncCompletion(me, fd->secret->md.osfd);
+ }
+ }
+ while(1);
+ } else {
+ do {
+ fd->secret->md.read.thread = me;
+ fd->secret->md.readReady = PR_FALSE; // expect the worst
+ result = OTRcv(endpoint, buf, bytesLeft, NULL);
+ if (fd->secret->nonblocking) {
+ fd->secret->md.readReady = (result != kOTNoDataErr);
+ break;
+ } else {
+ if (result != kOTNoDataErr) {
+ // If we successfully read a blocking socket, check for more data.
+ // According to IM:OT, we should be able to rely on OTCountDataBytes
+ // to tell us whether there is a nonzero amount of data pending.
+ size_t count;
+ OSErr tmpResult;
+ tmpResult = OTCountDataBytes(endpoint, &count);
+ fd->secret->md.readReady = ((tmpResult == kOTNoError) && (count > 0));
+ break;
+ }
+
+ // Blocking read, but no data available. Turn notifications on and
+ // wait for an event on this endpoint, and hope that we get a T_DATA event.
+ if (disabledNotifications) {
+ OTLeaveNotifier(endpoint);
+ disabledNotifications = false;
+ }
+ WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
+ result = me->md.osErrCode;
+ if (result != kOTNoError) // interrupted thread, etc.
+ break;
+
+ // Prepare to loop back and try again
+ disabledNotifications = OTEnterNotifier(endpoint);
+ PrepareForAsyncCompletion(me, fd->secret->md.osfd);
+ }
+ }
+ // Retry read if we had to wait for data to show up.
+ while(1);
+ }
+
+ me->io_pending = PR_FALSE;
+
+ if (opCode == kSTREAM_SEND)
+ fd->secret->md.write.thread = NULL;
+ else
+ fd->secret->md.read.thread = NULL;
+
+ // turn notifications back on
+ if (disabledNotifications)
+ OTLeaveNotifier(endpoint);
+
+ if (result > 0) {
+ buf = (void *) ( (UInt32) buf + (UInt32)result );
+ bytesLeft -= result;
+ if (opCode == kSTREAM_RECEIVE) {
+ amount = result;
+ goto NormalExit;
+ }
+ } else {
+ switch (result) {
+ case kOTLookErr:
+ PR_ASSERT(!"call to OTLook() required after all.");
+ break;
+
+ case kOTFlowErr:
+ case kOTNoDataErr:
+ case kEAGAINErr:
+ case kEWOULDBLOCKErr:
+ if (fd->secret->nonblocking) {
+
+ if (bytesLeft == amount) { // no data was sent
+ err = result;
+ goto ErrorExit;
+ }
+
+ // some data was sent
+ amount -= bytesLeft;
+ goto NormalExit;
+ }
+
+ WaitOnThisThread(me, timeout);
+ err = me->md.osErrCode;
+ if (err != kOTNoError)
+ goto ErrorExit;
+ break;
+
+ case kOTOutStateErr: // if provider already closed, fall through to handle error
+ if (fd->secret->md.orderlyDisconnect) {
+ amount = 0;
+ goto NormalExit;
+ }
+ // else fall through
+ default:
+ err = result;
+ goto ErrorExit;
+ }
+ }
+ }
+
+NormalExit:
+ PR_ASSERT(opCode == kSTREAM_SEND ? fd->secret->md.write.thread == NULL :
+ fd->secret->md.read.thread == NULL);
+ return amount;
+
+ErrorExit:
+ PR_ASSERT(opCode == kSTREAM_SEND ? fd->secret->md.write.thread == NULL :
+ fd->secret->md.read.thread == NULL);
+ macsock_map_error(err);
+ return -1;
+}
+
+
+PRInt32 _MD_recv(PRFileDesc *fd, void *buf, PRInt32 amount,
+ PRIntn flags, PRIntervalTime timeout)
+{
+ return (SendReceiveStream(fd, buf, amount, flags, timeout, kSTREAM_RECEIVE));
+}
+
+
+PRInt32 _MD_send(PRFileDesc *fd,const void *buf, PRInt32 amount,
+ PRIntn flags, PRIntervalTime timeout)
+{
+ return (SendReceiveStream(fd, (void *)buf, amount, flags, timeout, kSTREAM_SEND));
+}
+
+
+// Errors:
+// EBADF -- bad socket id
+// EFAULT -- bad buffer
+static PRInt32 SendReceiveDgram(PRFileDesc *fd, void *buf, PRInt32 amount,
+ PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen,
+ PRIntervalTime timeout, SndRcvOpCode opCode)
+{
+ OSStatus err;
+ EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+ PRInt32 bytesLeft = amount;
+ TUnitData dgram;
+
+ PR_ASSERT(flags == 0);
+
+ if (endpoint == NULL) {
+ err = kEBADFErr;
+ goto ErrorExit;
+ }
+
+ if (buf == NULL || addr == NULL) {
+ err = kEFAULTErr;
+ goto ErrorExit;
+ }
+
+ if (opCode != kDGRAM_SEND && opCode != kDGRAM_RECEIVE) {
+ err = kEINVALErr;
+ goto ErrorExit;
+ }
+
+ memset(&dgram, 0 , sizeof(dgram));
+ dgram.addr.maxlen = *addrlen;
+ dgram.addr.len = *addrlen;
+ dgram.addr.buf = (UInt8*) addr;
+ dgram.udata.maxlen = amount;
+ dgram.udata.len = amount;
+ dgram.udata.buf = (UInt8*) buf;
+
+ while (bytesLeft > 0) {
+
+ PrepareForAsyncCompletion(me, fd->secret->md.osfd);
+
+ if (opCode == kDGRAM_SEND) {
+ fd->secret->md.write.thread = me;
+ fd->secret->md.writeReady = PR_FALSE; // expect the worst
+ err = OTSndUData(endpoint, &dgram);
+ if (err != kOTFlowErr) // hope for the best
+ fd->secret->md.writeReady = PR_TRUE;
+ } else {
+ fd->secret->md.read.thread = me;
+ fd->secret->md.readReady = PR_FALSE; // expect the worst
+ err = OTRcvUData(endpoint, &dgram, NULL);
+ if (err != kOTNoDataErr) // hope for the best
+ fd->secret->md.readReady = PR_TRUE;
+ }
+
+ if (err == kOTNoError) {
+ buf = (void *) ( (UInt32) buf + (UInt32)dgram.udata.len );
+ bytesLeft -= dgram.udata.len;
+ dgram.udata.buf = (UInt8*) buf;
+ me->io_pending = PR_FALSE;
+ } else {
+ PR_ASSERT(err == kOTNoDataErr || err == kOTOutStateErr);
+ WaitOnThisThread(me, timeout);
+ err = me->md.osErrCode;
+ if (err != kOTNoError)
+ goto ErrorExit;
+ }
+ }
+
+ if (opCode == kDGRAM_RECEIVE)
+ *addrlen = dgram.addr.len;
+
+ return amount;
+
+ErrorExit:
+ macsock_map_error(err);
+ return -1;
+}
+
+
+PRInt32 _MD_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount,
+ PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen,
+ PRIntervalTime timeout)
+{
+ return (SendReceiveDgram(fd, buf, amount, flags, addr, addrlen,
+ timeout, kDGRAM_RECEIVE));
+}
+
+
+PRInt32 _MD_sendto(PRFileDesc *fd,const void *buf, PRInt32 amount,
+ PRIntn flags, PRNetAddr *addr, PRUint32 addrlen,
+ PRIntervalTime timeout)
+{
+ return (SendReceiveDgram(fd, (void *)buf, amount, flags, addr, &addrlen,
+ timeout, kDGRAM_SEND));
+}
+
+
+PRInt32 _MD_closesocket(PRInt32 osfd)
+{
+ OSStatus err;
+ EndpointRef endpoint = (EndpointRef) osfd;
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+
+ if (endpoint == NULL) {
+ err = kEBADFErr;
+ goto ErrorExit;
+ }
+
+ if (me->io_pending && me->io_fd == osfd)
+ me->io_pending = PR_FALSE;
+
+ (void) OTSndOrderlyDisconnect(endpoint);
+ err = OTCloseProvider(endpoint);
+ if (err != kOTNoError)
+ goto ErrorExit;
+
+ return kOTNoError;
+
+ErrorExit:
+ macsock_map_error(err);
+ return -1;
+}
+
+
+PRInt32 _MD_writev(PRFileDesc *fd, const struct PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout)
+{
+#pragma unused (fd, iov, iov_size, timeout)
+
+ PR_ASSERT(0);
+ _PR_MD_CURRENT_THREAD()->md.osErrCode = unimpErr;
+ return -1;
+}
+
+// OT endpoint states are documented here:
+// http://gemma.apple.com/techpubs/mac/NetworkingOT/NetworkingWOT-27.html#MARKER-9-65
+//
+static PRBool GetState(PRFileDesc *fd, PRBool *readReady, PRBool *writeReady, PRBool *exceptReady)
+{
+ OTResult resultOT;
+ // hack to emulate BSD sockets; say that a socket that has disconnected
+ // is still readable.
+ size_t availableData = 1;
+ if (!fd->secret->md.orderlyDisconnect)
+ OTCountDataBytes((EndpointRef)fd->secret->md.osfd, &availableData);
+
+ *readReady = fd->secret->md.readReady && (availableData > 0);
+ *exceptReady = fd->secret->md.exceptReady;
+
+ resultOT = OTGetEndpointState((EndpointRef)fd->secret->md.osfd);
+ switch (resultOT) {
+ case T_IDLE:
+ case T_UNBND:
+ // the socket is not connected. Emulating BSD sockets,
+ // we mark it readable and writable. The next PR_Read
+ // or PR_Write will then fail. Usually, in this situation,
+ // fd->secret->md.exceptReady is also set, and returned if
+ // anyone is polling for it.
+ *readReady = PR_FALSE;
+ *writeReady = PR_FALSE;
+ break;
+
+ case T_DATAXFER: // data transfer
+ *writeReady = fd->secret->md.writeReady;
+ break;
+
+ case T_INREL: // incoming orderly release
+ *writeReady = fd->secret->md.writeReady;
+ break;
+
+ case T_OUTCON: // outgoing connection pending
+ case T_INCON: // incoming connection pending
+ case T_OUTREL: // outgoing orderly release
+ default:
+ *writeReady = PR_FALSE;
+ }
+
+ return *readReady || *writeReady || *exceptReady;
+}
+
+// check to see if any of the poll descriptors have data available
+// for reading or writing, by calling their poll methods (layered IO).
+static PRInt32 CheckPollDescMethods(PRPollDesc *pds, PRIntn npds, PRInt16 *outReadFlags, PRInt16 *outWriteFlags)
+{
+ PRInt32 ready = 0;
+ PRPollDesc *pd, *epd;
+ PRInt16 *readFlag, *writeFlag;
+
+ for (pd = pds, epd = pd + npds, readFlag = outReadFlags, writeFlag = outWriteFlags;
+ pd < epd;
+ pd++, readFlag++, writeFlag++)
+ {
+ PRInt16 in_flags_read = 0, in_flags_write = 0;
+ PRInt16 out_flags_read = 0, out_flags_write = 0;
+
+ pd->out_flags = 0;
+
+ if (NULL == pd->fd || pd->in_flags == 0) continue;
+
+ if (pd->in_flags & PR_POLL_READ)
+ {
+ in_flags_read = (pd->fd->methods->poll)(
+ pd->fd, pd->in_flags & ~PR_POLL_WRITE, &out_flags_read);
+ }
+
+ if (pd->in_flags & PR_POLL_WRITE)
+ {
+ in_flags_write = (pd->fd->methods->poll)(
+ pd->fd, pd->in_flags & ~PR_POLL_READ, &out_flags_write);
+ }
+
+ if ((0 != (in_flags_read & out_flags_read)) ||
+ (0 != (in_flags_write & out_flags_write)))
+ {
+ ready += 1; /* some layer has buffer input */
+ pd->out_flags = out_flags_read | out_flags_write;
+ }
+
+ *readFlag = in_flags_read;
+ *writeFlag = in_flags_write;
+ }
+
+ return ready;
+}
+
+// check to see if any of OT endpoints of the poll descriptors have data available
+// for reading or writing.
+static PRInt32 CheckPollDescEndpoints(PRPollDesc *pds, PRIntn npds, const PRInt16 *inReadFlags, const PRInt16 *inWriteFlags)
+{
+ PRInt32 ready = 0;
+ PRPollDesc *pd, *epd;
+ const PRInt16 *readFlag, *writeFlag;
+
+ for (pd = pds, epd = pd + npds, readFlag = inReadFlags, writeFlag = inWriteFlags;
+ pd < epd;
+ pd++, readFlag++, writeFlag++)
+ {
+ PRFileDesc *bottomFD;
+ PRBool readReady, writeReady, exceptReady;
+ PRInt16 in_flags_read = *readFlag;
+ PRInt16 in_flags_write = *writeFlag;
+
+ if (NULL == pd->fd || pd->in_flags == 0) continue;
+
+ if ((pd->in_flags & ~pd->out_flags) == 0) {
+ ready++;
+ continue;
+ }
+
+ bottomFD = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
+ /* bottomFD can be NULL for pollable sockets */
+ if (bottomFD)
+ {
+ if (_PR_FILEDESC_OPEN == bottomFD->secret->state)
+ {
+ if (GetState(bottomFD, &readReady, &writeReady, &exceptReady))
+ {
+ if (readReady)
+ {
+ if (in_flags_read & PR_POLL_READ)
+ pd->out_flags |= PR_POLL_READ;
+ if (in_flags_write & PR_POLL_READ)
+ pd->out_flags |= PR_POLL_WRITE;
+ }
+ if (writeReady)
+ {
+ if (in_flags_read & PR_POLL_WRITE)
+ pd->out_flags |= PR_POLL_READ;
+ if (in_flags_write & PR_POLL_WRITE)
+ pd->out_flags |= PR_POLL_WRITE;
+ }
+ if (exceptReady && (pd->in_flags & PR_POLL_EXCEPT))
+ {
+ pd->out_flags |= PR_POLL_EXCEPT;
+ }
+ }
+ if (0 != pd->out_flags) ready++;
+ }
+ else /* bad state */
+ {
+ ready += 1; /* this will cause an abrupt return */
+ pd->out_flags = PR_POLL_NVAL; /* bogii */
+ }
+ }
+ }
+
+ return ready;
+}
+
+
+// see how many of the poll descriptors are ready
+static PRInt32 CountReadyPollDescs(PRPollDesc *pds, PRIntn npds)
+{
+ PRInt32 ready = 0;
+ PRPollDesc *pd, *epd;
+
+ for (pd = pds, epd = pd + npds; pd < epd; pd++)
+ {
+ if (pd->out_flags)
+ ready ++;
+ }
+
+ return ready;
+}
+
+// set or clear the poll thread on the poll descriptors
+static void SetDescPollThread(PRPollDesc *pds, PRIntn npds, PRThread* thread)
+{
+ PRInt32 ready = 0;
+ PRPollDesc *pd, *epd;
+
+ for (pd = pds, epd = pd + npds; pd < epd; pd++)
+ {
+ if (pd->fd)
+ {
+ PRFileDesc *bottomFD = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
+ if (bottomFD && (_PR_FILEDESC_OPEN == bottomFD->secret->state))
+ {
+ if (pd->in_flags & PR_POLL_READ) {
+ PR_ASSERT(thread == NULL || bottomFD->secret->md.read.thread == NULL);
+ bottomFD->secret->md.read.thread = thread;
+ }
+
+ if (pd->in_flags & PR_POLL_WRITE) {
+ // it's possible for the writing thread to be non-null during
+ // a non-blocking connect, so we assert that we're on
+ // the same thread, or the thread is null.
+ // Note that it's strictly possible for the connect and poll
+ // to be on different threads, so ideally we need to assert
+ // that if md.write.thread is non-null, there is a non-blocking
+ // connect in progress.
+ PR_ASSERT(thread == NULL ||
+ (bottomFD->secret->md.write.thread == NULL ||
+ bottomFD->secret->md.write.thread == thread));
+ bottomFD->secret->md.write.thread = thread;
+ }
+ }
+ }
+ }
+}
+
+
+#define DESCRIPTOR_FLAGS_ARRAY_SIZE 32
+
+PRInt32 _MD_poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
+{
+ PRInt16 readFlagsArray[DESCRIPTOR_FLAGS_ARRAY_SIZE];
+ PRInt16 writeFlagsArray[DESCRIPTOR_FLAGS_ARRAY_SIZE];
+
+ PRInt16 *readFlags = readFlagsArray;
+ PRInt16 *writeFlags = writeFlagsArray;
+
+ PRInt16 *ioFlags = NULL;
+
+ PRThread *thread = _PR_MD_CURRENT_THREAD();
+ PRInt32 ready;
+
+ if (npds > DESCRIPTOR_FLAGS_ARRAY_SIZE)
+ {
+ // we allocate a single double-size array. The first half is used
+ // for read flags, and the second half for write flags.
+ ioFlags = (PRInt16*)PR_Malloc(sizeof(PRInt16) * npds * 2);
+ if (!ioFlags)
+ {
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+ return -1;
+ }
+
+ readFlags = ioFlags;
+ writeFlags = &ioFlags[npds];
+ }
+
+ // we have to be outside the lock when calling this, since
+ // it can call arbitrary user code (including other socket
+ // entry points)
+ ready = CheckPollDescMethods(pds, npds, readFlags, writeFlags);
+
+ if (!ready && timeout != PR_INTERVAL_NO_WAIT) {
+ intn is;
+
+
+ _PR_INTSOFF(is);
+ PR_Lock(thread->md.asyncIOLock);
+ PrepareForAsyncCompletion(thread, 0);
+
+ SetDescPollThread(pds, npds, thread);
+
+ (void)CheckPollDescEndpoints(pds, npds, readFlags, writeFlags);
+
+ PR_Unlock(thread->md.asyncIOLock);
+ _PR_FAST_INTSON(is);
+
+ ready = CountReadyPollDescs(pds, npds);
+
+ if (ready == 0) {
+ WaitOnThisThread(thread, timeout);
+
+ // since we may have been woken by a pollable event firing,
+ // we have to check both poll methods and endpoints.
+ (void)CheckPollDescMethods(pds, npds, readFlags, writeFlags);
+ ready = CheckPollDescEndpoints(pds, npds, readFlags, writeFlags);
+ }
+
+ thread->io_pending = PR_FALSE;
+ SetDescPollThread(pds, npds, NULL);
+ }
+ else {
+ ready = CheckPollDescEndpoints(pds, npds, readFlags, writeFlags);
+ }
+
+ if (readFlags != readFlagsArray)
+ PR_Free(ioFlags);
+
+ return ready;
+}
+
+
+void _MD_initfiledesc(PRFileDesc *fd)
+{
+ // Allocate a PR_Lock to arbitrate miscellaneous OT calls for this endpoint between threads
+ // We presume that only one thread will be making Read calls (Recv/Accept) and that only
+ // one thread will be making Write calls (Send/Connect) on the endpoint at a time.
+ if (fd->methods->file_type == PR_DESC_SOCKET_TCP ||
+ fd->methods->file_type == PR_DESC_SOCKET_UDP )
+ {
+ PR_ASSERT(fd->secret->md.miscLock == NULL);
+ fd->secret->md.miscLock = PR_NewLock();
+ PR_ASSERT(fd->secret->md.miscLock != NULL);
+ fd->secret->md.orderlyDisconnect = PR_FALSE;
+ fd->secret->md.readReady = PR_FALSE; // let's not presume we have data ready to read
+ fd->secret->md.writeReady = PR_TRUE; // let's presume we can write unless we hear otherwise
+ fd->secret->md.exceptReady = PR_FALSE;
+ }
+}
+
+
+void _MD_freefiledesc(PRFileDesc *fd)
+{
+ if (fd->secret->md.miscLock)
+ {
+ PR_ASSERT(fd->methods->file_type == PR_DESC_SOCKET_TCP || fd->methods->file_type == PR_DESC_SOCKET_UDP);
+ PR_DestroyLock(fd->secret->md.miscLock);
+ fd->secret->md.miscLock = NULL;
+ } else {
+ PR_ASSERT(fd->methods->file_type != PR_DESC_SOCKET_TCP && PR_DESC_SOCKET_TCP != PR_DESC_SOCKET_UDP);
+ }
+}
+
+// _MD_makenonblock is also used for sockets meant to be used for blocking I/O,
+// in order to install the notifier routine for async completion.
+void _MD_makenonblock(PRFileDesc *fd)
+{
+ // We simulate non-blocking mode using async mode rather
+ // than put the endpoint in non-blocking mode.
+ // We need to install the PRFileDesc as the contextPtr for the NotifierRoutine, but it
+ // didn't exist at the time the endpoint was created. It does now though...
+ ProviderRef endpointRef = (ProviderRef)fd->secret->md.osfd;
+ OSStatus err;
+
+ // Install fd->secret as the contextPtr for the Notifier function associated with this
+ // endpoint. We use this instead of the fd itself because:
+ // (a) in cases where you import I/O layers, the containing
+ // fd changes, but the secret structure does not;
+ // (b) the notifier func refers only to the secret data structure
+ // anyway.
+ err = OTInstallNotifier(endpointRef, NotifierRoutineUPP, fd->secret);
+ PR_ASSERT(err == kOTNoError);
+
+ // Now that we have a NotifierRoutine installed, we can make the endpoint asynchronous
+ err = OTSetAsynchronous(endpointRef);
+ PR_ASSERT(err == kOTNoError);
+}
+
+
+void _MD_initfdinheritable(PRFileDesc *fd, PRBool imported)
+{
+ /* XXX this function needs to be implemented */
+ fd->secret->inheritable = _PR_TRI_UNKNOWN;
+}
+
+
+void _MD_queryfdinheritable(PRFileDesc *fd)
+{
+ /* XXX this function needs to be implemented */
+ PR_ASSERT(0);
+}
+
+
+PR_IMPLEMENT(PRInt32) _MD_shutdown(PRFileDesc *fd, PRIntn how)
+{
+#pragma unused (fd, how)
+
+/* Just succeed silently!!! */
+return (0);
+}
+
+
+PR_IMPLEMENT(PRStatus)
+_MD_getpeername(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen)
+{
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+ EndpointRef ep = (EndpointRef) fd->secret->md.osfd;
+ InetAddress inetAddr;
+ TBind peerAddr;
+ OSErr err;
+
+ if (*addrlen < sizeof(InetAddress)) {
+
+ err = (OSErr) kEINVALErr;
+ goto ErrorExit;
+ }
+
+ peerAddr.addr.maxlen = sizeof(InetAddress);
+ peerAddr.addr.len = 0;
+ peerAddr.addr.buf = (UInt8*) &inetAddr;
+ peerAddr.qlen = 0;
+
+ PrepareForAsyncCompletion(me, fd->secret->md.osfd);
+ fd->secret->md.misc.thread = me; // tell notifier routine what to wake up
+
+ err = OTGetProtAddress(ep, NULL, &peerAddr);
+
+ if (err != kOTNoError)
+ goto ErrorExit;
+
+ WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
+
+ err = me->md.osErrCode;
+ if ((err == kOTNoError) && (peerAddr.addr.len < sizeof(InetAddress)))
+ err = kEBADFErr; // we don't understand the address we got
+ if (err != kOTNoError)
+ goto ErrorExit;
+
+ // Translate the OT peer information into an NSPR address.
+ addr->inet.family = AF_INET;
+ addr->inet.port = (PRUint16) inetAddr.fPort;
+ addr->inet.ip = (PRUint32) inetAddr.fHost;
+
+ *addrlen = PR_NETADDR_SIZE(addr); // return the amount of data obtained
+ return PR_SUCCESS;
+
+ErrorExit:
+ macsock_map_error(err);
+ return PR_FAILURE;
+}
+
+
+PR_IMPLEMENT(unsigned long) inet_addr(const char *cp)
+{
+ OSStatus err;
+ InetHost host;
+
+ _MD_FinishInitNetAccess();
+
+ err = OTInetStringToHost((char*) cp, &host);
+ if (err != kOTNoError)
+ return -1;
+
+ return host;
+}
+
+
+static char *sAliases[1] = {NULL};
+static struct hostent sHostEnt = {NULL, &sAliases[0], AF_INET, sizeof (long), NULL};
+static InetHostInfo sHostInfo;
+static InetHost *sAddresses[kMaxHostAddrs+1];
+
+
+PR_IMPLEMENT(struct hostent *) gethostbyname(const char * name)
+{
+ OSStatus err;
+ PRUint32 index;
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+
+ _MD_FinishInitNetAccess();
+
+ me->io_pending = PR_TRUE;
+ me->io_fd = NULL;
+ me->md.osErrCode = noErr;
+
+ PR_Lock(dnsContext.lock); // so we can safely store our thread ptr in dnsContext
+ dnsContext.thread = me; // so we know what thread to wake up when OTInetStringToAddress completes
+
+ err = OTInetStringToAddress(dnsContext.serviceRef, (char *)name, &sHostInfo);
+ if (err != kOTNoError) {
+ me->io_pending = PR_FALSE;
+ me->md.osErrCode = err;
+ goto ErrorExit;
+ }
+
+ WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
+ PR_Unlock(dnsContext.lock);
+
+ if (me->md.osErrCode != kOTNoError)
+ goto ErrorExit;
+
+ sHostEnt.h_name = sHostInfo.name;
+ for (index=0; index<kMaxHostAddrs && sHostInfo.addrs[index] != NULL; index++)
+ sAddresses[index] = &sHostInfo.addrs[index];
+ sAddresses[index] = NULL;
+ sHostEnt.h_addr_list = (char **)sAddresses;
+
+ return (&sHostEnt);
+
+ErrorExit:
+ return NULL;
+}
+
+
+PR_IMPLEMENT(struct hostent *) gethostbyaddr(const void *addr, int addrlen, int type)
+{
+ PR_ASSERT(type == AF_INET);
+ PR_ASSERT(addrlen == sizeof(struct in_addr));
+
+ _MD_FinishInitNetAccess();
+
+ OTInetHostToString((InetHost)addr, sHostInfo.name);
+
+ return (gethostbyname(sHostInfo.name));
+}
+
+
+PR_IMPLEMENT(char *) inet_ntoa(struct in_addr addr)
+{
+ _MD_FinishInitNetAccess();
+
+ OTInetHostToString((InetHost)addr.s_addr, sHostInfo.name);
+
+ return sHostInfo.name;
+}
+
+
+PRStatus _MD_gethostname(char *name, int namelen)
+{
+ OSStatus err;
+ InetInterfaceInfo info;
+
+ _MD_FinishInitNetAccess();
+
+ /*
+ * On a Macintosh, we don't have the concept of a local host name.
+ * We do though have an IP address & everyone should be happy with
+ * a string version of that for a name.
+ * The alternative here is to ping a local DNS for our name, they
+ * will often know it. This is the cheap, easiest, and safest way out.
+ */
+
+ /* Make sure the string is as long as the longest possible address */
+ if (namelen < strlen("123.123.123.123")) {
+ err = kEINVALErr;
+ goto ErrorExit;
+ }
+
+ err = OTInetGetInterfaceInfo(&info, kDefaultInetInterface);
+ if (err != kOTNoError)
+ goto ErrorExit;
+
+ OTInetHostToString(info.fAddress, name);
+
+ return PR_SUCCESS;
+
+ErrorExit:
+ macsock_map_error(err);
+ return PR_FAILURE;
+}
+
+
+#define kIPName "ip"
+static struct protoent sIPProto = {kIPName, NULL, INET_IP};
+static struct protoent sTCPProto = {kTCPName, NULL, INET_TCP};
+static struct protoent sUDPProto = {kUDPName, NULL, INET_UDP};
+
+PR_IMPLEMENT(struct protoent *) getprotobyname(const char * name)
+{
+ if (strcmp(name, kIPName) == 0)
+ return (&sIPProto);
+
+ if (strcmp(name, kTCPName) == 0)
+ return (&sTCPProto);
+
+ if (strcmp(name, kUDPName) == 0)
+ return (&sUDPProto);
+
+ErrorExit:
+ macsock_map_error(kEINVALErr);
+ return NULL;
+}
+
+
+PR_IMPLEMENT(struct protoent *) getprotobynumber(int number)
+{
+ if (number == INET_IP)
+ return (&sIPProto);
+
+ if (number == INET_TCP)
+ return (&sTCPProto);
+
+ if (number == INET_UDP)
+ return (&sUDPProto);
+
+ErrorExit:
+ macsock_map_error(kEINVALErr);
+ return NULL;
+}
+
+
+int _MD_mac_get_nonblocking_connect_error(PRFileDesc* fd)
+{
+ EndpointRef endpoint = (EndpointRef)fd->secret->md.osfd;
+ OTResult resultOT = OTGetEndpointState(endpoint);
+
+ switch (resultOT) {
+ case T_OUTCON:
+ macsock_map_error(EINPROGRESS);
+ return -1;
+
+ case T_DATAXFER:
+ return 0;
+
+ case T_IDLE:
+ macsock_map_error(fd->secret->md.disconnectError);
+ fd->secret->md.disconnectError = 0;
+ return -1;
+
+ case T_INREL:
+ macsock_map_error(ENOTCONN);
+ return -1;
+
+ default:
+ PR_ASSERT(0);
+ return -1;
+ }
+
+ return -1; // not reached
+}
diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macthr.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macthr.c
new file mode 100644
index 00000000..292389ea
--- /dev/null
+++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macthr.c
@@ -0,0 +1,721 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "primpl.h"
+
+#include <string.h>
+
+#include <MacTypes.h>
+#include <Timer.h>
+#include <OSUtils.h>
+#include <Math64.h>
+#include <LowMem.h>
+#include <Multiprocessing.h>
+#include <Gestalt.h>
+
+#include "mdcriticalregion.h"
+
+TimerUPP gTimerCallbackUPP = NULL;
+PRThread * gPrimaryThread = NULL;
+
+ProcessSerialNumber gApplicationProcess;
+
+PR_IMPLEMENT(PRThread *) PR_GetPrimaryThread()
+{
+ return gPrimaryThread;
+}
+
+//##############################################################################
+//##############################################################################
+#pragma mark -
+#pragma mark CREATING MACINTOSH THREAD STACKS
+
+#if defined(GC_LEAK_DETECTOR)
+extern void* GC_malloc_atomic(PRUint32 size);
+#endif
+
+/*
+** Allocate a new memory segment. We allocate it from our figment heap. Currently,
+** it is being used for per thread stack space.
+**
+** Return the segment's access rights and size. vaddr is used on Unix platforms to
+** map an existing address for the segment.
+*/
+PRStatus _MD_AllocSegment(PRSegment *seg, PRUint32 size, void *vaddr)
+{
+ PR_ASSERT(seg != 0);
+ PR_ASSERT(size != 0);
+ PR_ASSERT(vaddr == 0);
+
+ /*
+ ** Take the actual memory for the segment out of our Figment heap.
+ */
+
+#if defined(GC_LEAK_DETECTOR)
+ seg->vaddr = (char *)GC_malloc_atomic(size);
+#else
+ seg->vaddr = (char *)malloc(size);
+#endif
+
+ if (seg->vaddr == NULL) {
+
+#if DEBUG
+ DebugStr("\p_MD_AllocSegment failed.");
+#endif
+
+ return PR_FAILURE;
+ }
+
+ seg->size = size;
+
+ return PR_SUCCESS;
+}
+
+
+/*
+** Free previously allocated memory segment.
+*/
+void _MD_FreeSegment(PRSegment *seg)
+{
+ PR_ASSERT((seg->flags & _PR_SEG_VM) == 0);
+
+ if (seg->vaddr != NULL)
+ free(seg->vaddr);
+}
+
+
+/*
+** The thread's stack has been allocated and its fields are already properly filled
+** in by PR. Perform any debugging related initialization here.
+**
+** Put a recognizable pattern so that we can find it from Macsbug.
+** Put a cookie at the top of the stack so that we can find it from Macsbug.
+*/
+void _MD_InitStack(PRThreadStack *ts, int redZoneBytes)
+ {
+#pragma unused (redZoneBytes)
+#if DEVELOPER_DEBUG
+ // Put a cookie at the top of the stack so that we can find
+ // it from Macsbug.
+
+ memset(ts->allocBase, 0xDC, ts->stackSize);
+
+ ((UInt32 *)ts->stackTop)[-1] = 0xBEEFCAFE;
+ ((UInt32 *)ts->stackTop)[-2] = (UInt32)gPrimaryThread;
+ ((UInt32 *)ts->stackTop)[-3] = (UInt32)(ts);
+ ((UInt32 *)ts->stackBottom)[0] = 0xCAFEBEEF;
+#else
+#pragma unused (ts)
+#endif
+ }
+
+extern void _MD_ClearStack(PRThreadStack *ts)
+ {
+#if DEVELOPER_DEBUG
+ // Clear out our cookies.
+
+ memset(ts->allocBase, 0xEF, ts->allocSize);
+ ((UInt32 *)ts->stackTop)[-1] = 0;
+ ((UInt32 *)ts->stackTop)[-2] = 0;
+ ((UInt32 *)ts->stackTop)[-3] = 0;
+ ((UInt32 *)ts->stackBottom)[0] = 0;
+#else
+#pragma unused (ts)
+#endif
+ }
+
+
+//##############################################################################
+//##############################################################################
+#pragma mark -
+#pragma mark TIME MANAGER-BASED CLOCK
+
+// On Mac OS X, it's possible for the application to spend lots of time
+// in WaitNextEvent, yielding to other applications. Since NSPR threads are
+// cooperative here, this means that NSPR threads will also get very little
+// time to run. To kick ourselves out of a WaitNextEvent call when we have
+// determined that it's time to schedule another thread, the Timer Task
+// (which fires every 8ms, even when other apps have the CPU) calls WakeUpProcess.
+// We only want to do this on Mac OS X; the gTimeManagerTaskDoesWUP variable
+// indicates when we're running on that OS.
+//
+// Note that the TimerCallback makes use of gApplicationProcess. We need to
+// have set this up before the first possible run of the timer task; we do
+// so in _MD_EarlyInit().
+static Boolean gTimeManagerTaskDoesWUP;
+
+static TMTask gTimeManagerTaskElem;
+
+extern void _MD_IOInterrupt(void);
+_PRInterruptTable _pr_interruptTable[] = {
+ { "clock", _PR_MISSED_CLOCK, _PR_ClockInterrupt, },
+ { "i/o", _PR_MISSED_IO, _MD_IOInterrupt, },
+ { 0 }
+};
+
+#define kMacTimerInMiliSecs 8L
+
+pascal void TimerCallback(TMTaskPtr tmTaskPtr)
+{
+ _PRCPU *cpu = _PR_MD_CURRENT_CPU();
+ PRIntn is;
+
+ if (_PR_MD_GET_INTSOFF()) {
+ cpu->u.missed[cpu->where] |= _PR_MISSED_CLOCK;
+ PrimeTime((QElemPtr)tmTaskPtr, kMacTimerInMiliSecs);
+ return;
+ }
+
+ _PR_INTSOFF(is);
+
+ // And tell nspr that a clock interrupt occured.
+ _PR_ClockInterrupt();
+
+ if ((_PR_RUNQREADYMASK(cpu)) >> ((_PR_MD_CURRENT_THREAD()->priority))) {
+ if (gTimeManagerTaskDoesWUP) {
+ // We only want to call WakeUpProcess if we know that NSPR has managed to switch threads
+ // since the last call, otherwise we end up spewing out WakeUpProcess() calls while the
+ // application is blocking somewhere. This can interfere with events loops other than
+ // our own (see bug 158927).
+ if (UnsignedWideToUInt64(cpu->md.lastThreadSwitch) > UnsignedWideToUInt64(cpu->md.lastWakeUpProcess))
+ {
+ WakeUpProcess(&gApplicationProcess);
+ cpu->md.lastWakeUpProcess = UpTime();
+ }
+ }
+ _PR_SET_RESCHED_FLAG();
+ }
+
+ _PR_FAST_INTSON(is);
+
+ // Reset the clock timer so that we fire again.
+ PrimeTime((QElemPtr)tmTaskPtr, kMacTimerInMiliSecs);
+}
+
+
+void _MD_StartInterrupts(void)
+{
+ gPrimaryThread = _PR_MD_CURRENT_THREAD();
+
+ gTimeManagerTaskDoesWUP = RunningOnOSX();
+
+ if ( !gTimerCallbackUPP )
+ gTimerCallbackUPP = NewTimerUPP(TimerCallback);
+
+ // Fill in the Time Manager queue element
+
+ gTimeManagerTaskElem.tmAddr = (TimerUPP)gTimerCallbackUPP;
+ gTimeManagerTaskElem.tmCount = 0;
+ gTimeManagerTaskElem.tmWakeUp = 0;
+ gTimeManagerTaskElem.tmReserved = 0;
+
+ // Make sure that our time manager task is ready to go.
+ InsTime((QElemPtr)&gTimeManagerTaskElem);
+
+ PrimeTime((QElemPtr)&gTimeManagerTaskElem, kMacTimerInMiliSecs);
+}
+
+void _MD_StopInterrupts(void)
+{
+ if (gTimeManagerTaskElem.tmAddr != NULL) {
+ RmvTime((QElemPtr)&gTimeManagerTaskElem);
+ gTimeManagerTaskElem.tmAddr = NULL;
+ }
+}
+
+
+#define MAX_PAUSE_TIMEOUT_MS 500
+
+void _MD_PauseCPU(PRIntervalTime timeout)
+{
+ if (timeout != PR_INTERVAL_NO_WAIT)
+ {
+ // There is a race condition entering the critical section
+ // in AsyncIOCompletion (and probably elsewhere) that can
+ // causes deadlock for the duration of this timeout. To
+ // work around this, use a max 500ms timeout for now.
+ // See bug 99561 for details.
+ if (PR_IntervalToMilliseconds(timeout) > MAX_PAUSE_TIMEOUT_MS)
+ timeout = PR_MillisecondsToInterval(MAX_PAUSE_TIMEOUT_MS);
+
+ WaitOnIdleSemaphore(timeout);
+ (void) _MD_IOInterrupt();
+ }
+}
+
+void _MD_InitRunningCPU(_PRCPU* cpu)
+{
+ cpu->md.trackScheduling = RunningOnOSX();
+ if (cpu->md.trackScheduling) {
+ AbsoluteTime zeroTime = {0, 0};
+ cpu->md.lastThreadSwitch = UpTime();
+ cpu->md.lastWakeUpProcess = zeroTime;
+ }
+}
+
+
+//##############################################################################
+//##############################################################################
+#pragma mark -
+#pragma mark THREAD SUPPORT FUNCTIONS
+
+#include <OpenTransport.h> /* for error codes */
+
+PRStatus _MD_InitThread(PRThread *thread)
+{
+ thread->md.asyncIOLock = PR_NewLock();
+ PR_ASSERT(thread->md.asyncIOLock != NULL);
+ thread->md.asyncIOCVar = PR_NewCondVar(thread->md.asyncIOLock);
+ PR_ASSERT(thread->md.asyncIOCVar != NULL);
+
+ if (thread->md.asyncIOLock == NULL || thread->md.asyncIOCVar == NULL)
+ return PR_FAILURE;
+ else
+ return PR_SUCCESS;
+}
+
+PRStatus _MD_wait(PRThread *thread, PRIntervalTime timeout)
+{
+#pragma unused (timeout)
+
+ _MD_SWITCH_CONTEXT(thread);
+ return PR_SUCCESS;
+}
+
+
+void WaitOnThisThread(PRThread *thread, PRIntervalTime timeout)
+{
+ intn is;
+ PRIntervalTime timein = PR_IntervalNow();
+ PRStatus status = PR_SUCCESS;
+
+ // Turn interrupts off to avoid a race over lock ownership with the callback
+ // (which can fire at any time). Interrupts may stay off until we leave
+ // this function, or another NSPR thread turns them back on. They certainly
+ // stay off until PR_WaitCondVar() relinquishes the asyncIOLock lock, which
+ // is what we care about.
+ _PR_INTSOFF(is);
+ PR_Lock(thread->md.asyncIOLock);
+ if (timeout == PR_INTERVAL_NO_TIMEOUT) {
+ while ((thread->io_pending) && (status == PR_SUCCESS))
+ status = PR_WaitCondVar(thread->md.asyncIOCVar, PR_INTERVAL_NO_TIMEOUT);
+ } else {
+ while ((thread->io_pending) && ((PRIntervalTime)(PR_IntervalNow() - timein) < timeout) && (status == PR_SUCCESS))
+ status = PR_WaitCondVar(thread->md.asyncIOCVar, timeout);
+ }
+ if ((status == PR_FAILURE) && (PR_GetError() == PR_PENDING_INTERRUPT_ERROR)) {
+ thread->md.osErrCode = kEINTRErr;
+ } else if (thread->io_pending) {
+ thread->md.osErrCode = kETIMEDOUTErr;
+ PR_SetError(PR_IO_TIMEOUT_ERROR, kETIMEDOUTErr);
+ }
+
+ thread->io_pending = PR_FALSE;
+ PR_Unlock(thread->md.asyncIOLock);
+ _PR_FAST_INTSON(is);
+}
+
+
+void DoneWaitingOnThisThread(PRThread *thread)
+{
+ intn is;
+
+ PR_ASSERT(thread->md.asyncIOLock->owner == NULL);
+
+ // DoneWaitingOnThisThread() is called from OT notifiers and async file I/O
+ // callbacks that can run at "interrupt" time (Classic Mac OS) or on pthreads
+ // that may run concurrently with the main threads (Mac OS X). They can thus
+ // be called when any NSPR thread is running, or even while NSPR is in a
+ // thread context switch. It is therefore vital that we can guarantee to
+ // be able to get the asyncIOLock without blocking (thus avoiding code
+ // that makes assumptions about the current NSPR thread etc). To achieve
+ // this, we use NSPR interrrupts as a semaphore on the lock; all code
+ // that grabs the lock also disables interrupts for the time the lock
+ // is held. Callers of DoneWaitingOnThisThread() thus have to check whether
+ // interrupts are already off, and, if so, simply set the missed_IO flag on
+ // the CPU rather than calling this function.
+
+ _PR_INTSOFF(is);
+ PR_Lock(thread->md.asyncIOLock);
+ thread->io_pending = PR_FALSE;
+ /* let the waiting thread know that async IO completed */
+ PR_NotifyCondVar(thread->md.asyncIOCVar);
+ PR_Unlock(thread->md.asyncIOLock);
+ _PR_FAST_INTSON(is);
+}
+
+
+PR_IMPLEMENT(void) PR_Mac_WaitForAsyncNotify(PRIntervalTime timeout)
+{
+ intn is;
+ PRIntervalTime timein = PR_IntervalNow();
+ PRStatus status = PR_SUCCESS;
+ PRThread *thread = _PR_MD_CURRENT_THREAD();
+
+ // See commments in WaitOnThisThread()
+ _PR_INTSOFF(is);
+ PR_Lock(thread->md.asyncIOLock);
+ if (timeout == PR_INTERVAL_NO_TIMEOUT) {
+ while ((!thread->md.asyncNotifyPending) && (status == PR_SUCCESS))
+ status = PR_WaitCondVar(thread->md.asyncIOCVar, PR_INTERVAL_NO_TIMEOUT);
+ } else {
+ while ((!thread->md.asyncNotifyPending) && ((PRIntervalTime)(PR_IntervalNow() - timein) < timeout) && (status == PR_SUCCESS))
+ status = PR_WaitCondVar(thread->md.asyncIOCVar, timeout);
+ }
+ if ((status == PR_FAILURE) && (PR_GetError() == PR_PENDING_INTERRUPT_ERROR)) {
+ thread->md.osErrCode = kEINTRErr;
+ } else if (!thread->md.asyncNotifyPending) {
+ thread->md.osErrCode = kETIMEDOUTErr;
+ PR_SetError(PR_IO_TIMEOUT_ERROR, kETIMEDOUTErr);
+ }
+ thread->md.asyncNotifyPending = PR_FALSE;
+ PR_Unlock(thread->md.asyncIOLock);
+ _PR_FAST_INTSON(is);
+}
+
+
+void AsyncNotify(PRThread *thread)
+{
+ intn is;
+
+ PR_ASSERT(thread->md.asyncIOLock->owner == NULL);
+
+ // See commments in DoneWaitingOnThisThread()
+ _PR_INTSOFF(is);
+ PR_Lock(thread->md.asyncIOLock);
+ thread->md.asyncNotifyPending = PR_TRUE;
+ /* let the waiting thread know that async IO completed */
+ PR_NotifyCondVar(thread->md.asyncIOCVar);
+ PR_Unlock(thread->md.asyncIOLock);
+ _PR_FAST_INTSON(is);
+}
+
+
+PR_IMPLEMENT(void) PR_Mac_PostAsyncNotify(PRThread *thread)
+{
+ _PRCPU * cpu = _PR_MD_CURRENT_CPU();
+
+ if (_PR_MD_GET_INTSOFF()) {
+ thread->md.missedAsyncNotify = PR_TRUE;
+ cpu->u.missed[cpu->where] |= _PR_MISSED_IO;
+ } else {
+ AsyncNotify(thread);
+ }
+}
+
+
+//##############################################################################
+//##############################################################################
+#pragma mark -
+#pragma mark PROCESS SUPPORT FUNCTIONS
+
+PRProcess * _MD_CreateProcess(
+ const char *path,
+ char *const *argv,
+ char *const *envp,
+ const PRProcessAttr *attr)
+{
+#pragma unused (path, argv, envp, attr)
+
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, unimpErr);
+ return NULL;
+}
+
+PRStatus _MD_DetachProcess(PRProcess *process)
+{
+#pragma unused (process)
+
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, unimpErr);
+ return PR_FAILURE;
+}
+
+PRStatus _MD_WaitProcess(PRProcess *process, PRInt32 *exitCode)
+{
+#pragma unused (process, exitCode)
+
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, unimpErr);
+ return PR_FAILURE;
+}
+
+PRStatus _MD_KillProcess(PRProcess *process)
+{
+#pragma unused (process)
+
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, unimpErr);
+ return PR_FAILURE;
+}
+
+//##############################################################################
+//##############################################################################
+#pragma mark -
+#pragma mark ATOMIC OPERATIONS
+
+#ifdef _PR_HAVE_ATOMIC_OPS
+PRInt32
+_MD_AtomicSet(PRInt32 *val, PRInt32 newval)
+{
+ PRInt32 rv;
+ do {
+ rv = *val;
+ } while (!OTCompareAndSwap32(rv, newval, (UInt32*)val));
+
+ return rv;
+}
+
+#endif // _PR_HAVE_ATOMIC_OPS
+
+//##############################################################################
+//##############################################################################
+#pragma mark -
+#pragma mark INTERRUPT SUPPORT
+
+#if TARGET_CARBON
+
+/*
+ This critical region support is required for Mac NSPR to work correctly on dual CPU
+ machines on Mac OS X. This note explains why.
+
+ NSPR uses a timer task, and has callbacks for async file I/O and Open Transport
+ whose runtime behaviour differs depending on environment. On "Classic" Mac OS
+ these run at "interrupt" time (OS-level interrupts, that is, not NSPR interrupts),
+ and can thus preempt other code, but they always run to completion.
+
+ On Mac OS X, these are all emulated using MP tasks, which sit atop pthreads. Thus,
+ they can be preempted at any time (and not necessarily run to completion), and can
+ also run *concurrently* with eachother, and with application code, on multiple
+ CPU machines. Note that all NSPR threads are emulated, and all run on the main
+ application MP task.
+
+ We thus have to use MP critical sections to protect data that is shared between
+ the various callbacks and the main MP thread. It so happens that NSPR has this
+ concept of software interrupts, and making interrupt-off times be critical
+ sections works.
+
+*/
+
+
+/*
+ Whether to use critical regions. True if running on Mac OS X and later
+*/
+
+PRBool gUseCriticalRegions;
+
+/*
+ Count of the number of times we've entered the critical region.
+ We need this because ENTER_CRITICAL_REGION() will *not* block when
+ called from different NSPR threads (which all run on one MP thread),
+ and we need to ensure that when code turns interrupts back on (by
+ settings _pr_intsOff to 0) we exit the critical section enough times
+ to leave it.
+*/
+
+PRInt32 gCriticalRegionEntryCount;
+
+
+void _MD_SetIntsOff(PRInt32 ints)
+{
+ ENTER_CRITICAL_REGION();
+ gCriticalRegionEntryCount ++;
+
+ _pr_intsOff = ints;
+
+ if (!ints)
+ {
+ PRInt32 i = gCriticalRegionEntryCount;
+
+ gCriticalRegionEntryCount = 0;
+ for ( ;i > 0; i --) {
+ LEAVE_CRITICAL_REGION();
+ }
+ }
+}
+
+
+#endif /* TARGET_CARBON */
+
+
+//##############################################################################
+//##############################################################################
+#pragma mark -
+#pragma mark CRITICAL REGION SUPPORT
+
+
+static PRBool RunningOnOSX()
+{
+ long systemVersion;
+ OSErr err = Gestalt(gestaltSystemVersion, &systemVersion);
+ return (err == noErr) && (systemVersion >= 0x00001000);
+}
+
+
+#if MAC_CRITICAL_REGIONS
+
+MDCriticalRegionID gCriticalRegion;
+
+void InitCriticalRegion()
+{
+ OSStatus err;
+
+ // we only need to do critical region stuff on Mac OS X
+ gUseCriticalRegions = RunningOnOSX();
+ if (!gUseCriticalRegions) return;
+
+ err = MD_CriticalRegionCreate(&gCriticalRegion);
+ PR_ASSERT(err == noErr);
+}
+
+void TermCriticalRegion()
+{
+ OSStatus err;
+
+ if (!gUseCriticalRegions) return;
+
+ err = MD_CriticalRegionDelete(gCriticalRegion);
+ PR_ASSERT(err == noErr);
+}
+
+
+void EnterCritialRegion()
+{
+ OSStatus err;
+
+ if (!gUseCriticalRegions) return;
+
+ PR_ASSERT(gCriticalRegion != kInvalidID);
+
+ /* Change to a non-infinite timeout for debugging purposes */
+ err = MD_CriticalRegionEnter(gCriticalRegion, kDurationForever /* 10000 * kDurationMillisecond */ );
+ PR_ASSERT(err == noErr);
+}
+
+void LeaveCritialRegion()
+{
+ OSStatus err;
+
+ if (!gUseCriticalRegions) return;
+
+ PR_ASSERT(gCriticalRegion != kInvalidID);
+
+ err = MD_CriticalRegionExit(gCriticalRegion);
+ PR_ASSERT(err == noErr);
+}
+
+
+#endif // MAC_CRITICAL_REGIONS
+
+//##############################################################################
+//##############################################################################
+#pragma mark -
+#pragma mark IDLE SEMAPHORE SUPPORT
+
+/*
+ Since the WaitNextEvent() in _MD_PauseCPU() is causing all sorts of
+ headache under Mac OS X we're going to switch to MPWaitOnSemaphore()
+ which should do what we want
+*/
+
+#if TARGET_CARBON
+PRBool gUseIdleSemaphore = PR_FALSE;
+MPSemaphoreID gIdleSemaphore = NULL;
+#endif
+
+void InitIdleSemaphore()
+{
+ // we only need to do idle semaphore stuff on Mac OS X
+#if TARGET_CARBON
+ gUseIdleSemaphore = RunningOnOSX();
+ if (gUseIdleSemaphore)
+ {
+ OSStatus err = MPCreateSemaphore(1 /* max value */, 0 /* initial value */, &gIdleSemaphore);
+ PR_ASSERT(err == noErr);
+ }
+#endif
+}
+
+void TermIdleSemaphore()
+{
+#if TARGET_CARBON
+ if (gUseIdleSemaphore)
+ {
+ OSStatus err = MPDeleteSemaphore(gIdleSemaphore);
+ PR_ASSERT(err == noErr);
+ gUseIdleSemaphore = NULL;
+ }
+#endif
+}
+
+
+void WaitOnIdleSemaphore(PRIntervalTime timeout)
+{
+#if TARGET_CARBON
+ if (gUseIdleSemaphore)
+ {
+ OSStatus err = MPWaitOnSemaphore(gIdleSemaphore, kDurationMillisecond * PR_IntervalToMilliseconds(timeout));
+ PR_ASSERT(err == noErr);
+ }
+ else
+#endif
+ {
+ EventRecord theEvent;
+ /*
+ ** Calling WaitNextEvent() here is suboptimal. This routine should
+ ** pause the process until IO or the timeout occur, yielding time to
+ ** other processes on operating systems that require this (Mac OS classic).
+ ** WaitNextEvent() may incur too much latency, and has other problems,
+ ** such as the potential to drop suspend/resume events.
+ */
+ (void)WaitNextEvent(nullEvent, &theEvent, 1, NULL);
+ }
+}
+
+
+void SignalIdleSemaphore()
+{
+#if TARGET_CARBON
+ if (gUseIdleSemaphore)
+ {
+ // often we won't be waiting on the semaphore here, so ignore any errors
+ (void)MPSignalSemaphore(gIdleSemaphore);
+ }
+ else
+#endif
+ {
+ WakeUpProcess(&gApplicationProcess);
+ }
+}
+
+
diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mactime.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mactime.c
new file mode 100644
index 00000000..1e7d2a22
--- /dev/null
+++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mactime.c
@@ -0,0 +1,253 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <OSUtils.h>
+#include <Timer.h>
+
+#include "primpl.h"
+
+#include "mactime.h"
+
+unsigned long gJanuaryFirst1970Seconds;
+
+/*
+ * The geographic location and time zone information of a Mac
+ * are stored in extended parameter RAM. The ReadLocation
+ * produdure uses the geographic location record, MachineLocation,
+ * to read the geographic location and time zone information in
+ * extended parameter RAM.
+ *
+ * Because serial port and SLIP conflict with ReadXPram calls,
+ * we cache the call here.
+ *
+ * Caveat: this caching will give the wrong result if a session
+ * extend across the DST changeover time.
+ */
+
+static void MyReadLocation(MachineLocation *loc)
+{
+ static MachineLocation storedLoc;
+ static Boolean didReadLocation = false;
+
+ if (!didReadLocation) {
+ ReadLocation(&storedLoc);
+ didReadLocation = true;
+ }
+ *loc = storedLoc;
+}
+
+static long GMTDelta(void)
+{
+ MachineLocation loc;
+ long gmtDelta;
+
+ MyReadLocation(&loc);
+ gmtDelta = loc.u.gmtDelta & 0x00ffffff;
+ if (gmtDelta & 0x00800000) { /* test sign extend bit */
+ gmtDelta |= 0xff000000;
+ }
+ return gmtDelta;
+}
+
+void MacintoshInitializeTime(void)
+{
+ /*
+ * The NSPR epoch is midnight, Jan. 1, 1970 GMT.
+ *
+ * At midnight Jan. 1, 1970 GMT, the local time was
+ * midnight Jan. 1, 1970 + GMTDelta().
+ *
+ * Midnight Jan. 1, 1970 is 86400 * (365 * (1970 - 1904) + 17)
+ * = 2082844800 seconds since the Mac epoch.
+ * (There were 17 leap years from 1904 to 1970.)
+ *
+ * So the NSPR epoch is 2082844800 + GMTDelta() seconds since
+ * the Mac epoch. Whew! :-)
+ */
+ gJanuaryFirst1970Seconds = 2082844800 + GMTDelta();
+}
+
+/*
+ *-----------------------------------------------------------------------
+ *
+ * PR_Now --
+ *
+ * Returns the current time in microseconds since the epoch.
+ * The epoch is midnight January 1, 1970 GMT.
+ * The implementation is machine dependent. This is the Mac
+ * Implementation.
+ * Cf. time_t time(time_t *tp)
+ *
+ *-----------------------------------------------------------------------
+ */
+
+PRTime PR_Now(void)
+{
+ unsigned long currentTime; /* unsigned 32-bit integer, ranging
+ from midnight Jan. 1, 1904 to
+ 6:28:15 AM Feb. 6, 2040 */
+ PRTime retVal;
+ int64 usecPerSec;
+
+ /*
+ * Get the current time expressed as the number of seconds
+ * elapsed since the Mac epoch, midnight, Jan. 1, 1904 (local time).
+ * On a Mac, current time accuracy is up to a second.
+ */
+ GetDateTime(&currentTime);
+
+ /*
+ * Express the current time relative to the NSPR epoch,
+ * midnight, Jan. 1, 1970 GMT.
+ *
+ * At midnight Jan. 1, 1970 GMT, the local time was
+ * midnight Jan. 1, 1970 + GMTDelta().
+ *
+ * Midnight Jan. 1, 1970 is 86400 * (365 * (1970 - 1904) + 17)
+ * = 2082844800 seconds since the Mac epoch.
+ * (There were 17 leap years from 1904 to 1970.)
+ *
+ * So the NSPR epoch is 2082844800 + GMTDelta() seconds since
+ * the Mac epoch. Whew! :-)
+ */
+ currentTime = currentTime - 2082844800 - GMTDelta();
+
+ /* Convert seconds to microseconds */
+ LL_I2L(usecPerSec, PR_USEC_PER_SEC);
+ LL_I2L(retVal, currentTime);
+ LL_MUL(retVal, retVal, usecPerSec);
+
+ return retVal;
+}
+
+/*
+ *-------------------------------------------------------------------------
+ *
+ * PR_LocalTimeParameters --
+ *
+ * returns the time parameters for the local time zone
+ *
+ * This is the machine-dependent implementation for Mac.
+ *
+ * Caveat: On a Mac, we only know the GMT and DST offsets for
+ * the current time, not for the time in question.
+ * Mac has no support for DST handling.
+ * DST changeover is all manually set by the user.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+PRTimeParameters PR_LocalTimeParameters(const PRExplodedTime *gmt)
+{
+#pragma unused (gmt)
+
+ PRTimeParameters retVal;
+ MachineLocation loc;
+
+ MyReadLocation(&loc);
+
+ /*
+ * On a Mac, the GMT value is in seconds east of GMT. For example,
+ * San Francisco is at -28,800 seconds (8 hours * 3600 seconds per hour)
+ * east of GMT. The gmtDelta field is a 3-byte value contained in a
+ * long word, so you must take care to get it properly.
+ */
+
+ retVal.tp_gmt_offset = loc.u.gmtDelta & 0x00ffffff;
+ if (retVal.tp_gmt_offset & 0x00800000) { /* test sign extend bit */
+ retVal.tp_gmt_offset |= 0xff000000;
+ }
+
+ /*
+ * The daylight saving time value, dlsDelta, is a signed byte
+ * value representing the offset for the hour field -- whether
+ * to add 1 hour, subtract 1 hour, or make no change at all.
+ */
+
+ if (loc.u.dlsDelta) {
+ retVal.tp_gmt_offset -= 3600;
+ retVal.tp_dst_offset = 3600;
+ } else {
+ retVal.tp_dst_offset = 0;
+ }
+ return retVal;
+}
+
+PRIntervalTime _MD_GetInterval(void)
+{
+ PRIntervalTime retVal;
+ PRUint64 upTime, microtomilli;
+
+ /*
+ * Use the Microseconds procedure to obtain the number of
+ * microseconds elapsed since system startup time.
+ */
+ Microseconds((UnsignedWide *)&upTime);
+ LL_I2L(microtomilli, PR_USEC_PER_MSEC);
+ LL_DIV(upTime, upTime, microtomilli);
+ LL_L2I(retVal, upTime);
+
+ return retVal;
+}
+
+struct tm *Maclocaltime(const time_t * t)
+{
+ DateTimeRec dtr;
+ MachineLocation loc;
+ time_t macLocal = *t + gJanuaryFirst1970Seconds; /* GMT Mac */
+ static struct tm statictime;
+ static const short monthday[12] =
+ {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
+
+ SecondsToDate(macLocal, &dtr);
+ statictime.tm_sec = dtr.second;
+ statictime.tm_min = dtr.minute;
+ statictime.tm_hour = dtr.hour;
+ statictime.tm_mday = dtr.day;
+ statictime.tm_mon = dtr.month - 1;
+ statictime.tm_year = dtr.year - 1900;
+ statictime.tm_wday = dtr.dayOfWeek - 1;
+ statictime.tm_yday = monthday[statictime.tm_mon]
+ + statictime.tm_mday - 1;
+ if (2 < statictime.tm_mon && !(statictime.tm_year & 3))
+ ++statictime.tm_yday;
+ MyReadLocation(&loc);
+ statictime.tm_isdst = loc.u.dlsDelta;
+ return(&statictime);
+}
+
+
diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mactime.h b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mactime.h
new file mode 100644
index 00000000..a78424df
--- /dev/null
+++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mactime.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+
+#ifndef mactime_h__
+#define mactime_h__
+
+
+PR_BEGIN_EXTERN_C
+
+void MacintoshInitializeTime(void);
+
+
+PR_END_EXTERN_C
+
+
+#endif /* mactime_h__ */
diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mdcriticalregion.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mdcriticalregion.c
new file mode 100644
index 00000000..15eea19a
--- /dev/null
+++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mdcriticalregion.c
@@ -0,0 +1,173 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: NULL; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * George Warner, Apple Computer Inc.
+ * Simon Fraser <sfraser@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "mdcriticalregion.h"
+#include <MacErrors.h>
+
+/*
+ This code is a replacement for MPEnterCriticalRegion/MPLeaveCriticalRegion,
+ which is broken on Mac OS 10.0.x builds, but fixed in 10.1. This code works
+ everywhere.
+*/
+
+
+typedef struct MDCriticalRegionData_struct {
+ MPTaskID mMPTaskID; /* Who's in the critical region? */
+ UInt32 mDepthCount; /* How deep? */
+ MPSemaphoreID mMPSemaphoreID; /* ready semaphore */
+} MDCriticalRegionData, *MDCriticalRegionDataPtr;
+
+
+OSStatus
+MD_CriticalRegionCreate(MDCriticalRegionID * outCriticalRegionID)
+{
+ MDCriticalRegionDataPtr newCriticalRegionPtr;
+ MPSemaphoreID mpSemaphoreID;
+ OSStatus err = noErr;
+
+ if (outCriticalRegionID == NULL)
+ return paramErr;
+
+ *outCriticalRegionID = NULL;
+
+ newCriticalRegionPtr = (MDCriticalRegionDataPtr)MPAllocateAligned(sizeof(MDCriticalRegionData),
+ kMPAllocateDefaultAligned, kMPAllocateClearMask);
+ if (newCriticalRegionPtr == NULL)
+ return memFullErr;
+
+ // Note: this semaphore is pre-fired (ready!)
+ err = MPCreateBinarySemaphore(&mpSemaphoreID);
+ if (err == noErr)
+ {
+ newCriticalRegionPtr->mMPTaskID = kInvalidID;
+ newCriticalRegionPtr->mDepthCount = 0;
+ newCriticalRegionPtr->mMPSemaphoreID = mpSemaphoreID;
+
+ *outCriticalRegionID = (MDCriticalRegionID)newCriticalRegionPtr;
+ }
+ else
+ {
+ MPFree((LogicalAddress)newCriticalRegionPtr);
+ }
+
+ return err;
+}
+
+OSStatus
+MD_CriticalRegionDelete(MDCriticalRegionID inCriticalRegionID)
+{
+ MDCriticalRegionDataPtr criticalRegion = (MDCriticalRegionDataPtr)inCriticalRegionID;
+ OSStatus err = noErr;
+
+ if (criticalRegion == NULL)
+ return paramErr;
+
+ if ((criticalRegion->mMPTaskID != kInvalidID) && (criticalRegion->mDepthCount > 0))
+ return kMPInsufficientResourcesErr;
+
+ if (criticalRegion->mMPSemaphoreID != kInvalidID)
+ err = MPDeleteSemaphore(criticalRegion->mMPSemaphoreID);
+ if (noErr != err) return err;
+
+ criticalRegion->mMPSemaphoreID = kInvalidID;
+ MPFree((LogicalAddress) criticalRegion);
+
+ return noErr;
+}
+
+OSStatus
+MD_CriticalRegionEnter(MDCriticalRegionID inCriticalRegionID, Duration inTimeout)
+{
+ MDCriticalRegionDataPtr criticalRegion = (MDCriticalRegionDataPtr)inCriticalRegionID;
+ MPTaskID currentTaskID = MPCurrentTaskID();
+ OSStatus err = noErr;
+
+ if (criticalRegion == NULL)
+ return paramErr;
+
+ // if I'm inside the critical region...
+ if (currentTaskID == criticalRegion->mMPTaskID)
+ {
+ // bump my depth
+ criticalRegion->mDepthCount++;
+ // and continue
+ return noErr;
+ }
+
+ // wait for the ready semaphore
+ err = MPWaitOnSemaphore(criticalRegion->mMPSemaphoreID, inTimeout);
+ // we didn't get it. return the error
+ if (noErr != err) return err;
+
+ // we got it!
+ criticalRegion->mMPTaskID = currentTaskID;
+ criticalRegion->mDepthCount = 1;
+
+ return noErr;
+}
+
+OSStatus
+MD_CriticalRegionExit(MDCriticalRegionID inCriticalRegionID)
+{
+ MDCriticalRegionDataPtr criticalRegion = (MDCriticalRegionDataPtr)inCriticalRegionID;
+ MPTaskID currentTaskID = MPCurrentTaskID();
+ OSStatus err = noErr;
+
+ // if we don't own the critical region...
+ if (currentTaskID != criticalRegion->mMPTaskID)
+ return kMPInsufficientResourcesErr;
+
+ // if we aren't at a depth...
+ if (criticalRegion->mDepthCount == 0)
+ return kMPInsufficientResourcesErr;
+
+ // un-bump my depth
+ criticalRegion->mDepthCount--;
+
+ // if we just bottomed out...
+ if (criticalRegion->mDepthCount == 0)
+ {
+ // release ownership of the structure
+ criticalRegion->mMPTaskID = kInvalidID;
+ // and signal the ready semaphore
+ err = MPSignalSemaphore(criticalRegion->mMPSemaphoreID);
+ }
+ return err;
+}
+
diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mdcriticalregion.h b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mdcriticalregion.h
new file mode 100644
index 00000000..abcd20e3
--- /dev/null
+++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mdcriticalregion.h
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * George Warner, Apple Computer Inc.
+ * Simon Fraser <sfraser@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef mdcriticalregion_h___
+#define mdcriticalregion_h___
+
+
+#ifndef __MULTIPROCESSING__
+#include <Multiprocessing.h>
+#endif
+
+typedef struct OpaqueMDCriticalRegionID* MDCriticalRegionID;
+
+OSStatus MD_CriticalRegionCreate(MDCriticalRegionID * pMDCriticalRegionID);
+
+OSStatus MD_CriticalRegionDelete(MDCriticalRegionID pMDCriticalRegionID);
+
+OSStatus MD_CriticalRegionEnter(MDCriticalRegionID pMDCriticalRegionID, Duration pTimeout);
+
+OSStatus MD_CriticalRegionExit(MDCriticalRegionID pMDCriticalRegionID);
+
+#endif /* mdcriticalregion_h___ */
+
diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mdmac.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mdmac.c
new file mode 100644
index 00000000..bcbb3f82
--- /dev/null
+++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mdmac.c
@@ -0,0 +1,776 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <Types.h>
+#include <Timer.h>
+#include <Files.h>
+#include <Errors.h>
+#include <Folders.h>
+#include <Gestalt.h>
+#include <Events.h>
+#include <Processes.h>
+#include <TextUtils.h>
+#include <MixedMode.h>
+#include <LowMem.h>
+
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stat.h>
+#include <stdarg.h>
+#include <unix.h>
+
+#include "MacErrorHandling.h"
+
+#include "primpl.h"
+#include "prgc.h"
+
+#include "mactime.h"
+
+#include "mdmac.h"
+
+// undefine getenv, so that _MD_GetEnv can call the version in NSStdLib::nsEnvironment.cpp.
+#undef getenv
+
+//
+// Local routines
+//
+unsigned char GarbageCollectorCacheFlusher(PRUint32 size);
+
+extern PRThread *gPrimaryThread;
+extern ProcessSerialNumber gApplicationProcess; // in macthr.c
+
+
+//##############################################################################
+//##############################################################################
+#pragma mark -
+#pragma mark CREATING MACINTOSH THREAD STACKS
+
+
+enum {
+ uppExitToShellProcInfo = kPascalStackBased,
+ uppStackSpaceProcInfo = kRegisterBased
+ | RESULT_SIZE(SIZE_CODE(sizeof(long)))
+ | REGISTER_RESULT_LOCATION(kRegisterD0)
+ | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(UInt16)))
+};
+
+typedef CALLBACK_API( long , StackSpacePatchPtr )(UInt16 trapNo);
+typedef REGISTER_UPP_TYPE(StackSpacePatchPtr) StackSpacePatchUPP;
+
+StackSpacePatchUPP gStackSpacePatchUPP = NULL;
+UniversalProcPtr gStackSpacePatchCallThru = NULL;
+long (*gCallOSTrapUniversalProc)(UniversalProcPtr,ProcInfoType,...) = NULL;
+
+
+pascal long StackSpacePatch(UInt16 trapNo)
+{
+ char tos;
+ PRThread *thisThread;
+
+ thisThread = PR_CurrentThread();
+
+ // If we are the primary thread, then call through to the
+ // good ol' fashion stack space implementation. Otherwise,
+ // compute it by hand.
+ if ((thisThread == gPrimaryThread) ||
+ (&tos < thisThread->stack->stackBottom) ||
+ (&tos > thisThread->stack->stackTop)) {
+ return gCallOSTrapUniversalProc(gStackSpacePatchCallThru, uppStackSpaceProcInfo, trapNo);
+ }
+ else {
+ return &tos - thisThread->stack->stackBottom;
+ }
+}
+
+
+static void InstallStackSpacePatch(void)
+{
+ long systemVersion;
+ OSErr err;
+ CFragConnectionID connID;
+ Str255 errMessage;
+ Ptr interfaceLibAddr;
+ CFragSymbolClass symClass;
+ UniversalProcPtr (*getOSTrapAddressProc)(UInt16);
+ void (*setOSTrapAddressProc)(StackSpacePatchUPP, UInt16);
+ UniversalProcPtr (*newRoutineDescriptorProc)(ProcPtr,ProcInfoType,ISAType);
+
+
+ err = Gestalt(gestaltSystemVersion,&systemVersion);
+ if (systemVersion >= 0x00000A00) // we don't need to patch StackSpace()
+ return;
+
+ // open connection to "InterfaceLib"
+ err = GetSharedLibrary("\pInterfaceLib", kPowerPCCFragArch, kFindCFrag,
+ &connID, &interfaceLibAddr, errMessage);
+ PR_ASSERT(err == noErr);
+ if (err != noErr)
+ return;
+
+ // get symbol GetOSTrapAddress
+ err = FindSymbol(connID, "\pGetOSTrapAddress", &(Ptr)getOSTrapAddressProc, &symClass);
+ if (err != noErr)
+ return;
+
+ // get symbol SetOSTrapAddress
+ err = FindSymbol(connID, "\pSetOSTrapAddress", &(Ptr)setOSTrapAddressProc, &symClass);
+ if (err != noErr)
+ return;
+
+ // get symbol NewRoutineDescriptor
+ err = FindSymbol(connID, "\pNewRoutineDescriptor", &(Ptr)newRoutineDescriptorProc, &symClass);
+ if (err != noErr)
+ return;
+
+ // get symbol CallOSTrapUniversalProc
+ err = FindSymbol(connID, "\pCallOSTrapUniversalProc", &(Ptr)gCallOSTrapUniversalProc, &symClass);
+ if (err != noErr)
+ return;
+
+ // get and set trap address for StackSpace (A065)
+ gStackSpacePatchCallThru = getOSTrapAddressProc(0x0065);
+ if (gStackSpacePatchCallThru)
+ {
+ gStackSpacePatchUPP =
+ (StackSpacePatchUPP)newRoutineDescriptorProc((ProcPtr)(StackSpacePatch), uppStackSpaceProcInfo, GetCurrentArchitecture());
+ setOSTrapAddressProc(gStackSpacePatchUPP, 0x0065);
+ }
+
+#if DEBUG
+ StackSpace();
+#endif
+}
+
+
+//##############################################################################
+//##############################################################################
+#pragma mark -
+#pragma mark ENVIRONMENT VARIABLES
+
+
+typedef struct EnvVariable EnvVariable;
+
+struct EnvVariable {
+ char *variable;
+ char *value;
+ EnvVariable *next;
+};
+
+EnvVariable *gEnvironmentVariables = NULL;
+
+char *_MD_GetEnv(const char *name)
+{
+ EnvVariable *currentVariable = gEnvironmentVariables;
+
+ while (currentVariable) {
+ if (!strcmp(currentVariable->variable, name))
+ return currentVariable->value;
+
+ currentVariable = currentVariable->next;
+ }
+
+ return getenv(name);
+}
+
+PR_IMPLEMENT(int)
+_MD_PutEnv(const char *string)
+{
+ EnvVariable *currentVariable = gEnvironmentVariables;
+ char *variableCopy,
+ *value,
+ *current;
+
+ variableCopy = strdup(string);
+ PR_ASSERT(variableCopy != NULL);
+
+ current = variableCopy;
+ while (*current != '=')
+ current++;
+
+ *current = 0;
+ current++;
+
+ value = current;
+
+ while (currentVariable) {
+ if (!strcmp(currentVariable->variable, variableCopy))
+ break;
+
+ currentVariable = currentVariable->next;
+ }
+
+ if (currentVariable == NULL) {
+ currentVariable = PR_NEW(EnvVariable);
+
+ if (currentVariable == NULL) {
+ PR_DELETE(variableCopy);
+ return -1;
+ }
+
+ currentVariable->variable = strdup(variableCopy);
+ currentVariable->value = strdup(value);
+ currentVariable->next = gEnvironmentVariables;
+ gEnvironmentVariables = currentVariable;
+ }
+
+ else {
+ PR_DELETE(currentVariable->value);
+ currentVariable->value = strdup(current);
+
+ /* This is a temporary hack. Working on a real fix, remove this when done. */
+ /* OK, there are two ways to access the */
+ /* library path, getenv() and PR_GetLibraryPath(). Take a look at PR_GetLibraryPath(). */
+ /* You'll see that we keep the path in a global which is intialized at startup from */
+ /* a call to getenv(). From then on, they have nothing in common. */
+ /* We need to keep them in synch. */
+ if (strcmp(currentVariable->variable, "LD_LIBRARY_PATH") == 0)
+ PR_SetLibraryPath(currentVariable->value);
+ }
+
+ PR_DELETE(variableCopy);
+ return 0;
+}
+
+
+
+//##############################################################################
+//##############################################################################
+#pragma mark -
+#pragma mark MISCELLANEOUS
+
+PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np)
+{
+ if (isCurrent) {
+ (void) setjmp(t->md.jb);
+ }
+ *np = sizeof(t->md.jb) / sizeof(PRUint32);
+ return (PRWord*) (t->md.jb);
+}
+
+void _MD_GetRegisters(PRUint32 *to)
+{
+ (void) setjmp((void*) to);
+}
+
+void _MD_EarlyInit()
+{
+ Handle environmentVariables;
+
+ GetCurrentProcess(&gApplicationProcess);
+
+ INIT_CRITICAL_REGION();
+ InitIdleSemaphore();
+
+#if !defined(MAC_NSPR_STANDALONE)
+ // MacintoshInitializeMemory(); Moved to mdmacmem.c: AllocateRawMemory(Size blockSize)
+#else
+ MacintoshInitializeMemory();
+#endif
+ MacintoshInitializeTime();
+
+ // Install resource-controlled environment variables.
+
+ environmentVariables = GetResource('Envi', 128);
+ if (environmentVariables != NULL) {
+
+ Size resourceSize;
+ char *currentPutEnvString = (char *)*environmentVariables,
+ *currentScanChar = currentPutEnvString;
+
+ resourceSize = GetHandleSize(environmentVariables);
+ DetachResource(environmentVariables);
+ HLock(environmentVariables);
+
+ while (resourceSize--) {
+
+ if ((*currentScanChar == '\n') || (*currentScanChar == '\r')) {
+ *currentScanChar = 0;
+ _MD_PutEnv (currentPutEnvString);
+ currentPutEnvString = currentScanChar + 1;
+ }
+
+ currentScanChar++;
+
+ }
+
+ DisposeHandle(environmentVariables);
+
+ }
+
+#ifdef PR_INTERNAL_LOGGING
+ _MD_PutEnv ("NSPR_LOG_MODULES=clock:6,cmon:6,io:6,mon:6,linker:6,cvar:6,sched:6,thread:6");
+#endif
+
+ InstallStackSpacePatch();
+}
+
+void _MD_FinalInit()
+{
+ _MD_InitNetAccess();
+}
+
+void PR_InitMemory(void) {
+#ifndef NSPR_AS_SHARED_LIB
+ // Needed for Mac browsers without Java. We don't want them calling PR_INIT, since it
+ // brings in all of the thread support. But we do need to allow them to initialize
+ // the NSPR memory package.
+ // This should go away when all clients of the NSPR want threads AND memory.
+ MacintoshInitializeMemory();
+#endif
+}
+
+//##############################################################################
+//##############################################################################
+#pragma mark -
+#pragma mark TERMINATION
+
+
+// THIS IS *** VERY *** IMPORTANT... our CFM Termination proc.
+// This allows us to deactivate our Time Mananger task even
+// if we are not totally gracefully exited. If this is not
+// done then we will randomly crash at later times when the
+// task is called after the app heap is gone.
+
+#if TARGET_CARBON
+extern OTClientContextPtr clientContext;
+#define CLOSE_OPEN_TRANSPORT() CloseOpenTransportInContext(clientContext)
+
+#else
+
+#define CLOSE_OPEN_TRANSPORT() CloseOpenTransport()
+#endif /* TARGET_CARBON */
+
+extern pascal void __NSTerminate(void);
+
+void CleanupTermProc(void)
+{
+ _MD_StopInterrupts(); // deactive Time Manager task
+
+ CLOSE_OPEN_TRANSPORT();
+ TermIdleSemaphore();
+ TERM_CRITICAL_REGION();
+
+ __NSTerminate();
+}
+
+
+
+//##############################################################################
+//##############################################################################
+#pragma mark -
+#pragma mark STRING OPERATIONS
+
+#if !defined(MAC_NSPR_STANDALONE)
+
+// PStrFromCStr converts the source C string to a destination
+// pascal string as it copies. The dest string will
+// be truncated to fit into an Str255 if necessary.
+// If the C String pointer is NULL, the pascal string's length is set to zero
+//
+void
+PStrFromCStr(const char* src, Str255 dst)
+{
+ short length = 0;
+
+ // handle case of overlapping strings
+ if ( (void*)src == (void*)dst )
+ {
+ unsigned char* curdst = &dst[1];
+ unsigned char thisChar;
+
+ thisChar = *(const unsigned char*)src++;
+ while ( thisChar != '\0' )
+ {
+ unsigned char nextChar;
+
+ // use nextChar so we don't overwrite what we are about to read
+ nextChar = *(const unsigned char*)src++;
+ *curdst++ = thisChar;
+ thisChar = nextChar;
+
+ if ( ++length >= 255 )
+ break;
+ }
+ }
+ else if ( src != NULL )
+ {
+ unsigned char* curdst = &dst[1];
+ short overflow = 255; // count down so test it loop is faster
+ register char temp;
+
+ // Can't do the K&R C thing of "while (*s++ = *t++)" because it will copy trailing zero
+ // which might overrun pascal buffer. Instead we use a temp variable.
+ while ( (temp = *src++) != 0 )
+ {
+ *(char*)curdst++ = temp;
+
+ if ( --overflow <= 0 )
+ break;
+ }
+ length = 255 - overflow;
+ }
+ dst[0] = length;
+}
+
+
+void CStrFromPStr(ConstStr255Param pString, char **cString)
+{
+ // Allocates a cString and copies a Pascal string into it.
+ unsigned int len;
+
+ len = pString[0];
+ *cString = malloc(len+1);
+
+ if (*cString != NULL) {
+ strncpy(*cString, (char *)&pString[1], len);
+ (*cString)[len] = NULL;
+ }
+}
+
+
+void dprintf(const char *format, ...)
+{
+#if DEBUG
+ va_list ap;
+ Str255 buffer;
+
+ va_start(ap, format);
+ buffer[0] = PR_vsnprintf((char *)buffer + 1, sizeof(buffer) - 1, format, ap);
+ va_end(ap);
+
+ DebugStr(buffer);
+#endif /* DEBUG */
+}
+
+#else
+
+void debugstr(const char *debuggerMsg)
+{
+ Str255 pStr;
+
+ PStrFromCStr(debuggerMsg, pStr);
+ DebugStr(pStr);
+}
+
+
+char *strdup(const char *source)
+{
+ char *newAllocation;
+ size_t stringLength;
+
+ PR_ASSERT(source);
+
+ stringLength = strlen(source) + 1;
+
+ newAllocation = (char *)PR_MALLOC(stringLength);
+ if (newAllocation == NULL)
+ return NULL;
+ BlockMoveData(source, newAllocation, stringLength);
+ return newAllocation;
+}
+
+// PStrFromCStr converts the source C string to a destination
+// pascal string as it copies. The dest string will
+// be truncated to fit into an Str255 if necessary.
+// If the C String pointer is NULL, the pascal string's length is set to zero
+//
+void PStrFromCStr(const char* src, Str255 dst)
+{
+ short length = 0;
+
+ // handle case of overlapping strings
+ if ( (void*)src == (void*)dst )
+ {
+ unsigned char* curdst = &dst[1];
+ unsigned char thisChar;
+
+ thisChar = *(const unsigned char*)src++;
+ while ( thisChar != '\0' )
+ {
+ unsigned char nextChar;
+
+ // use nextChar so we don't overwrite what we are about to read
+ nextChar = *(const unsigned char*)src++;
+ *curdst++ = thisChar;
+ thisChar = nextChar;
+
+ if ( ++length >= 255 )
+ break;
+ }
+ }
+ else if ( src != NULL )
+ {
+ unsigned char* curdst = &dst[1];
+ short overflow = 255; // count down so test it loop is faster
+ register char temp;
+
+ // Can't do the K&R C thing of "while (*s++ = *t++)" because it will copy trailing zero
+ // which might overrun pascal buffer. Instead we use a temp variable.
+ while ( (temp = *src++) != 0 )
+ {
+ *(char*)curdst++ = temp;
+
+ if ( --overflow <= 0 )
+ break;
+ }
+ length = 255 - overflow;
+ }
+ dst[0] = length;
+}
+
+
+void CStrFromPStr(ConstStr255Param pString, char **cString)
+{
+ // Allocates a cString and copies a Pascal string into it.
+ unsigned int len;
+
+ len = pString[0];
+ *cString = PR_MALLOC(len+1);
+
+ if (*cString != NULL) {
+ strncpy(*cString, (char *)&pString[1], len);
+ (*cString)[len] = NULL;
+ }
+}
+
+
+size_t strlen(const char *source)
+{
+ size_t currentLength = 0;
+
+ if (source == NULL)
+ return currentLength;
+
+ while (*source++ != '\0')
+ currentLength++;
+
+ return currentLength;
+}
+
+int strcmpcore(const char *str1, const char *str2, int caseSensitive)
+{
+ char currentChar1, currentChar2;
+
+ while (1) {
+
+ currentChar1 = *str1;
+ currentChar2 = *str2;
+
+ if (!caseSensitive) {
+
+ if ((currentChar1 >= 'a') && (currentChar1 <= 'z'))
+ currentChar1 += ('A' - 'a');
+
+ if ((currentChar2 >= 'a') && (currentChar2 <= 'z'))
+ currentChar2 += ('A' - 'a');
+
+ }
+
+ if (currentChar1 == '\0')
+ break;
+
+ if (currentChar1 != currentChar2)
+ return currentChar1 - currentChar2;
+
+ str1++;
+ str2++;
+
+ }
+
+ return currentChar1 - currentChar2;
+}
+
+int strcmp(const char *str1, const char *str2)
+{
+ return strcmpcore(str1, str2, true);
+}
+
+int strcasecmp(const char *str1, const char *str2)
+{
+ return strcmpcore(str1, str2, false);
+}
+
+
+void *memcpy(void *to, const void *from, size_t size)
+{
+ if (size != 0) {
+#if DEBUG
+ if ((UInt32)to < 0x1000)
+ DebugStr("\pmemcpy has illegal to argument");
+ if ((UInt32)from < 0x1000)
+ DebugStr("\pmemcpy has illegal from argument");
+#endif
+ BlockMoveData(from, to, size);
+ }
+ return to;
+}
+
+void dprintf(const char *format, ...)
+{
+ va_list ap;
+ char *buffer;
+
+ va_start(ap, format);
+ buffer = (char *)PR_vsmprintf(format, ap);
+ va_end(ap);
+
+ debugstr(buffer);
+ PR_DELETE(buffer);
+}
+
+void
+exit(int result)
+{
+#pragma unused (result)
+
+ ExitToShell();
+}
+
+void abort(void)
+{
+ exit(-1);
+}
+
+#endif
+
+//##############################################################################
+//##############################################################################
+#pragma mark -
+#pragma mark FLUSHING THE GARBAGE COLLECTOR
+
+#if !defined(MAC_NSPR_STANDALONE)
+
+unsigned char GarbageCollectorCacheFlusher(PRUint32)
+{
+
+ PRIntn is;
+
+ UInt32 oldPriority;
+
+ // If java wasn't completely initialized, then bail
+ // harmlessly.
+
+ if (PR_GetGCInfo()->lock == NULL)
+ return false;
+
+#if DEBUG
+ if (_MD_GET_INTSOFF() == 1)
+ DebugStr("\pGarbageCollectorCacheFlusher at interrupt time!");
+#endif
+
+ // The synchronization here is very tricky. We really
+ // don't want any other threads to run while we are
+ // cleaning up the gc heap... they could call malloc,
+ // and then we would be in trouble in a big way. So,
+ // we jack up our priority and that of the finalizer
+ // so that we won't yield to other threads.
+ // dkc 5/17/96
+
+ oldPriority = PR_GetThreadPriority(PR_GetCurrentThread());
+ _PR_INTSOFF(is);
+ _PR_SetThreadPriority(PR_GetCurrentThread(), (PRThreadPriority)30);
+ _PR_INTSON(is);
+
+ // Garbage collect twice. This will finalize any
+ // dangling AWT resources (images, components), and
+ // then free up their GC space, too.
+ // dkc 2/15/96
+ // interrupts must be on during PR_GC
+
+ PR_GC();
+
+ // By setting the finalizer priority to 31, then we
+ // ensure it will run before us. When it finishes
+ // its list of finalizations, it returns to us
+ // for the second garbage collection.
+
+ PR_Yield();
+
+ PR_GC();
+
+ // Restore our old priorities.
+
+ _PR_INTSOFF(is);
+ _PR_SetThreadPriority(PR_GetCurrentThread(), (PRThreadPriority)oldPriority);
+ _PR_INTSON(is);
+
+ return false;
+}
+
+#endif
+
+//##############################################################################
+//##############################################################################
+#pragma mark -
+#pragma mark MISCELLANEOUS-HACKS
+
+
+//
+// ***** HACK FIX THESE ****
+//
+extern long _MD_GetOSName(char *buf, long count)
+{
+ long len;
+
+ len = PR_snprintf(buf, count, "Mac OS");
+
+ return 0;
+}
+
+extern long _MD_GetOSVersion(char *buf, long count)
+{
+ long len;
+
+ len = PR_snprintf(buf, count, "7.5");
+
+ return 0;
+}
+
+extern long _MD_GetArchitecture(char *buf, long count)
+{
+ long len;
+
+#if defined(TARGET_CPU_PPC) && TARGET_CPU_PPC
+ len = PR_snprintf(buf, count, "PowerPC");
+#else
+ len = PR_snprintf(buf, count, "Motorola68k");
+#endif
+
+ return 0;
+}
diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mdmac.h b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mdmac.h
new file mode 100644
index 00000000..ad8c3c4d
--- /dev/null
+++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mdmac.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+
+#ifndef mdmac_h__
+#define mdmac_h__
+
+
+PR_BEGIN_EXTERN_C
+
+void PStrFromCStr(const char* src, Str255 dst);
+void CStrFromPStr(ConstStr255Param pString, char **cString);
+
+PR_END_EXTERN_C
+
+
+#endif /* mdmac_h__ */
diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/prcpucfg.h b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/prcpucfg.h
new file mode 100644
index 00000000..17d665c6
--- /dev/null
+++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/prcpucfg.h
@@ -0,0 +1,136 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nspr_cpucfg___
+#define nspr_cpucfg___
+
+#ifndef XP_MAC
+#define XP_MAC
+#endif
+
+#undef IS_LITTLE_ENDIAN
+#define IS_BIG_ENDIAN 1
+
+#define HAVE_LONG_LONG
+
+#define PR_AF_INET6 30 /* same as AF_INET6 */
+
+#define PR_BYTES_PER_BYTE 1L
+#define PR_BYTES_PER_SHORT 2L
+#define PR_BYTES_PER_INT 4L
+#define PR_BYTES_PER_INT64 8L
+#define PR_BYTES_PER_LONG 4L
+#define PR_BYTES_PER_FLOAT 4L
+#define PR_BYTES_PER_DOUBLE 8L
+#define PR_BYTES_PER_WORD 4L
+#define PR_BYTES_PER_DWORD 8L
+
+#define PR_BITS_PER_BYTE 8L
+#define PR_BITS_PER_SHORT 16L
+#define PR_BITS_PER_INT 32L
+#define PR_BITS_PER_INT64 64L
+#define PR_BITS_PER_LONG 32L
+#define PR_BITS_PER_FLOAT 32L
+#define PR_BITS_PER_DOUBLE 64L
+#define PR_BITS_PER_WORD 32L
+
+#define PR_BITS_PER_BYTE_LOG2 3L
+#define PR_BITS_PER_SHORT_LOG2 4L
+#define PR_BITS_PER_INT_LOG2 5L
+#define PR_BITS_PER_INT64_LOG2 6L
+#define PR_BITS_PER_LONG_LOG2 5L
+#define PR_BITS_PER_FLOAT_LOG2 5L
+#define PR_BITS_PER_DOUBLE_LOG2 6L
+#define PR_BITS_PER_WORD_LOG2 5L
+
+#define PR_ALIGN_OF_SHORT 2L
+#define PR_ALIGN_OF_INT 4L
+#define PR_ALIGN_OF_LONG 4L
+#define PR_ALIGN_OF_INT64 2L
+#define PR_ALIGN_OF_FLOAT 4L
+#define PR_ALIGN_OF_DOUBLE 4L
+#define PR_ALIGN_OF_POINTER 4L
+#define PR_ALIGN_OF_WORD 4L
+
+#define PR_BYTES_PER_WORD_LOG2 2L
+#define PR_BYTES_PER_DWORD_LOG2 3L
+#define PR_WORDS_PER_DWORD_LOG2 1L
+
+#ifndef NO_NSPR_10_SUPPORT
+#define BYTES_PER_BYTE PR_BYTES_PER_BYTE
+#define BYTES_PER_SHORT PR_BYTES_PER_SHORT
+#define BYTES_PER_INT PR_BYTES_PER_INT
+#define BYTES_PER_INT64 PR_BYTES_PER_INT64
+#define BYTES_PER_LONG PR_BYTES_PER_LONG
+#define BYTES_PER_FLOAT PR_BYTES_PER_FLOAT
+#define BYTES_PER_DOUBLE PR_BYTES_PER_DOUBLE
+#define BYTES_PER_WORD PR_BYTES_PER_WORD
+#define BYTES_PER_DWORD PR_BYTES_PER_DWORD
+
+#define BITS_PER_BYTE PR_BITS_PER_BYTE
+#define BITS_PER_SHORT PR_BITS_PER_SHORT
+#define BITS_PER_INT PR_BITS_PER_INT
+#define BITS_PER_INT64 PR_BITS_PER_INT64
+#define BITS_PER_LONG PR_BITS_PER_LONG
+#define BITS_PER_FLOAT PR_BITS_PER_FLOAT
+#define BITS_PER_DOUBLE PR_BITS_PER_DOUBLE
+#define BITS_PER_WORD PR_BITS_PER_WORD
+
+#define BITS_PER_BYTE_LOG2 PR_BITS_PER_BYTE_LOG2
+#define BITS_PER_SHORT_LOG2 PR_BITS_PER_SHORT_LOG2
+#define BITS_PER_INT_LOG2 PR_BITS_PER_INT_LOG2
+#define BITS_PER_INT64_LOG2 PR_BITS_PER_INT64_LOG2
+#define BITS_PER_LONG_LOG2 PR_BITS_PER_LONG_LOG2
+#define BITS_PER_FLOAT_LOG2 PR_BITS_PER_FLOAT_LOG2
+#define BITS_PER_DOUBLE_LOG2 PR_BITS_PER_DOUBLE_LOG2
+#define BITS_PER_WORD_LOG2 PR_BITS_PER_WORD_LOG2
+
+#define ALIGN_OF_SHORT PR_ALIGN_OF_SHORT
+#define ALIGN_OF_INT PR_ALIGN_OF_INT
+#define ALIGN_OF_LONG PR_ALIGN_OF_LONG
+#define ALIGN_OF_INT64 PR_ALIGN_OF_INT64
+#define ALIGN_OF_FLOAT PR_ALIGN_OF_FLOAT
+#define ALIGN_OF_DOUBLE PR_ALIGN_OF_DOUBLE
+#define ALIGN_OF_POINTER PR_ALIGN_OF_POINTER
+#define ALIGN_OF_WORD PR_ALIGN_OF_WORD
+
+#define BYTES_PER_WORD_LOG2 PR_BYTES_PER_WORD_LOG2
+#define BYTES_PER_DWORD_LOG2 PR_BYTES_PER_DWORD_LOG2
+#define WORDS_PER_DWORD_LOG2 PR_WORDS_PER_DWORD_LOG2
+#endif /* NO_NSPR_10_SUPPORT */
+
+#endif /* nspr_cpucfg___ */