diff options
Diffstat (limited to 'src/libs/xpcom18a4/nsprpub/pr/src/md/mac')
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(¤tTime); + + /* + * 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___ */ |